Acked-by: Ankur Sharma <ankursha...@vmware.com> ________________________________________ From: dev <dev-boun...@openvswitch.org> on behalf of Alin Serdean <aserd...@cloudbasesolutions.com> Sent: Friday, October 24, 2014 3:15 PM To: Nithin Raju; dev@openvswitch.org Subject: Re: [ovs-dev] [PATCH 5/7] datapath-windows: core refactoring in Vport.c
Acked-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> Tested-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> -----Mesaj original----- De la: dev [mailto:dev-boun...@openvswitch.org] În numele Nithin Raju Trimis: Friday, October 24, 2014 3:33 AM Către: dev@openvswitch.org Subiect: [ovs-dev] [PATCH 5/7] datapath-windows: core refactoring in Vport.c We do a bunch of changes that did not make sense to split up into smaller patches: 1. Add descriptive comments to the important functions to clarify purpose. 2. s/OvsInitVportCommon/InitHvVportCommon - this function is common code for every port that shows up on the Hyper-V switch. 3. Introduce a InitOvsVportCommon() that is common code for evrey port that gets added from userspace. This is especially useful for ports that are not present on the Hyper-V switch. ie. tunnel ports and bridge-internal ports. 4. Fix OvsClearAllSwitchVports() to remove ports from both the lists: the ones added from Hyper-V as well as the ones added from OVS userspace. 5. Update OvsInitVxlanTunnel() to not call into InitHvVportCommon (formerly OvsInitVportCommon()) since it is not a port on the Hyper-v switch. In a later patch in the series, we'll call InitOvsVportCommon() for a VXLAN port. 6. 'numNonHvVports' increments and decrements ONLY for ports that are added from OVS userspace but not present on the Hyper-V switch. Signed-off-by: Nithin Raju <nit...@vmware.com> --- datapath-windows/ovsext/Vport.c | 236 ++++++++++++++++++++++++++++++++------ datapath-windows/ovsext/Vport.h | 4 +- datapath-windows/ovsext/Vxlan.c | 21 +--- 3 files changed, 206 insertions(+), 55 deletions(-) diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c index 6fb0653..11ec07d 100644 --- a/datapath-windows/ovsext/Vport.c +++ b/datapath-windows/ovsext/Vport.c @@ -54,8 +54,8 @@ static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport, PNDIS_SWITCH_PORT_PARAMETERS portParam); static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext, POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam); -static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY - virtVport, UINT32 nicIndex); +static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVPort, + POVS_VPORT_ENTRY virtExtVport, UINT32 nicIndex); static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec); static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet, @@ -94,7 +94,7 @@ HvCreatePort(POVS_SWITCH_CONTEXT switchContext, } OvsInitVportWithPortParam(vport, portParam); - OvsInitVportCommon(switchContext, vport); + InitHvVportCommon(switchContext, vport); create_port_done: NdisReleaseRWLock(switchContext->dispatchLock, &lockState); @@ -201,15 +201,16 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext, if (nicParam->NicType == NdisSwitchNicTypeExternal && nicParam->NicIndex != 0) { - POVS_VPORT_ENTRY virtVport = + POVS_VPORT_ENTRY virtExtVport = (POVS_VPORT_ENTRY)switchContext->virtualExternalVport; + vport = (POVS_VPORT_ENTRY)OvsAllocateVport(); if (vport == NULL) { status = NDIS_STATUS_RESOURCES; goto add_nic_done; } - OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex); - status = OvsInitVportCommon(switchContext, vport); + OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex); + status = InitHvVportCommon(switchContext, vport); if (status != NDIS_STATUS_SUCCESS) { OvsFreeMemory(vport); goto add_nic_done; @@ -600,6 +601,7 @@ OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport, vport->portId = portParam->PortId; vport->nicState = NdisSwitchNicStateUnknown; vport->isExternal = FALSE; + vport->isBridgeInternal = FALSE; switch (vport->portType) { case NdisSwitchPortTypeExternal: @@ -616,7 +618,8 @@ OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport, } RtlCopyMemory(&vport->hvPortName, &portParam->PortName, sizeof (NDIS_SWITCH_PORT_NAME)); - + /* For external and internal ports, 'portFriendlyName' is overwritten + * later. */ RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName, sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME)); @@ -682,26 +685,35 @@ OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext, } } +/* + * +----------------------------------------------------------------------- +--- + * Copies the relevant NDIS port properties from a virtual (pseudo) +external + * NIC to a physical (real) external NIC. + * +----------------------------------------------------------------------- +--- + */ static VOID -OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, - POVS_VPORT_ENTRY virtVport, - UINT32 nicIndex) +OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport, + POVS_VPORT_ENTRY virtExtVport, + UINT32 physNicIndex) { - vport->portType = virtVport->portType; - vport->portState = virtVport->portState; - vport->portId = virtVport->portId; - vport->nicState = NdisSwitchNicStateUnknown; - vport->ovsType = OVS_VPORT_TYPE_NETDEV; - vport->isExternal = TRUE; - vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex; - - RtlCopyMemory(&vport->hvPortName, &virtVport->hvPortName, + physExtVport->portType = virtExtVport->portType; + physExtVport->portState = virtExtVport->portState; + physExtVport->portId = virtExtVport->portId; + physExtVport->nicState = NdisSwitchNicStateUnknown; + physExtVport->ovsType = OVS_VPORT_TYPE_NETDEV; + physExtVport->isExternal = TRUE; + physExtVport->isBridgeInternal = FALSE; + physExtVport->nicIndex = (NDIS_SWITCH_NIC_INDEX)physNicIndex; + + RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName, sizeof (NDIS_SWITCH_PORT_NAME)); - RtlCopyMemory(&vport->portFriendlyName, &virtVport->portFriendlyName, + /* 'portFriendlyName' is overwritten later. */ + RtlCopyMemory(&physExtVport->portFriendlyName, + &virtExtVport->portFriendlyName, sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME)); - vport->ovsState = OVS_STATE_PORT_CREATED; + physExtVport->ovsState = OVS_STATE_PORT_CREATED; } /* @@ -753,36 +765,93 @@ OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport) return STATUS_SUCCESS; } +/* + * +----------------------------------------------------------------------- +--- + * For external vports 'portFriendlyName' provided by Hyper-V is +over-written + * by synthetic names. + * +----------------------------------------------------------------------- +--- + */ +static VOID +AssignNicNameSpecial(POVS_VPORT_ENTRY vport) { + size_t len; + + if (vport->portType == NdisSwitchPortTypeExternal) { + if (vport->nicIndex == 0) { + ASSERT(vport->nicIndex == 0); + RtlStringCbPrintfW(vport->portFriendlyName.String, + IF_MAX_STRING_SIZE, + L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W); + } else { + RtlStringCbPrintfW(vport->portFriendlyName.String, + IF_MAX_STRING_SIZE, + L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W, + (UINT32)vport->nicIndex); + } + } else { + RtlStringCbPrintfW(vport->portFriendlyName.String, + IF_MAX_STRING_SIZE, + L"%s", OVS_DPPORT_INTERNAL_NAME_W); + } + + RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE, + &len); + vport->portFriendlyName.Length = (USHORT)len; } + + +/* + * +----------------------------------------------------------------------- +--- + * Functionality common to any port on the Hyper-V switch. This +function is not + * to be called for a port that is not on the Hyper-V switch. + * + * Inserts the port into 'portIdHashArray' and caches the pointer in +the + * 'switchContext' if needed. + * + * For external NIC, assigns the name for the NIC. + * +----------------------------------------------------------------------- +--- + */ NDIS_STATUS -OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext, - POVS_VPORT_ENTRY vport) +InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext, + POVS_VPORT_ENTRY vport) { UINT32 hash; ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID); switch (vport->portType) { case NdisSwitchPortTypeExternal: + /* + * Overwrite the 'portFriendlyName' of this external vport. The reason + * for having this in common code is to be able to call it from the NDIS + * Port callback as well as the NDIS NIC callback. + */ + AssignNicNameSpecial(vport); + if (vport->nicIndex == 0) { switchContext->virtualExternalPortId = vport->portId; switchContext->virtualExternalVport = vport; - RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, - "external.virtualAdapter"); } else { switchContext->numPhysicalNics++; - RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, - "external.%lu", (UINT32)vport->nicIndex); } break; case NdisSwitchPortTypeInternal: + ASSERT(vport->isBridgeInternal == FALSE); + + /* Overwrite the 'portFriendlyName' of the internal vport. */ + AssignNicNameSpecial(vport); switchContext->internalPortId = vport->portId; switchContext->internalVport = vport; break; case NdisSwitchPortTypeSynthetic: - break; case NdisSwitchPortTypeEmulated: break; } + /* + * It is important to not insert vport corresponding to virtual external + * port into the 'portIdHashArray' since the port should not be exposed to + * OVS userspace. + */ if (vport->portType == NdisSwitchPortTypeExternal && vport->nicIndex == 0) { return NDIS_STATUS_SUCCESS; @@ -800,10 +869,61 @@ OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext, return NDIS_STATUS_SUCCESS; } +/* + * +----------------------------------------------------------------------- +--- + * Functionality common to any port added from OVS userspace. + * + * Inserts the port into 'portIdHashArray', 'ovsPortNameHashArray' and +caches + * the pointer in the 'switchContext' if needed. + * +----------------------------------------------------------------------- +--- + */ +NDIS_STATUS +InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, + POVS_VPORT_ENTRY vport) { + UINT32 hash; + + switch(vport->ovsType) { + case OVS_VPORT_TYPE_VXLAN: + ASSERT(switchContext->vxlanVport == NULL); + switchContext->vxlanVport = vport; + switchContext->numNonHvVports++; + break; + default: + break; + } + + /* + * Insert the port into the hash array of ports: by port number and ovs + * and ovs (datapath) port name. + * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the + * portNo is stored in 2 bytes only (max port number = MAXUINT16). + */ + hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS); + InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK], + &vport->portNoLink); + + hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1, + OVS_HASH_BASIS); + InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK], + &vport->ovsNameLink); + + return STATUS_SUCCESS; +} + + +/* + * +----------------------------------------------------------------------- +--- + * Provides functionality that is partly complementatry to + * InitOvsVportCommon()/InitHvVportCommon(). + * +----------------------------------------------------------------------- +--- + */ VOID OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, POVS_VPORT_ENTRY vport) { + BOOLEAN hvSwitchPort = FALSE; + if (vport->isExternal) { if (vport->nicIndex == 0) { ASSERT(switchContext->numPhysicalNics == 0); @@ -814,22 +934,28 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, } else { ASSERT(switchContext->numPhysicalNics); switchContext->numPhysicalNics--; + hvSwitchPort = TRUE; } } switch (vport->ovsType) { case OVS_VPORT_TYPE_INTERNAL: - switchContext->internalPortId = 0; - switchContext->internalVport = NULL; - OvsInternalAdapterDown(); + if (!vport->isBridgeInternal) { + switchContext->internalPortId = 0; + switchContext->internalVport = NULL; + OvsInternalAdapterDown(); + hvSwitchPort = TRUE; + } break; case OVS_VPORT_TYPE_VXLAN: OvsCleanupVxlanTunnel(vport); + switchContext->vxlanVport = NULL; break; case OVS_VPORT_TYPE_GRE: case OVS_VPORT_TYPE_GRE64: break; case OVS_VPORT_TYPE_NETDEV: + hvSwitchPort = TRUE; default: break; } @@ -837,7 +963,11 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, RemoveEntryList(&vport->ovsNameLink); RemoveEntryList(&vport->portIdLink); RemoveEntryList(&vport->portNoLink); - switchContext->numHvVports--; + if (hvSwitchPort) { + switchContext->numHvVports--; + } else { + switchContext->numNonHvVports--; + } OvsFreeMemory(vport); } @@ -871,7 +1001,7 @@ OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext) goto cleanup; } OvsInitVportWithPortParam(vport, portParam); - status = OvsInitVportCommon(switchContext, vport); + status = InitHvVportCommon(switchContext, vport); if (status != NDIS_STATUS_SUCCESS) { OvsFreeMemory(vport); goto cleanup; @@ -923,12 +1053,13 @@ OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext) if (nicParam->NicType == NdisSwitchNicTypeExternal && nicParam->NicIndex != 0) { - POVS_VPORT_ENTRY virtVport = + POVS_VPORT_ENTRY virtExtVport = (POVS_VPORT_ENTRY)switchContext->virtualExternalVport; vport = OvsAllocateVport(); if (vport) { - OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex); - status = OvsInitVportCommon(switchContext, vport); + OvsInitPhysNicVport(vport, virtExtVport, + nicParam->NicIndex); + status = InitHvVportCommon(switchContext, vport); if (status != NDIS_STATUS_SUCCESS) { OvsFreeMemory(vport); vport = NULL; @@ -957,6 +1088,14 @@ cleanup: return status; } +/* + * +----------------------------------------------------------------------- +--- + * Deletes ports added from the Hyper-V switch as well as OVS +usersapce. The + * function deletes ports in 'portIdHashArray'. This will delete most +of the + * ports that are in the 'portNoHashArray' as well. Any remaining ports + * are deleted by walking the the 'portNoHashArray'. + * +----------------------------------------------------------------------- +--- + */ VOID OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext) { @@ -970,11 +1109,32 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext) OvsRemoveAndDeleteVport(switchContext, vport); } } - + /* + * Remove 'virtualExternalVport' as well. This port is not part of the + * 'portIdHashArray'. + */ if (switchContext->virtualExternalVport) { OvsRemoveAndDeleteVport(switchContext, - (POVS_VPORT_ENTRY)switchContext->virtualExternalVport); + (POVS_VPORT_ENTRY)switchContext->virtualExternalVport); } + + for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) { + PLIST_ENTRY head, link, next; + + head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]); + LIST_FORALL_SAFE(head, link, next) { + POVS_VPORT_ENTRY vport; + vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink); + ASSERT(OvsIsTunnelVportType(vport->portType) || + (vport->ovsType == OVS_VPORT_TYPE_INTERNAL && + vport->isBridgeInternal)); + OvsRemoveAndDeleteVport(switchContext, vport); + } + } + + ASSERT(switchContext->virtualExternalVport == NULL); + ASSERT(switchContext->internalVport == NULL); + ASSERT(switchContext->vxlanVport == NULL); } diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h index 4757d80..bf9028e 100644 --- a/datapath-windows/ovsext/Vport.h +++ b/datapath-windows/ovsext/Vport.h @@ -203,7 +203,9 @@ OvsGetExternalMtu() VOID OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, POVS_VPORT_ENTRY vport); -NDIS_STATUS OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext, +NDIS_STATUS InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext, + POVS_VPORT_ENTRY vport); NDIS_STATUS +InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, POVS_VPORT_ENTRY vport); NTSTATUS OvsInitTunnelVport(POVS_VPORT_ENTRY vport, OVS_VPORT_TYPE ovsType, UINT16 dstport); diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c index f5f3c08..0a68c9c 100644 --- a/datapath-windows/ovsext/Vxlan.c +++ b/datapath-windows/ovsext/Vxlan.c @@ -52,13 +52,12 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext; /* * udpDestPort: the vxlan is set as payload to a udp frame. If the destination * port of an udp frame is udpDestPort, we understand it to be vxlan. -*/ + */ NL_ERROR OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, UINT16 udpDestPort) { POVS_VXLAN_VPORT vxlanPort; - NTSTATUS status; vxlanPort = OvsAllocateMemory(sizeof (*vxlanPort)); if (vxlanPort == NULL) { @@ -68,23 +67,13 @@ OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, RtlZeroMemory(vxlanPort, sizeof(*vxlanPort)); vxlanPort->dstPort = udpDestPort; /* - * since we are installing the WFP filter before the port is created - * We need to check if it is the same number - * XXX should be removed later - */ + * since we are installing the WFP filter before the port is created + * We need to check if it is the same number + * XXX should be removed later + */ ASSERT(vxlanPort->dstPort == VXLAN_UDP_PORT); vport->priv = (PVOID)vxlanPort; - status = OvsInitVportCommon(gOvsSwitchContext, vport); - ASSERT(status == NDIS_STATUS_SUCCESS); - - vport->ovsState = OVS_STATE_CONNECTED; - vport->nicState = NdisSwitchNicStateConnected; - /* - * allow the vport to be deleted, because there is no hyper-v switch part - */ - vport->hvDeleted = TRUE; - return NL_ERROR_SUCCESS; } -- 1.7.4.1 _______________________________________________ dev mailing list dev@openvswitch.org https://urldefense.proofpoint.com/v1/url?u=http://openvswitch.org/mailman/listinfo/dev&k=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0A&r=f6EhnZ0ORGZNt5QbYmRaOxfWfx%2Bqd3KEiPf3%2FYaollU%3D%0A&m=uOjJHmrHQBNvhsrTtg30qp0KhJ0WxYgkshPdEAJvwZQ%3D%0A&s=3e5ccdec357d3b2fa336a1be40421e6102ddcfd658862f61cdd32964a2075e4e _______________________________________________ dev mailing list dev@openvswitch.org https://urldefense.proofpoint.com/v1/url?u=http://openvswitch.org/mailman/listinfo/dev&k=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0A&r=f6EhnZ0ORGZNt5QbYmRaOxfWfx%2Bqd3KEiPf3%2FYaollU%3D%0A&m=uOjJHmrHQBNvhsrTtg30qp0KhJ0WxYgkshPdEAJvwZQ%3D%0A&s=3e5ccdec357d3b2fa336a1be40421e6102ddcfd658862f61cdd32964a2075e4e _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev