>Add functionality for dp ports, hv nics, hv ports This is a little ahead of its time. Adding functional changes when we canĀ¹t even test it with the upstream code is not the way to go. This should be resurrected once the Netlink-integration is complete and we have a OVS working on HyperV.
> >In order to be able to make the mapping between datapath ports and >hyper-v ports. >Hyper-v switch ports and hyper-v nics belong to the switch, while the dp >ports are implemented as fixed >sized arrays and belong in the datapath. > >Functions to hande Hv Nic and Hv Port creations, deletes, etc. are >provided, but the old functionality of the switch (with hyper-v ports >merged into vports) is not removed. The repacement is to be done in a >future commit. > >Signed-off-by: Samuel Ghinet <sghi...@cloudbasesolutions.com> >--- > datapah-windows/ovsext/Core/FixedSizedArray.c | 4 +- > datapath-windows/ovsextCore/FixedSizedArray.h | 4 +- > datapath-widows/ovsext/Hyper-V/HvNic.c | 515 ++++++++++++++++++++ > datapath-windows/ovsext/Hyper-V/HvNic.h | 66 +++ > datapath-windowsovsext/Hyper-V/HvPort.c | 410 ++++++++++++++++ > datapath-windows/ovsext/Hyper-V/HvPort.h | 56 +++ > datapath-windows/ovsext/Hyper-V/Switch.h | 22 +- > datapath-windows/ovsext/OpenFlow/DpPort.c | 632 >+++++++++++++++++++++++++ > datapath-windows/ovsext/OpenFlow/DpPort.h | 161 +++++++ > datapath-windows/ovsext/ovsext.vcxproj | 6 + > datapath-windows/ovsext/ovsext.vcxproj.filters | 18 + > 11 files changed, 1888 insertions(+), 6 deletions(-) > creae mode 100644 datapath-windows/ovsext/Hyper-V/HvNic.c > create mode 100644 datapath-windows/ovsext/Hyper-V/HvNic.h > create mode 100644 datapath-windows/ovsext/Hyper-V/HvPort.c > create mode 100644 datapath-windows/ovsext/Hyper-V/HvPort.h > create mode 100644 datapath-windows/ovsext/OpenFlow/DpPort.c > create mode 100644 datapath-windows/ovsext/OpenFlowDpPort.h > >diff --git a/datapath-windows/ovsext/Core/FixedSizedArray.c >b/atapath-windows/ovsext/Core/FixedSizedArray.c >index 3f63753..8a35a4f 100644>--- >a/datapath-windows/ovsext/Core/FixedSizedArray.c >+++ b/datapath-windows/ovsext/Core/FixedSizedArray.c >@@ -165,11 +165,11 @@ OS_FXDARRAY_ITEM* FxdArray_Find_Ref(const >OVS_FIXED_SIZED_ARRAY* pArray, FxdArr > OVS_FXDARRAY_ITEM* pOutItem = NUL; > LOCK_STATE_EX lockState; > >- FXARRAY_LOCK_READ(pArray, &lockState); >+ FXDARRAY_LOCK_READ(pArray, &lockState); > > pOutItem = FxdArray_Find_Unsae(pArray, condition, pCondData); > >- FXARRAY_UNLOCK(pArray, &lockState); >+ FXDARRY_UNLOCK(pArray, &lockState); > > return pOutItem; > } >diff --git a/datapath-windows/ovsext/Core/FixedSizedArray.h >b/datapath-windows/ovsext/Core/FixedSizedArray.h >index 08dddb3..7ccf59e 100644 >--- a/datapath-windows/ovsext/Core/FixedSizedArray.h >+++ b/datapath-windows/ovsext/Core/FixedSizedArray.h >@@ -91,10 +91,10 @@ typedef struct _OVS_FIXED_SIZED_ARRAY > > >/************************************************************************* >*********/ > >-//unsafe = you must lock with FXARRAY lock >+//unsafe = you must lock with FXDARRAY lock > BOOLEAN FxdArray_FindNextFree_Unsafe(_In_ const VS_FIXED_SIZED_ARRAY* >pPorts, _Inout_ UINT16* pFirst); > >-//unsafe = you must lock with FXARRAY lock >+//unsafe = you must lock with FXDARRAY lock > OVS_ERROR FxdArray_AddByNumber_Unsafe(_Inout_ OVS_FIXED_SIZED_ARRAY* >pArray, _In_ const OVS_FXDARRAY_ITEM* pItem, UINT16 number); > > //unsafe = you must lock with FXARRAY lock >diff --git a/datapath-windows/ovsext/Hyper-V/HvNic.c >b/datapath-windows/ovsext/Hyper-V/HvNic.c >new file mode 100644 >index 0000000..2c8ed70 >--- /dev/null >+++ b/datapath-windows/ovsext/Hyper-V/HvNic.c >@@ -0,0 +1,515 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#include "precomp.h" >+#include "HvNic.h" >+#include "Switch.h" >+ >+#include "Core\List.h" >+#include "OpenFlow\DpPort.h" >+#include "Oid.h" >+ >+#define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100 >+ >+NDIS_STATUS HVNic_Delete_Unsafe(_In_ const OVS_SWITCH_CONTEXT* >pSwithContext, _In_ NDIS_SWITCH_PORT_ID portId, _In_ >NDIS_SWITCH_NIC_INDEX nicIndex) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ >+ OVS_HVNIC_ENTRY* pNicEntry = >HVNic_FindByPortIdAndNicIndex_Unsafe(pSwitchContext, portId, nicIndex); >+ if (pNicEntry == NULL) >+ { >+ OVS_CHECK(FALSE); >+ goto Cleanup; >+ } >+ >+ OVS_REFCOUNT_DESTROY(pNicEntry); >+ >+Cleanup: >+ return status; >+} >+ >+VOID NicEntry_DestroyNow_Unsafe(OVS_HVNIC_ENTRY* pNicEntry) >+{ >+ if (pNicEntry) >+ { >+ RemoveEntryList(&pNicEntry->listEntry); >+ OVS_FREE(pNicEntry); >+ } >+} >+ >+OVS_HVNIC_ENTRY* HVNic_FindByPortIdAndNicIndex_Unsafe(_In_ const >OVS_SWITCH_CONTEXT* pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId, _In_ >NDIS_SWITCH_NIC_INDEX nicIndex) >+{ >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ >+ OVS_LIST_FOR_EACH(OVS_HVNIC_ENTRY, pNicEntry, >&(pSwitchContext->hvNicList)) >+ { >+ if (pNicEntry->hvNicInfo.portId == portId && >pNicEntry->hvNicInfo.nicIndex == nicIndex) >+ { >+ return pNicEntry; >+ } >+ } >+ >+ return NULL; >+} >+ >+OVS_HVNIC_ENTRY* HVNic_FindByPortId_Unsafe(_In_ const >OVS_SWITCH_CONTEXT* pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId) >+{ >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ >+ OVS_LIST_FOR_EACH(OVS_HVNIC_ENTRY, pNicEntry, >&(pSwitchContext->hvNicList)) >+ { >+ if (pNicEntry->hvNicInfo.portId == portId) >+ { >+ return pNicEntry; >+ } >+ } >+ >+ return NULL; >+} >+ >+NDIS_STATUS HVNic_Add_Unsafe(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pCurNic, OVS_HVNIC_ENTRY** ppNicEntry) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ LIST_ENTRY* pNicList = &pSwitchContext->hvNicList; >+ >+ pNicEntry = HVNic_FindByPortIdAndNicIndex_Unsafe(pSwitchContext, >pCurNic->PortId, pCurNic->NicIndex); >+ if (pNicEntry) >+ { >+ return status; >+ } >+ >+ pNicEntry = KZAlloc(sizeof(OVS_HVNIC_ENTRY)); >+ if (pNicEntry == NULL) >+ { >+ status = NDIS_STATUS_RESOURCES; >+ goto Cleanup; >+ } >+ >+ pNicEntry->refCount.Destroy = NicEntry_DestroyNow_Unsafe; >+ RtlCopyMemory(pNicEntry->hvNicInfo.macAddress, >pCurNic->PermanentMacAddress, ETH_ADDR_LENGTH); >+ >+ pNicEntry->hvNicInfo.portId = pCurNic->PortId; >+ pNicEntry->hvNicInfo.nicIndex = pCurNic->NicIndex; >+ pNicEntry->hvNicInfo.nicType = pCurNic->NicType; >+ pNicEntry->hvNicInfo.connected = (pCurNic->NicState == >NdisSwitchNicStateConnected); >+ pNicEntry->hvNicInfo.mtu = pCurNic->MTU; >+ pNicEntry->hvNicInfo.dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+#ifdef DBG >+ WcharArrayToAscii(pNicEntry->hvNicInfo.vmName, >pCurNic->VmFriendlyName.String, min(OVS_NIC_ENTRY_NAME_SIZE, >pCurNic->VmFriendlyName.Length)); >+ WcharArrayToAscii(pNicEntry->hvNicInfo.adapName, >pCurNic->NicFriendlyName.String, min(OVS_NIC_ENTRY_NAME_SIZE, >pCurNic->NicFriendlyName.Length)); >+#endif >+ >+ LOG_INFO("NIC: port=%d; index=%d; type=%d; connected=%d; mtu=%d; >name=\"%s\"; vm name=\"%s\"\n", >+ pNicEntry->hvNicInfo.portId, pNicEntry->hvNicInfo.nicIndex, >pNicEntry->hvNicInfo.nicType, pNicEntry->hvNicInfo.connected, >+ pNicEntry->hvNicInfo.mtu, pNicEntry->hvNicInfo.adapName, >pNicEntry->hvNicInfo.vmName); >+ >+ InsertHeadList(pNicList, &pNicEntry->listEntry); >+ >+ if (ppNicEntry) >+ { >+ *ppNicEntry = pNicEntry; >+ } >+ >+Cleanup: >+ return status; >+} >+ >+/****************************************/ >+ >+_Use_decl_annotations_ >+NDIS_STATUS HVNic_OnCreate(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pNicParams) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ LOCK_STATE_EX lockState = { 0 }; >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ OVS_CHECK(pNicParams->NicState != NdisSwitchNicStateConnected); >+ status = HVNic_Add_Unsafe(pSwitchContext, pNicParams, &pNicEntry); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ if (pNicParams->NicType == NdisSwitchNicTypeExternal && >+ pNicParams->NicIndex != NDIS_SWITCH_DEFAULT_NIC_INDEX) >+ { >+ OVS_CHECK(!pSwitchContext->pExternalNic); >+ OVS_CHECK(pNicEntry); >+ >+ pSwitchContext->pExternalNic = pNicEntry; >+ } >+ >+ //NOTE: the internal port has nic index = 0 >+ else if (pNicParams->NicType == NdisSwitchNicTypeInternal && >!pSwitchContext->pInternalNic) >+ { >+ OVS_CHECK(!pSwitchContext->pInternalNic); >+ OVS_CHECK(pNicEntry); >+ >+ pSwitchContext->pInternalNic = pNicEntry; >+ } >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ return status; >+} >+ >+_Use_decl_annotations_ >+VOID HVNic_OnConnect(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pNicParams) >+{ >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ NDIS_SWITCH_PORT_ID portId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ NDIS_SWITCH_NIC_INDEX nicIndex = NDIS_SWITCH_DEFAULT_NIC_INDEX; >+ LOCK_STATE_EX lockState = { 0 }; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+ OvsWaitActivate(pSwitchContext, >OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC); >+ >+ if (!pSwitchContext->isActivated) { >+ LOG_WARN("Switch is not activated yet."); >+ return; >+ } >+ >+ HVSWITCH_LOCK_READ(pSwitchContext, &lockState); >+ >+ if (pNicParams->NicType == NdisSwitchNicTypeExternal && >+ pNicParams->NicIndex != NDIS_SWITCH_DEFAULT_NIC_INDEX) >+ { >+ OVS_CHECK(pSwitchContext->pExternalNic); >+ >+ pNicEntry = pSwitchContext->pExternalNic; >+ } >+ >+ //NOTE: the internal port has nic index = 0 >+ else if (pNicParams->NicType == NdisSwitchNicTypeInternal) >+ { >+ pNicEntry = pSwitchContext->pInternalNic; >+ } >+ >+ //if internal, we still check this out >+ else if (pNicParams->NicType != NdisSwitchNicTypeExternal) >+ { >+ OVS_CHECK(pNicParams->NicType != NdisSwitchNicTypeInternal); >+ >+ pNicEntry = HVNic_FindByPortIdAndNicIndex_Unsafe(pSwitchContext, >pNicParams->PortId, pNicParams->NicIndex); >+ >+ OVS_CHECK(pNicEntry != NULL); >+ >+ pNicEntry = OVS_REFCOUNT_REFERENCE(pNicEntry); >+ } >+ >+ if (pNicEntry) >+ { >+ OVS_CHECK(pNicEntry->hvNicInfo.dpPortNumber == >OVS_INVALID_PORT_NUMBER); >+ >+ portId = pNicEntry->hvNicInfo.portId; >+ nicIndex = pNicEntry->hvNicInfo.nicIndex; >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ if (portId != NDIS_SWITCH_DEFAULT_PORT_ID) >+ { >+ dpPortNumber = DpPort_SetHvNicIndexAndPortId(pSwitchContext, >portId, nicIndex); >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ if (pNicEntry) >+ { >+ pNicEntry->hvNicInfo.dpPortNumber = dpPortNumber; >+ pNicEntry->hvNicInfo.connected = TRUE; >+ >+ ++(pSwitchContext->numPhysicalNics); >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ //Cleanup >+ OVS_REFCOUNT_DEREFERENCE(pNicEntry); >+} >+ >+_Use_decl_annotations_ >+VOID HVNic_OnDisconnect(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pNicParams) >+{ >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ OvsWaitActivate(pSwitchContext, >OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC); >+ >+ if (!pSwitchContext->isActivated) { >+ LOG_WARN("Switch is not activated yet."); >+ return; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ if (pNicParams->NicType == NdisSwitchNicTypeExternal) >+ { >+ OVS_CHECK(pSwitchContext->pExternalNic); >+ >+ if (pNicParams->NicIndex == >pSwitchContext->pExternalNic->hvNicInfo.nicIndex) >+ { >+ pNicEntry = pSwitchContext->pExternalNic; >+ } >+ } >+ else if (pNicParams->NicType == NdisSwitchNicTypeInternal) >+ { >+ OVS_CHECK(pSwitchContext->pInternalNic); >+ >+ pNicEntry = pSwitchContext->pInternalNic; >+ } >+ else >+ { >+ pNicEntry = HVNic_FindByPortIdAndNicIndex_Unsafe(pSwitchContext, >pNicParams->PortId, pNicParams->NicIndex); >+ >+ OVS_CHECK(pNicEntry != NULL); >+ } >+ >+ if (pNicEntry != NULL) >+ { >+ pNicEntry->hvNicInfo.connected = FALSE; >+ --(pSwitchContext->numPhysicalNics); >+ >+ //we no longer need to 'unset' the dp port: it will try >(eventually) to send to this port id, but it will not find nic, so it >will fail. >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+} >+ >+_Use_decl_annotations_ >+VOID HVNic_OnDelete(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pNicParams) >+{ >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ OvsWaitActivate(pSwitchContext, >OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC); >+ if (!pSwitchContext->isActivated) >+ { >+ LOG_WARN("Switch is not activated yet."); >+ return; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ if (pNicParams->NicType == NdisSwitchNicTypeExternal) >+ { >+ OVS_CHECK(pSwitchContext->pExternalNic); >+ >+ if (pNicParams->NicIndex == >pSwitchContext->pExternalNic->hvNicInfo.nicIndex) >+ { >+ OVS_CHECK(pSwitchContext->pExternalNic->hvNicInfo.connected >== FALSE); >+ pSwitchContext->pExternalNic = NULL; >+ } >+ } >+ else if (pNicParams->NicType == NdisSwitchNicTypeInternal) >+ { >+ OVS_CHECK(pSwitchContext->pInternalNic); >+ >+ if (pNicParams->NicIndex == >pSwitchContext->pInternalNic->hvNicInfo.nicIndex) >+ { >+ OVS_CHECK(pSwitchContext->pInternalNic->hvNicInfo.connected >== FALSE); >+ pSwitchContext->pInternalNic = FALSE; >+ } >+ } >+ >+ HVNic_Delete_Unsafe(pSwitchContext, pNicParams->PortId, >pNicParams->NicIndex); >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ return; >+} >+ >+_Use_decl_annotations_ >+VOID HVNic_OnUpdate(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_NIC_PARAMETERS* pNicParams) >+{ >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ LOCK_STATE_EX lockState = { 0 }; >+ UINT32 status = 0; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+ OvsWaitActivate(pSwitchContext, >OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC); >+ >+ if (!pSwitchContext->isActivated) { >+ LOG_WARN("Switch is not activated yet."); >+ return; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ pNicEntry = HVNic_FindByPortIdAndNicIndex_Unsafe(pSwitchContext, >pNicParams->PortId, pNicParams->NicIndex); >+ if (!pNicEntry) >+ { >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ return; >+ } >+ >+ switch (pNicParams->NicType) >+ { >+ case NdisSwitchNicTypeExternal: >+ case NdisSwitchNicTypeInternal: >+ RtlCopyMemory(&pNicEntry->hvNicInfo.netCfgInstanceId, >&pNicParams->NetCfgInstanceId, sizeof(GUID)); >+ break; >+ >+ case NdisSwitchNicTypeSynthetic: >+ case NdisSwitchNicTypeEmulated: >+ break; >+ >+ default: >+ OVS_CHECK(__UNEXPECTED__); >+ } >+ >+ if (!RtlEqualMemory(pNicEntry->hvNicInfo.macAddress, >pNicParams->PermanentMacAddress, sizeof(pNicEntry->hvNicInfo.macAddress))) >+ { >+ RtlCopyMemory(pNicEntry->hvNicInfo.macAddress, >pNicParams->PermanentMacAddress, sizeof(pNicEntry->hvNicInfo.macAddress)); >+ //status |= OVS_EVENT_MAC_CHANGE; >+ } >+ >+ if (pNicEntry->hvNicInfo.mtu != pNicParams->MTU) >+ { >+ pNicEntry->hvNicInfo.mtu = pNicParams->MTU; >+ //status |= OVS_EVENT_MTU_CHANGE; >+ } >+ >+ pNicEntry->hvNicInfo.numaNodeId = pNicParams->NumaNodeId; >+ dpPortNumber = pNicEntry->hvNicInfo.dpPortNumber; >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ if (status && dpPortNumber) >+ { >+ //OvsPostEvent(dpPortNumber, status); >+ } >+} >+ >+_Use_decl_annotations_ >+NDIS_STATUS HVNic_OnProcessRequest(const NDIS_OID_REQUEST* pOidRequest) >+{ >+ if (pOidRequest->RequestType == NdisRequestSetInformation && >pOidRequest->DATA.SET_INFORMATION.Oid == OID_NIC_SWITCH_ALLOCATE_VF) >+ { >+ return NDIS_STATUS_FAILURE; >+ } >+ >+ return NDIS_STATUS_SUCCESS; >+} >+ >+static NDIS_STATUS _HvNicIsSupported(_In_ OVS_SWITCH_CONTEXT* >pSwitchInfo, _In_ const NDIS_SWITCH_NIC_PARAMETERS* pCurNic) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ >+ //HANDLE CASE: traffic flows through VF (must disable VF - packets >will pass through the switch port instead). Read more here: >+ >//https://urldefense.proofpoint.com/v1/url?u=http://msdn.microsoft.com/en- >us/library/windows/hardware/hh598215%28v%3Dvs.85%29.aspx&k=oIvRg1%2BdGAgOo >M1BIlLLqw%3D%3D%0A&r=pEkjsHfytvHEWufeZPpgqSOJMdMjuZPbesVsNhCUc0E%3D%0A&m=r >MyshbVzg7JjbsLBmZ63esZiT3wVv3iF4NDNF9c6omE%3D%0A&s=3914e4ad6669a7141afac76 >4d35f975ff328288fef8721b9dcbe55f14c775ca3 >+ //"VFAssigned: A BOOLEAN value that, if set to TRUE, specifies that >the network adapter is attached to a PCI Express (PCIe) virtual function >(VF). >+ //A VF is exposed by an underlying physical network adapter that >supports the single root I/O virtualization (SR-IOV) interface." >+ >+ // If a VF is assigned to a NIC, then the traffic flows through the >VF and not the switch. This means we have to revoke the VF to enforce our >policy. >+ if (pCurNic->VFAssigned) >+ { >+ status = >pSwitchInfo->NdisSwitchHandlers.ReferenceSwitchNic(pSwitchInfo->NdisSwitch >Context, pCurNic->PortId, pCurNic->NicIndex); >+ OVS_CHECK(status == NDIS_STATUS_SUCCESS); >+ >+ //TODO issue status indication: NDIS_STATUS_SWITCH_PORT_REMOVE_VF >+ >+ status = >pSwitchInfo->NdisSwitchHandlers.DereferenceSwitchNic(pSwitchInfo->NdisSwit >chContext, pCurNic->PortId, pCurNic->NicIndex); >+ OVS_CHECK(status == NDIS_STATUS_SUCCESS); >+ } >+ >+ return status; >+} >+ >+NDIS_STATUS HvNic_InitializeList(_Inout_ OVS_SWITCH_CONTEXT* pSwitchInfo) >+{ >+ NDIS_STATUS status = STATUS_SUCCESS; >+ PNDIS_SWITCH_NIC_ARRAY nicArray = NULL; >+ >+ // Then it queries the NIC list >+ // Now, get NIC list. >+ status = OvsGetNicsOnSwitch(pSwitchInfo, &nicArray); >+ if (status != NDIS_STATUS_SUCCESS) >+ { >+ goto Cleanup; >+ } >+ >+ // and verifies it can support all of the NICs currently connected >to the switch >+ for (ULONG i = 0; i < nicArray->NumElements; ++i) >+ { >+ NDIS_SWITCH_NIC_PARAMETERS* pCurNic = >NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, i); >+ >+ status = _HvNicIsSupported(pSwitchInfo, pCurNic); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ >+ if (pCurNic->NicType == NdisSwitchNicTypeExternal && >+ pCurNic->NicIndex != NDIS_SWITCH_DEFAULT_NIC_INDEX && >!(pSwitchInfo->pExternalNic)) >+ { >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check >if there's a property for it, and add it to the NIC list. >+ status = HVNic_Add_Unsafe(pSwitchInfo, pCurNic, >&pNicEntry); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pNicEntry); >+ pSwitchInfo->pExternalNic = pNicEntry; >+ } >+ } >+ //NOTE: the internal port has nic index = 0 >+ else if (pCurNic->NicType == NdisSwitchNicTypeInternal && >!(pSwitchInfo->pInternalNic)) >+ { >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check >if there's a property for it, and add it to the NIC list. >+ status = HVNic_Add_Unsafe(pSwitchInfo, pCurNic, >&pNicEntry); >+ >+ //OvsInternalAdapterUp(vport->portNo, >&(pCurNic->NetCfgInstanceId)); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pNicEntry); >+ pSwitchInfo->pInternalNic = pNicEntry; >+ } >+ } >+ else if (pCurNic->NicType != NdisSwitchNicTypeExternal) >+ { >+ OVS_CHECK(pCurNic->NicType != NdisSwitchNicTypeInternal); >+ >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check >if there's a property for it, and add it to the NIC list. >+ status = HVNic_Add_Unsafe(pSwitchInfo, pCurNic, >&pNicEntry); >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pNicEntry); >+ } >+ } >+ >+ if (pNicEntry) >+ { >+ OVS_CHECK(pNicEntry->hvNicInfo.dpPortNumber == >OVS_INVALID_PORT_NUMBER); >+ >+ ++(pSwitchInfo->numPhysicalNics); >+ } >+ } >+ else >+ { >+ goto Cleanup; >+ } >+ } >+ >+Cleanup: >+ OVS_FREE(nicArray); >+ >+ return status; >+} >diff --git a/datapath-windows/ovsext/Hyper-V/HvNic.h >b/datapath-windows/ovsext/Hyper-V/HvNic.h >new file mode 100644 >index 0000000..c69a49b >--- /dev/null >+++ b/datapath-windows/ovsext/Hyper-V/HvNic.h >@@ -0,0 +1,66 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#pragma once >+ >+#include "precomp.h" >+#include "Protocol/Ethernet.h" >+ >+typedef struct _OVS_SWITCH_CONTEXT OVS_SWITCH_CONTEXT; >+ >+#define OVS_NIC_ENTRY_NAME_SIZE IF_MAX_STRING_SIZE >+ >+typedef struct _OVS_HVNIC_INFO >+{ >+ UINT8 macAddress[ETH_ADDR_LENGTH]; >+ NDIS_SWITCH_PORT_ID portId; >+ NDIS_SWITCH_NIC_INDEX nicIndex; >+ NDIS_SWITCH_NIC_TYPE nicType; >+ >+ BOOLEAN connected; >+ ULONG mtu; >+ >+ //netCfgInstanceId: valid only for internal / external >+ GUID netCfgInstanceId; >+ USHORT numaNodeId; >+ >+ //OVS_INVALID_PORT_NUMBER (0xFFFF) if we don't have one >+ UINT16 dpPortNumber; >+#ifdef DBG >+ CHAR vmName[OVS_NIC_ENTRY_NAME_SIZE + >1]; >+ CHAR adapName[OVS_NIC_ENTRY_NAME_SIZE >+ 1]; >+#endif >+}OVS_HVNIC_INFO; >+ >+typedef struct _OVS_HVNIC_ENTRY >+{ >+ OVS_REF_COUNT refCount; >+ >+ LIST_ENTRY listEntry; >+ OVS_HVNIC_INFO hvNicInfo; >+} OVS_HVNIC_ENTRY, *POVS_HVNIC_ENTRY; >+ >+NDIS_STATUS HVNic_OnCreate(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, >_In_ const NDIS_SWITCH_NIC_PARAMETERS* pNic); >+VOID HVNic_OnConnect(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_NIC_PARAMETERS* pNic); >+VOID HVNic_OnDisconnect(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_NIC_PARAMETERS* pNic); >+VOID HVNic_OnDelete(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_NIC_PARAMETERS* pNic); >+VOID HVNic_OnUpdate(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_NIC_PARAMETERS* pNic); >+ >+NDIS_STATUS HVNic_OnProcessRequest(_In_ const NDIS_OID_REQUEST* >pOidRequest); >+ >+OVS_HVNIC_ENTRY* HVNic_FindByPortIdAndNicIndex_Unsafe(_In_ const >OVS_SWITCH_CONTEXT* pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId, _In_ >NDIS_SWITCH_NIC_INDEX nicIndex); >+OVS_HVNIC_ENTRY* HVNic_FindByPortId_Unsafe(_In_ const >OVS_SWITCH_CONTEXT* pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId); >+NDIS_STATUS HvNic_InitializeList(_Inout_ OVS_SWITCH_CONTEXT* >pSwitchInfo); >diff --git a/datapath-windows/ovsext/Hyper-V/HvPort.c >b/datapath-windows/ovsext/Hyper-V/HvPort.c >new file mode 100644 >index 0000000..222c5df >--- /dev/null >+++ b/datapath-windows/ovsext/Hyper-V/HvPort.c >@@ -0,0 +1,410 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#include "precomp.h" >+#include "HvPort.h" >+#include "Switch.h" >+#include "Core/List.h" >+#include "OpenFlow\DpPort.h" >+#include "Oid.h" >+ >+NDIS_STATUS HVPort_Delete_Unsafe(_In_ const OVS_SWITCH_CONTEXT* >pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ >+ OVS_HVPORT_ENTRY* pPortEntry = >HVPort_FindById_Unsafe(pSwitchContext, portId); >+ if (pPortEntry == NULL) >+ { >+ OVS_CHECK(FALSE); >+ goto Cleanup; >+ } >+ >+ OVS_CHECK(pPortEntry->dpPortNumber == OVS_INVALID_PORT_NUMBER); >+ >+ OVS_REFCOUNT_DESTROY(pPortEntry); >+ >+Cleanup: >+ return status; >+} >+ >+VOID HVPortEntry_DestroyNow_Unsafe(OVS_HVPORT_ENTRY* pPortEntry) >+{ >+ if (pPortEntry) >+ { >+ RemoveEntryList(&pPortEntry->listEntry); >+ OVS_FREE(pPortEntry); >+ } >+} >+ >+OVS_HVPORT_ENTRY* HVPort_FindById_Unsafe(_In_ const OVS_SWITCH_CONTEXT* >pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId) >+{ >+ OVS_HVPORT_ENTRY* pHVPortEntry = NULL; >+ >+ OVS_LIST_FOR_EACH(OVS_HVPORT_ENTRY, pHVPortEntry, >&(pSwitchContext->hvPortList)) >+ { >+ if (pHVPortEntry->portId == portId) >+ { >+ return pHVPortEntry; >+ } >+ } >+ >+ return NULL; >+} >+ >+OVS_HVPORT_ENTRY* HVPort_FindBy_Unsafe(_In_ OVS_SWITCH_CONTEXT* >pSwitchInfo, const VOID* pContext, BOOLEAN(*Predicate)(int, const VOID*, >_In_ const OVS_HVPORT_ENTRY*)) >+{ >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ int i = 0; >+ >+ OVS_LIST_FOR_EACH(OVS_HVPORT_ENTRY, pPortEntry, >&(pSwitchInfo->hvPortList)) >+ { >+ if ((*Predicate)(i, pContext, pPortEntry)) >+ { >+ return pPortEntry; >+ } >+ >+ ++i; >+ } >+ >+ return NULL; >+} >+ >+NDIS_STATUS HVPort_Add_Unsafe(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pCurPort, _Inout_opt_ OVS_HVPORT_ENTRY** >ppPortEntry) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ LIST_ENTRY* pPortList = &pSwitchContext->hvPortList; >+ char* dpPortName = NULL; >+ >+ pPortEntry = HVPort_FindById_Unsafe(pSwitchContext, >pCurPort->PortId); >+ if (pPortEntry) >+ { >+ return status; >+ } >+ >+ pPortEntry = KZAlloc(sizeof(OVS_HVPORT_ENTRY)); >+ if (pPortEntry == NULL) >+ { >+ status = NDIS_STATUS_RESOURCES; >+ goto Cleanup; >+ } >+ >+ pPortEntry->refCount.Destroy = HVPortEntry_DestroyNow_Unsafe; >+ pPortEntry->portId = pCurPort->PortId; >+ pPortEntry->portType = pCurPort->PortType; >+ pPortEntry->on = (pCurPort->PortState == NdisSwitchPortStateCreated); >+ pPortEntry->portFriendlyName = pCurPort->PortFriendlyName; >+ pPortEntry->dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+ LOG_INFO("PORT: id=%d; type=%d; on=%d; friendly name=\"%s\"\n", >+ pPortEntry->portId, pPortEntry->portType, pPortEntry->on, >dpPortName); >+ >+ InsertHeadList(pPortList, &pPortEntry->listEntry); >+ >+ if (ppPortEntry) >+ { >+ *ppPortEntry = pPortEntry; >+ } >+ >+Cleanup: >+ OVS_FREE(dpPortName); >+ >+ return status; >+} >+ >+/*********************************************************************/ >+ >+_Use_decl_annotations_ >+NDIS_STATUS HVPort_OnCreate(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pPort) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ LOCK_STATE_EX lockState = { 0 }; >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ char* dpPortName = NULL; >+ NDIS_SWITCH_PORT_ID portId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ >+ //TODO: change to "if (pPort->IsValidationPort) return >NDIS_STATUS_SUCCESS;" >+ if (pPort->IsValidationPort) >+ { >+ return NDIS_STATUS_SUCCESS; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ OVS_CHECK(pPort->PortState == NdisSwitchPortStateCreated); >+ status = HVPort_Add_Unsafe(pSwitchContext, pPort, &pPortEntry); >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ ++(pSwitchContext->numVports); >+ >+ OVS_CHECK(pPortEntry); >+ //Sctx_Port_SetDpPort_Unsafe(pPortEntry); >+ pPortEntry = OVS_REFCOUNT_REFERENCE(pPortEntry); >+ //nothing could have been able to mark for deletion the >pPortEntry right now -- or, could it? >+ OVS_CHECK(pPortEntry); >+ >+ portId = pPortEntry->portId; >+ dpPortName = >IfCountedStringToCharArray(&pPortEntry->portFriendlyName); >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ if (status != NDIS_STATUS_SUCCESS) >+ { >+ return status; >+ } >+ >+ if (dpPortName) >+ { >+ dpPortNumber = DpPort_SetHvPortId(pSwitchContext, dpPortName, >portId); >+ } >+ >+ OVS_CHECK(pPortEntry); >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ pPortEntry->dpPortNumber = dpPortNumber; >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ //Cleanup >+ OVS_FREE(dpPortName); >+ >+ OVS_REFCOUNT_DEREFERENCE(pPortEntry); >+ >+ return status; >+} >+ >+_Use_decl_annotations_ >+VOID HVPort_OnUpdate(const OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pPort) >+{ >+ LOCK_STATE_EX lockState = { 0 }; >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ NDIS_SWITCH_PORT_ID portId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ char* dpPortName = NULL; >+ >+ if (pPort->IsValidationPort) >+ { >+ return; >+ } >+ >+ HVSWITCH_LOCK_READ(pSwitchContext, &lockState); >+ >+ OVS_CHECK(pPort->PortState == NdisSwitchPortStateCreated); >+ pPortEntry = HVPort_FindById_Unsafe(pSwitchContext, pPort->PortId); >+ OVS_CHECK(pPortEntry); >+ >+ pPortEntry = OVS_REFCOUNT_REFERENCE(pPortEntry); >+ //could not have marked for deletion this quickly. >+ OVS_CHECK(pPortEntry); >+ >+ //if the name of the hyper-v switch port has changed, and we did not >have a mapping between this hyper-v switch port and a dp port, >+ //we find a mapping now >+ if (pPortEntry->dpPortNumber == OVS_INVALID_PORT_NUMBER && >+ (pPortEntry->portFriendlyName.Length != >pPort->PortFriendlyName.Length || >+ memcmp(pPortEntry->portFriendlyName.String, >pPort->PortFriendlyName.String, pPortEntry->portFriendlyName.Length))) >+ { >+ portId = pPortEntry->portId; >+ dpPortName = >IfCountedStringToCharArray(&pPortEntry->portFriendlyName); >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ if (dpPortName) >+ { >+ dpPortNumber = >DpPort_SetHvPortId((OVS_SWITCH_CONTEXT*)pSwitchContext, dpPortName, >portId); >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ pPortEntry->dpPortNumber = dpPortNumber; >+ pPortEntry->portFriendlyName = pPort->PortFriendlyName; >+ pPortEntry->portType = pPort->PortType; >+ pPortEntry->on = (pPort->PortState == NdisSwitchPortStateCreated); >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ //Cleanup >+ OVS_FREE(dpPortName); >+ >+ OVS_REFCOUNT_DEREFERENCE(pPortEntry); >+} >+ >+_Use_decl_annotations_ >+VOID HVPort_OnTeardown(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pPort) >+{ >+ LOCK_STATE_EX lockState = { 0 }; >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ >+ if (pPort->IsValidationPort) >+ { >+ return; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ if (pPort->PortType == NdisSwitchPortTypeExternal) >+ { >+ OVS_CHECK(pSwitchContext->pExternalPort); >+ >+ if (pPort->PortId == pSwitchContext->pExternalPort->portId) >+ { >+ pPortEntry = pSwitchContext->pExternalPort; >+ } >+ } >+ else if (pPort->PortType == NdisSwitchPortTypeInternal) >+ { >+ OVS_CHECK(pSwitchContext->pInternalPort); >+ OVS_CHECK(pPort->PortId == >pSwitchContext->pInternalPort->portId); >+ >+ pPortEntry = pSwitchContext->pInternalPort; >+ } >+ else >+ { >+ pPortEntry = HVPort_FindById_Unsafe(pSwitchContext, >pPort->PortId); >+ >+ OVS_CHECK(pPortEntry != NULL); >+ } >+ >+ if (pPortEntry) >+ { >+ //we no longer 'unset' the dp port: when it will try to output >to dp port, it will find a hyper v switch port / nic, >+ //it will not find one, so it will drop the packet. >+ --(pSwitchContext->numVports); >+ pPortEntry->on = FALSE; >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ return; >+} >+ >+_Use_decl_annotations_ >+VOID >+HVPort_OnDelete(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pPort) >+{ >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ if (pPort->IsValidationPort) >+ { >+ return; >+ } >+ >+ HVSWITCH_LOCK_WRITE(pSwitchContext, &lockState); >+ >+ if (pPort->PortType == NdisSwitchPortTypeExternal) >+ { >+ OVS_CHECK(pSwitchContext->pExternalPort); >+ >+ if (pPort->PortId == pSwitchContext->pExternalPort->portId) >+ { >+ OVS_CHECK(pSwitchContext->pExternalPort->on == FALSE); >+ pSwitchContext->pExternalPort = NULL; >+ } >+ } >+ else if (pPort->PortType == NdisSwitchPortTypeInternal) >+ { >+ OVS_CHECK(pSwitchContext->pInternalPort); >+ >+ if (pPort->PortId == pSwitchContext->pInternalPort->portId) >+ { >+ OVS_CHECK(pSwitchContext->pInternalPort->on == FALSE); >+ pSwitchContext->pInternalPort = FALSE; >+ } >+ } >+ >+ HVPort_Delete_Unsafe(pSwitchContext, pPort->PortId); >+ >+ HVSWITCH_UNLOCK(pSwitchContext, &lockState); >+ >+ return; >+} >+ >+NDIS_STATUS HVPort_InitializeList(_Inout_ OVS_SWITCH_CONTEXT* >pSwitchInfo) >+{ >+ NDIS_STATUS status = STATUS_SUCCESS; >+ PNDIS_SWITCH_PORT_ARRAY portArray = NULL; >+ >+ // Then it queries the NIC list >+ // Now, get NIC list. >+ status = OvsGetPortsOnSwitch(pSwitchInfo, &portArray); >+ if (status != NDIS_STATUS_SUCCESS) >+ { >+ goto Cleanup; >+ } >+ >+ // and verifies it can support all of the NICs currently connected >to the switch >+ for (ULONG i = 0; i < portArray->NumElements; ++i) >+ { >+ NDIS_SWITCH_PORT_PARAMETERS* pCurPort = >NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, i); >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ >+ if (pCurPort->IsValidationPort) >+ { >+ continue; >+ } >+ >+ if (pCurPort->PortType == NdisSwitchPortTypeExternal && >!pSwitchInfo->pExternalPort) >+ { >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check if >there's a property for it, and add it to the NIC list. >+ status = HVPort_Add_Unsafe(pSwitchInfo, pCurPort, >&pPortEntry); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pPortEntry); >+ pSwitchInfo->pExternalPort = pPortEntry; >+ } >+ } >+ //NOTE: the internal port has nic index = 0 >+ else if (pCurPort->PortType == NdisSwitchPortTypeInternal && >!pSwitchInfo->pInternalPort) >+ { >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check if >there's a property for it, and add it to the NIC list. >+ status = HVPort_Add_Unsafe(pSwitchInfo, pCurPort, >&pPortEntry); >+ >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pPortEntry); >+ pSwitchInfo->pInternalPort = pPortEntry; >+ } >+ } >+ else if (pCurPort->PortType != NdisSwitchPortTypeInternal && >+ pCurPort->PortType != NdisSwitchPortTypeExternal) >+ { >+ // and adds the NICs to the NIC list. >+ // Now we've verified we can support the NIC, so check if >there's a property for it, and add it to the NIC list. >+ status = HVPort_Add_Unsafe(pSwitchInfo, pCurPort, >&pPortEntry); >+ if (status == NDIS_STATUS_SUCCESS) >+ { >+ OVS_CHECK(pPortEntry); >+ } >+ } >+ >+ if (pPortEntry) >+ { >+ OVS_CHECK(pPortEntry->dpPortNumber == >OVS_INVALID_PORT_NUMBER); >+ >+ pPortEntry->on = (pCurPort->PortState == >NdisSwitchPortStateCreated); >+ ++(pSwitchInfo->numVports); >+ } >+ } >+ >+Cleanup: >+ OVS_FREE(portArray); >+ >+ return status; >+} >diff --git a/datapath-windows/ovsext/Hyper-V/HvPort.h >b/datapath-windows/ovsext/Hyper-V/HvPort.h >new file mode 100644 >index 0000000..eef3ce4 >--- /dev/null >+++ b/datapath-windows/ovsext/Hyper-V/HvPort.h >@@ -0,0 +1,56 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#pragma once >+ >+/* PORT OID HANDLERS */ >+ >+typedef struct _OVS_SWITCH_CONTEXT OVS_SWITCH_CONTEXT; >+ >+typedef struct _OVS_HVPORT_ENTRY >+{ >+ //must be the first field in the struct >+ OVS_REF_COUNT refCount; >+ >+ LIST_ENTRY listEntry; >+ >+ NDIS_SWITCH_PORT_ID portId; >+ NDIS_SWITCH_PORT_FRIENDLYNAME portFriendlyName; >+ NDIS_SWITCH_PORT_TYPE portType; >+ BOOLEAN on; >+ >+ //OVS_INVALID_PORT_NUMBER (0xFFFF) when we don't have one >+ UINT16 dpPortNumber; >+} OVS_HVPORT_ENTRY, *POVS_HVPORT_ENTRY; >+ >+/***************************************************** PORT >****************************************************/ >+ >+NDIS_STATUS HVPort_OnCreate(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, >_In_ const NDIS_SWITCH_PORT_PARAMETERS* pPort); >+ >+VOID HVPort_OnUpdate(_In_ const OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_PORT_PARAMETERS* pPort); >+ >+VOID HVPort_OnTeardown(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_PORT_PARAMETERS* pPort); >+ >+VOID HVPort_OnDelete(_Inout_ OVS_SWITCH_CONTEXT* pSwitchContext, _In_ >const NDIS_SWITCH_PORT_PARAMETERS* pPort); >+ >+ >+NDIS_STATUS HVPort_Add_Unsafe(OVS_SWITCH_CONTEXT* pSwitchContext, const >NDIS_SWITCH_PORT_PARAMETERS* pCurPort, _Inout_opt_ OVS_HVPORT_ENTRY** >ppPortEntry); >+OVS_HVPORT_ENTRY* HVPort_FindById_Unsafe(_In_ const OVS_SWITCH_CONTEXT* >pSwitchContext, _In_ NDIS_SWITCH_PORT_ID portId); >+OVS_HVPORT_ENTRY* HVPort_FindBy_Unsafe(_In_ OVS_SWITCH_CONTEXT* >pSwitchInfo, const VOID* pContext, BOOLEAN(*Predicate)(int, const VOID*, >_In_ const OVS_HVPORT_ENTRY*)); >+UINT16 DpPort_SetHvPortId(_In_ OVS_SWITCH_CONTEXT* pSwitchInfo, const >char* dpPortName, NDIS_SWITCH_PORT_ID portId); >+ >+VOID HVPortEntry_DestroyNow_Unsafe(OVS_HVPORT_ENTRY* pPortEntry); >+NDIS_STATUS HVPort_InitializeList(_Inout_ OVS_SWITCH_CONTEXT* >pSwitchInfo); >diff --git a/datapath-windows/ovsext/Hyper-V/Switch.h >b/datapath-windows/ovsext/Hyper-V/Switch.h >index d80d744..e0c755f 100644 >--- a/datapath-windows/ovsext/Hyper-V/Switch.h >+++ b/datapath-windows/ovsext/Hyper-V/Switch.h >@@ -21,6 +21,7 @@ > #ifndef __OVS_SWITCH_H_ > #define __OVS_SWITCH_H_ 1 > >+#include "Core\FixedSizedArray.h" > #include "Protocol\NetProto.h" > #include "Transfer\BufferMgmt.h" > #define OVS_MAX_VPORT_ARRAY_SIZE 1024 >@@ -53,11 +54,16 @@ > > #define OVS_HASH_BASIS 0x13578642 > >+typedef struct _OVS_HVPORT_ENTRY OVS_HVPORT_ENTRY; >+typedef struct _OVS_HVNIC_ENTRY OVS_HVNIC_ENTRY; >+ > typedef struct _OVS_DATAPATH > { > PLIST_ENTRY flowTable; // Contains OvsFlows. > UINT32 nFlows; // Number of entries in >flowTable. > >+ OVS_FIXED_SIZED_ARRAY dpPorts; >+ > // List_Links queues[64]; // Hash table of queue >IDs. > > /* Statistics. */ >@@ -104,13 +110,21 @@ typedef struct _OVS_SWITCH_CONTEXT > > NDIS_SWITCH_PORT_ID externalPortId; > NDIS_SWITCH_PORT_ID internalPortId; >- PVOID externalVport; // the virtual adapter vport >- PVOID internalVport; > >+ OVS_HVPORT_ENTRY* pExternalPort; >+ OVS_HVPORT_ENTRY* pInternalPort; >+ OVS_HVNIC_ENTRY* pExternalNic; >+ OVS_HVNIC_ENTRY* pInternalNic; >+ >+ /* XXX: remote vportArray, nameHashArray, portHashArray. >+ /* use hvNic and hvPort lists only */ > PVOID *vportArray; > PLIST_ENTRY nameHashArray; // based on ovsName > PLIST_ENTRY portHashArray; // based on portId > >+ LIST_ENTRY hvPortList; >+ LIST_ENTRY hvNicList; >+ > UINT32 numPhysicalNics; > UINT32 numVports; // include validation port > UINT32 lastPortIndex; >@@ -134,6 +148,10 @@ typedef struct _OVS_SWITCH_CONTEXT > OVS_NBL_POOL ovsPool; > } OVS_SWITCH_CONTEXT, *POVS_SWITCH_CONTEXT; > >+#define HVSWITCH_LOCK_READ(pSwitchContext, pLockState) >NdisAcquireRWLockRead(pSwitchContext->dispatchLock, pLockState, 0) >+#define HVSWITCH_LOCK_WRITE(pSwitchContext, pLockState) >NdisAcquireRWLockWrite(pSwitchContext->dispatchLock, pLockState, 0) >+#define HVSWITCH_UNLOCK(pSwitchContext, pLockState) >NdisReleaseRWLock(pSwitchContext->dispatchLock, pLockState) >+ > > static __inline VOID > OvsAcquireDatapathRead(OVS_DATAPATH *datapath, >diff --git a/datapath-windows/ovsext/OpenFlow/DpPort.c >b/datapath-windows/ovsext/OpenFlow/DpPort.c >new file mode 100644 >index 0000000..b9057f3 >--- /dev/null >+++ b/datapath-windows/ovsext/OpenFlow/DpPort.c >@@ -0,0 +1,632 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#include "DpPort.h" >+ >+#include "Core\List.h" >+#include "Hyper-V\HvNic.h" >+#include "Hyper-V\HvPort.h" >+#include "Hyper-V\Switch.h" >+ >+#include <ntstrsafe.h> >+ >+extern OVS_SWITCH_CONTEXT* g_pSwitchInfo; >+ >+static LIST_ENTRY g_grePorts; >+static LIST_ENTRY g_vxlanPorts; >+ >+NDIS_RW_LOCK_EX* g_pLogicalPortsLock = NULL; >+ >+/******************************** LOGICAL PORTS & TUNNELS >/********************************/ >+ >+static BOOLEAN _AddDpPort_Logical(LIST_ENTRY* pList, _In_ const >OVS_DPPORT* pPort) >+{ >+ OVS_LOGICAL_PORT_ENTRY* pPortEntry = NULL; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ pPortEntry = OVS_ALLOC(sizeof(OVS_LOGICAL_PORT_ENTRY)); >+ if (!pPortEntry) >+ { >+ return FALSE; >+ } >+ >+ pPortEntry->pPort = (OVS_DPPORT*)pPort; >+ >+ NdisAcquireRWLockWrite(g_pLogicalPortsLock, &lockState, 0); >+ InsertTailList(pList, &pPortEntry->listEntry); >+ NdisReleaseRWLock(g_pLogicalPortsLock, &lockState); >+ >+ return TRUE; >+} >+ >+static BOOLEAN _RemoveDpPort_Logical(LIST_ENTRY* pList, _In_ const >OVS_DPPORT* pPort) >+{ >+ OVS_LOGICAL_PORT_ENTRY* pPortEntry = NULL; >+ BOOLEAN ok = FALSE; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ NdisAcquireRWLockWrite(g_pLogicalPortsLock, &lockState, 0); >+ >+ OVS_LIST_FOR_EACH(OVS_LOGICAL_PORT_ENTRY, pPortEntry, pList) >+ { >+ if (pPortEntry->pPort == pPort) >+ { >+ RemoveEntryList(&pPortEntry->listEntry); >+ >+ OVS_FREE(pPortEntry); >+ ok = TRUE; >+ goto Cleanup; >+ } >+ } >+ >+Cleanup: >+ NdisReleaseRWLock(g_pLogicalPortsLock, &lockState); >+ return ok; >+} >+ >+static BOOLEAN _AddDpPort_Gre(_In_ const OVS_DPPORT* pPort) >+{ >+ return _AddDpPort_Logical(&g_grePorts, pPort); >+} >+ >+static BOOLEAN _AddDpPort_Vxlan(_In_ const OVS_DPPORT* pPort) >+{ >+ return _AddDpPort_Logical(&g_vxlanPorts, pPort); >+} >+ >+static BOOLEAN _RemoveDpPort_Gre(_In_ const OVS_DPPORT* pPort) >+{ >+ return _RemoveDpPort_Logical(&g_grePorts, pPort); >+} >+ >+static BOOLEAN _RemoveDpPort_Vxlan(_In_ const OVS_DPPORT* pPort) >+{ >+ return _RemoveDpPort_Logical(&g_vxlanPorts, pPort); >+} >+ >+_Use_decl_annotations_ >+OVS_DPPORT* DpPort_FindGre_Ref() >+{ >+ OVS_LOGICAL_PORT_ENTRY* pPortEntry = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ NdisAcquireRWLockRead(g_pLogicalPortsLock, &lockState, 0); >+ >+ pPortEntry = CONTAINING_RECORD(g_grePorts.Flink, >OVS_LOGICAL_PORT_ENTRY, listEntry); >+ pOutPort = OVS_REFCOUNT_REFERENCE(pPortEntry->pPort); >+ >+ NdisReleaseRWLock(g_pLogicalPortsLock, &lockState); >+ >+ return pOutPort; >+} >+ >+_Use_decl_annotations_ >+OVS_DPPORT* DpPort_FindVxlan_Ref(LE16 udpDestPort) >+{ >+ OVS_LOGICAL_PORT_ENTRY* pPortEntry = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ NdisAcquireRWLockRead(g_pLogicalPortsLock, &lockState, 0); >+ >+ OVS_LIST_FOR_EACH(OVS_LOGICAL_PORT_ENTRY, pPortEntry, &g_vxlanPorts) >+ { >+ OVS_TUNNELING_PORT_OPTIONS* pOptions = NULL; >+ >+ pOptions = pPortEntry->pPort->pOptions; >+ OVS_CHECK(pOptions); >+ >+ if (pOptions->udpDestPort == udpDestPort) >+ { >+ pOutPort = OVS_REFCOUNT_REFERENCE(pPortEntry->pPort); >+ break; >+ } >+ } >+ >+ NdisReleaseRWLock(g_pLogicalPortsLock, &lockState); >+ >+ return pOutPort; >+} >+ >+/******************************** INIT AND UNINIT >********************************/ >+ >+BOOLEAN DpPort_InitializeLogicalPorts() >+{ >+ InitializeListHead(&g_grePorts); >+ InitializeListHead(&g_vxlanPorts); >+ >+ g_pLogicalPortsLock = NdisAllocateRWLock(NULL); >+ >+ return TRUE; >+} >+ >+VOID DpPort_UninitializeLogicalPorts() >+{ >+ OVS_CHECK(g_pLogicalPortsLock); >+ >+ NdisFreeRWLock(g_pLogicalPortsLock); >+ g_pLogicalPortsLock = NULL; >+} >+ >+/******************************** UTILITTY FUNCS >********************************/ >+ >+static BOOLEAN _PortFriendlyNameIs(int i, const char* portName, _In_ >const OVS_HVPORT_ENTRY* pPortEntry) >+{ >+ char asciiPortName[IF_MAX_STRING_SIZE + 1]; >+ >+ UNREFERENCED_PARAMETER(i); >+ >+ if (strlen(portName) != pPortEntry->portFriendlyName.Length / 2) >+ { >+ return FALSE; >+ } >+ >+ OVS_CHECK(pPortEntry->portFriendlyName.Length / 2 <= >IF_MAX_STRING_SIZE); >+ >+ NdisZeroMemory(asciiPortName, IF_MAX_STRING_SIZE + 1); >+ WcharArrayToAscii(asciiPortName, >pPortEntry->portFriendlyName.String, pPortEntry->portFriendlyName.Length >/ 2); >+ >+ return (0 == strcmp(portName, asciiPortName)); >+} >+ >+//Unsafe = does not lock the dpPort >+static VOID _DpPort_SetNicAndPort_Unsafe(OVS_SWITCH_CONTEXT* >pSwitchInfo, OVS_DPPORT* pPort) >+{ >+ LOCK_STATE_EX lockState = { 0 }; >+ const char* externalPortName = "external"; >+ >+ OVS_CHECK(pPort); >+ >+ //care must be taken: we lock here pSwitchInfo for read, while >having locked dp ports for write. >+ //we must not lock in any other part pSwitchInfo before or after dp >ports, or we will get into a deadlock. >+ HVSWITCH_LOCK_READ(pSwitchInfo, &lockState); >+ >+ if (pPort->dpPortType == OVS_DPPORT_TYPE_MANAG_OS) >+ { >+ if (pSwitchInfo->pInternalPort) >+ { >+ pPort->hvPortId = pSwitchInfo->pInternalPort->portId; >+ //TODO: should we use interlocked assign for >OVS_HVPORT_ENTRY's port id? >+ pSwitchInfo->pInternalPort->dpPortNumber = >pPort->dpPortNumber; >+ } >+ else >+ { >+ pPort->hvPortId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ } >+ } >+ else if (pPort->dpPortType == OVS_DPPORT_TYPE_GRE) >+ { >+ pPort->hvPortId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ } >+ else if (pPort->dpPortType == OVS_DPPORT_TYPE_VXLAN) >+ { >+ pPort->hvPortId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ } >+ else if (0 == strcmp(pPort->dpPortName, externalPortName)) >+ { >+ if (pSwitchInfo->pExternalPort) >+ { >+ //TODO: should we use interlockd assign for >OVS_HVPORT_ENTRY's port id? >+ pPort->hvPortId = pSwitchInfo->pExternalPort->portId; >+ pPort->isExternal = TRUE; >+ pSwitchInfo->pExternalPort->dpPortNumber = >pPort->dpPortNumber; >+ } >+ else >+ { >+ pPort->hvPortId = NDIS_SWITCH_DEFAULT_PORT_ID; >+ } >+ } >+ else >+ { >+ OVS_HVPORT_ENTRY* pPortEntry = NULL; >+ >+ pPortEntry = HVPort_FindBy_Unsafe(pSwitchInfo, >pPort->dpPortName, _PortFriendlyNameIs); >+ >+ if (pPortEntry) >+ { >+ OVS_HVNIC_ENTRY* pNicEntry = NULL; >+ pPort->hvPortId = pPortEntry->portId; >+ >+ pNicEntry = HVNic_FindByPortId_Unsafe(pSwitchInfo, >pPortEntry->portId); >+ if (pNicEntry) >+ { >+ pNicEntry->hvNicInfo.dpPortNumber = pPort->dpPortNumber; >+ } >+ } >+ } >+ >+ HVSWITCH_UNLOCK(pSwitchInfo, &lockState); >+} >+ >+UINT16 DpPort_SetHvPortId(_In_ OVS_DATAPATH* pDatapath, const char* >dpPortName, NDIS_SWITCH_PORT_ID portId) >+{ >+ OVS_DPPORT* pPort = NULL; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+ pPort = DpPort_FindByName_Ref(pDatapath, dpPortName); >+ if (pPort) >+ { >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ PORT_LOCK_WRITE(pPort, &lockState); >+ >+ pPort->hvPortId = portId; >+ dpPortNumber = pPort->dpPortNumber; >+ >+ PORT_UNLOCK(pPort, &lockState); >+ >+ OVS_REFCOUNT_DEREFERENCE(pPort); >+ } >+ >+ return dpPortNumber; >+} >+ >+OVS_DPPORT* DpPort_Create_Ref(OVS_SWITCH_CONTEXT* pSwitchInfo, _In_opt_ >const char* portName, _In_opt_ const UINT16* pPortNumber, OVS_DPPORT_TYPE >portType) >+{ >+ BOOLEAN ok = TRUE; >+ OVS_DPPORT* pPort = NULL; >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ BOOLEAN locked = FALSE; >+ LOCK_STATE_EX lockState; >+ OVS_DATAPATH* pDatapath = NULL; >+ >+ pDatapath = &(pSwitchInfo->datapath); >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ FXDARRAY_LOCK_WRITE(pPortsArray, &lockState); >+ locked = TRUE; >+ >+ if (pPortsArray->count >= OVS_MAX_PORTS) >+ { >+ ok = FALSE; >+ goto Cleanup; >+ } >+ >+ if (portType == OVS_DPPORT_TYPE_MANAG_OS) >+ { >+ //i.e. the first internal port is port LOCAL, must be created or >must have been created >+ //on slot = 0 (LOCAL port's number). ovs 1.11 allows multiple >internal (i.e. datapath) ports. >+ OVS_CHECK(pPortsArray->firstFree == OVS_LOCAL_PORT_NUMBER || >+ pPortsArray->array[OVS_LOCAL_PORT_NUMBER]); >+ OVS_CHECK(portName); >+ } >+ >+ pPort = KZAlloc(sizeof(OVS_DPPORT)); >+ if (!pPort) >+ { >+ ok = FALSE; >+ goto Cleanup; >+ } >+ >+ ((OVS_FXDARRAY_ITEM*)pPort)->refCount.Destroy = >DpPort_DestroyNow_Unsafe; >+ ((OVS_FXDARRAY_ITEM*)pPort)->pRwLock = NdisAllocateRWLock(NULL); >+ >+ //if name for port was not provided, we must have been given a number >+ if (!portName) >+ { >+ if (!pPortNumber) >+ { >+ ok = FALSE; >+ goto Cleanup; >+ } >+ >+ pPort->dpPortName = OVS_ALLOC(257); >+ if (!pPort->dpPortName) >+ { >+ ok = FALSE; >+ goto Cleanup; >+ } >+ >+ RtlStringCchPrintfA((char*)pPort->dpPortName, 257, "kport_%u", >*pPortNumber); >+ } >+ >+ //if a name has been given, we use it >+ else >+ { >+ ULONG portNameLen = (ULONG)strlen(portName) + 1; >+ >+ pPort->dpPortName = OVS_ALLOC(portNameLen); >+ if (!pPort->dpPortName) >+ { >+ ok = FALSE; >+ goto Cleanup; >+ } >+ >+ RtlStringCchCopyA((char*)pPort->dpPortName, portNameLen, >portName); >+ } >+ >+ //if port number was not given, we set it now to 0 an call below >_DpPort_AddByName_Unsafe >+ pPort->dpPortNumber = (pPortNumber ? *pPortNumber : 0); >+ pPort->dpPortType = portType; >+ >+ pPort = OVS_REFCOUNT_REFERENCE(pPort); >+ >+ if (portType == OVS_DPPORT_TYPE_GRE) >+ { >+ if (IsListEmpty(&g_grePorts)) >+ { >+ _AddDpPort_Gre(pPort); >+ } >+ else >+ { >+ LOG_ERROR("we already have gre vport!\n"); >+ ok = FALSE;//TODO: return EEXISTS! >+ goto Cleanup; >+ } >+ } >+ else if (portType == OVS_DPPORT_TYPE_VXLAN) >+ { >+ _AddDpPort_Vxlan(pPort); >+ } >+ >+ //NOTE: we may have more dp ports than NICS: logical ports don't >have nics associated >+ //the same goes with hyper-v switch ports >+ >+ _DpPort_SetNicAndPort_Unsafe(pSwitchInfo, pPort); >+ >+ if (pPortNumber) >+ { >+ OVS_ERROR error = FxdArray_AddByNumber_Unsafe(pPortsArray, >(OVS_FXDARRAY_ITEM*)pPort, pPort->dpPortNumber); >+ >+ if (error == OVS_ERROR_EXIST) >+ { >+ const OVS_DPPORT* pOtherPort = >(OVS_DPPORT*)pPortsArray->array[pPort->dpPortNumber]; >+ >+ UNREFERENCED_PARAMETER(pOtherPort); >+ >+ OVS_CHECK(pOtherPort->dpPortType == pPort->dpPortType); >+ OVS_CHECK(pOtherPort->dpPortNumber == pPort->dpPortNumber); >+ >+ ok = (error == OVS_ERROR_NOERROR); >+ } >+ >+ } >+ else >+ { >+ ok = FxdArray_Add_Unsafe(pPortsArray, (OVS_FXDARRAY_ITEM*)pPort, >&(pPort->dpPortNumber)); >+ } >+ >+ if (!ok) >+ { >+ goto Cleanup; >+ } >+ >+Cleanup: >+ if (!ok) >+ { >+ if (pPort) >+ { >+ DpPort_DestroyNow_Unsafe(pPort); >+ } >+ } >+ >+ if (locked) >+ { >+ FXDARRAY_UNLOCK(pPortsArray, &lockState); >+ } >+ >+ return (ok ? pPort : NULL); >+} >+ >+UINT16 DpPort_SetHvNicIndexAndPortId(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId, NDIS_SWITCH_NIC_INDEX nicIndex) >+{ >+ OVS_DPPORT* pPort = NULL; >+ LOCK_STATE_EX lockState; >+ UINT16 dpPortNumber = OVS_INVALID_PORT_NUMBER; >+ >+ FXDARRAY_LOCK_WRITE(&(pDatapath->dpPorts), &lockState); >+ >+ pPort = DpPort_FindById_Unsafe(pDatapath, portId); >+ if (pPort) >+ { >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ PORT_LOCK_WRITE(pPort, &lockState); >+ >+ pPort->hvPortId = portId; >+ pPort->hvNicIndex = nicIndex; >+ dpPortNumber = pPort->dpPortNumber; >+ >+ PORT_UNLOCK(pPort, &lockState); >+ } >+ >+ FXDARRAY_UNLOCK(&(pDatapath->dpPorts), &lockState); >+ >+ return dpPortNumber; >+} >+ >+/******************************** FIND FUNCTIONS >********************************/ >+ >+static __inline BOOLEAN _DpPort_IsExternal(OVS_FXDARRAY_ITEM* pItem, >UINT_PTR data) >+{ >+ OVS_DPPORT* pCurPort = (OVS_DPPORT*)pItem; >+ >+ UNREFERENCED_PARAMETER(data); >+ >+ return pCurPort->isExternal == TRUE && pCurPort->hvPortId != >NDIS_SWITCH_DEFAULT_PORT_ID; >+} >+ >+_Use_decl_annotations_ >+OVS_DPPORT* DpPort_FindExternal_Ref(OVS_DATAPATH* pDatapath) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Ref(pPortsArray, >_DpPort_IsExternal, NULL); >+ >+ return pOutPort; >+} >+ >+static __inline BOOLEAN _DpPort_IsInternal(OVS_FXDARRAY_ITEM* pItem, >UINT_PTR data) >+{ >+ OVS_DPPORT* pCurPort = (OVS_DPPORT*)pItem; >+ >+ UNREFERENCED_PARAMETER(data); >+ >+ return (pCurPort->dpPortType == OVS_DPPORT_TYPE_MANAG_OS && >+ pCurPort->hvPortId != NDIS_SWITCH_DEFAULT_PORT_ID); >+} >+ >+_Use_decl_annotations_ >+OVS_DPPORT* DpPort_FindInternal_Ref(OVS_DATAPATH* pDatapath) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Ref(pPortsArray, >_DpPort_IsInternal, NULL); >+ >+ return pOutPort; >+} >+ >+static __inline BOOLEAN _DpPort_NameEquals(OVS_FXDARRAY_ITEM* pItem, >UINT_PTR data) >+{ >+ OVS_DPPORT* pCurPort = (OVS_DPPORT*)pItem; >+ const char* dpPortName = (const char*)data; >+ >+ return (0 == strcmp(pCurPort->dpPortName, dpPortName)); >+} >+ >+OVS_DPPORT* DpPort_FindByName_Ref(OVS_DATAPATH* pDatapath, const char* >dpPortName) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Ref(pPortsArray, >_DpPort_NameEquals, dpPortName); >+ >+ return pOutPort; >+} >+ >+static __inline BOOLEAN _DpPort_PortIdEquals(OVS_FXDARRAY_ITEM* pItem, >UINT_PTR data) >+{ >+ OVS_DPPORT* pCurPort = (OVS_DPPORT*)pItem; >+ NDIS_SWITCH_PORT_ID portId = (NDIS_SWITCH_PORT_ID)data; >+ >+ return (pCurPort->hvPortId == portId); >+} >+ >+OVS_DPPORT* DpPort_FindById_Ref(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Ref(pPortsArray, >_DpPort_PortIdEquals, &portId); >+ >+ return pOutPort; >+} >+ >+OVS_DPPORT* DpPort_FindById_Unsafe(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Unsafe(pPortsArray, >_DpPort_PortIdEquals, &portId); >+ >+ return pOutPort; >+} >+ >+static __inline BOOLEAN _DpPort_PortNumberEquals(OVS_FXDARRAY_ITEM* >pItem, UINT_PTR data) >+{ >+ OVS_DPPORT* pCurPort = (OVS_DPPORT*)pItem; >+ UINT16 portNumber = (UINT16)data; >+ >+ return (pCurPort->dpPortNumber == portNumber); >+} >+ >+OVS_DPPORT* DpPort_FindByNumber_Ref(OVS_DATAPATH* pDatapath, UINT16 >portNumber) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ OVS_DPPORT* pOutPort = NULL; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ pOutPort = (OVS_DPPORT*)FxdArray_Find_Ref(pPortsArray, >_DpPort_PortNumberEquals, &portNumber); >+ >+ return pOutPort; >+} >+ >+/******************************** DELETE FUNCTIONS >********************************/ >+ >+//TODO: if it comes here unreferenced, then it means it might have been >deleted, I think >+BOOLEAN DpPort_Delete(OVS_DATAPATH* pDatapath, OVS_DPPORT* pPort) >+{ >+ OVS_FIXED_SIZED_ARRAY* pPortsArray = NULL; >+ BOOLEAN ok = TRUE; >+ BOOLEAN portsLocked = FALSE; >+ LOCK_STATE_EX lockState = { 0 }; >+ >+ pPortsArray = &(pDatapath->dpPorts); >+ >+ FXDARRAY_LOCK_WRITE(pPortsArray, &lockState); >+ portsLocked = TRUE; >+ >+ if (pPort->dpPortType == OVS_DPPORT_TYPE_GRE) >+ { >+ _RemoveDpPort_Gre(pPort); >+ } >+ else if (pPort->dpPortType == OVS_DPPORT_TYPE_VXLAN) >+ { >+ _RemoveDpPort_Vxlan(pPort); >+ } >+ >+ ok = FxdArray_Remove_Unsafe(pPortsArray, (OVS_FXDARRAY_ITEM*)pPort, >pPort->dpPortNumber); >+ if (!ok) >+ { >+ goto Cleanup; >+ } >+ >+ OVS_REFCOUNT_DEREF_AND_DESTROY(pPort); >+ >+Cleanup: >+ if (portsLocked) >+ { >+ FXDARRAY_UNLOCK(pPortsArray, &lockState); >+ } >+ >+ return ok; >+} >+ >+VOID DpPort_DestroyNow_Unsafe(OVS_DPPORT* pPort) >+{ >+ OVS_FREE(pPort->dpPortName); >+ >+ /* previously, we 'unset' the nic and port: the hyper-v switch ports >& nics were set to have pPort = NULL >+ ** Now we use numbers instead. Anyway, there's no need to do unset >now, because: >+ ** o) the only reason we keep the mapping between dp port numbers >and hyper-v switch port ids is because we need to find a port id, given a >dp port number (or dp port name) >+ ** o) we need to be able to find a dp port, when knowing a port id, >only when setting a hyper-v switch port name. >+ ** o) any packet is sent out using a dp port number (dp port) >+ ** o) it never happens for a port (hyper-v switch port or dp port) >to be created with the same number as one that had been deleted. >+ */ >+ >+ OVS_FREE(pPort->pOptions); >+ >+ if (((OVS_FXDARRAY_ITEM*)pPort)->pRwLock) >+ { >+ NdisFreeRWLock(((OVS_FXDARRAY_ITEM*)pPort)->pRwLock); >+ } >+ >+ OVS_FREE(pPort); >+} >diff --git a/datapath-windows/ovsext/OpenFlow/DpPort.h >b/datapath-windows/ovsext/OpenFlow/DpPort.h >new file mode 100644 >index 0000000..18f65b6 >--- /dev/null >+++ b/datapath-windows/ovsext/OpenFlow/DpPort.h >@@ -0,0 +1,161 @@ >+/* >+Copyright 2014 Cloudbase Solutions Srl >+ >+Licensed under the Apache License, Version 2.0 (the "License"); >+you may not use this file except in compliance with the License. >+You may obtain a copy of the License at >+ >+http ://www.apache.org/licenses/LICENSE-2.0 >+ >+Unless required by applicable law or agreed to in writing, software >+distributed under the License is distributed on an "AS IS" BASIS, >+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+See the License for the specific language governing permissions and >+limitations under the License. >+*/ >+ >+#pragma once >+ >+#include "precomp.h" >+ >+#include "Core\FixedSizedArray.h" >+ >+#define OVS_LOCAL_PORT_NUMBER ((UINT32)0) >+#define OVS_MAX_PORTS MAXUINT16 >+#define OVS_INVALID_PORT_NUMBER OVS_MAX_PORTS >+ >+#define OVS_TUNNEL_OPTIONS_HAVE_UDP_DST_PORT 0x80 >+ >+typedef struct _OVS_TUNNELING_PORT_OPTIONS OVS_TUNNELING_PORT_OPTIONS; >+typedef struct _OVS_SWITCH_CONTEXT OVS_SWITCH_CONTEXT; >+typedef struct _OVS_DATAPATH OVS_DATAPATH; >+ >+typedef enum >+{ >+ OVS_DPPORT_TYPE_INVALID = 0, >+ >+ //a specific physical port, i.e. one that has a port id (vm port, >external) >+ OVS_DPPORT_TYPE_PHYSICAL = 1, >+ //, internal / management OS >+ OVS_DPPORT_TYPE_MANAG_OS = 2, >+ //PORT type GRE >+ OVS_DPPORT_TYPE_GRE = 3, >+ //PORT type VXLAN >+ OVS_DPPORT_TYPE_VXLAN = 4, >+ >+ //NOTE: not supported yet >+ OVS_DPPORT_TYPE_GENEVE = 6, >+ //same as GRE, except keys are 64-bit >+ //NOTE: not supported yet >+ OVS_DPPORT_TYPE_GRE64 = 104, >+ //NOTE: not supported yet >+ OVS_DPPORT_TYPE_LISP = 105 >+}OVS_DPPORT_TYPE; >+C_ASSERT(sizeof(OVS_DPPORT_TYPE) == sizeof(UINT)); >+ >+typedef struct _OVS_DPPORT_STATS >+{ >+ UINT64 packetsReceived; >+ UINT64 packetsSent; >+ UINT64 bytesReceived; >+ UINT64 bytesSent; >+ UINT64 errorsOnReceive; >+ UINT64 errorsOnSend; >+ UINT64 droppedOnReceive; >+ UINT64 droppedOnSend; >+}OVS_DPPORT_STATS, *POVS_DPPORT_STATS; >+ >+typedef struct _OVS_UPCALL_PORT_IDS >+{ >+ //TODO: we might need to use ref counting for this >+ UINT count; >+ UINT* ids; >+}OVS_UPCALL_PORT_IDS, *POVS_UPCALL_PORT_IDS; >+ >+typedef struct _OVS_DPPORT >+{ >+ OVS_FXDARRAY_ITEM; >+ >+ //port number assigned by OVS (userspace, or computed in driver) >+ UINT16 dpPortNumber; >+ >+ //port name assigned by OVS (userspace, or computed in driver) >+ char* dpPortName; >+ >+ //OpenFlow / datapath port type >+ OVS_DPPORT_TYPE dpPortType; >+ OVS_DPPORT_STATS dpStats; >+ >+ OVS_UPCALL_PORT_IDS upcallPortIds; >+ >+ OVS_TUNNELING_PORT_OPTIONS* pOptions; >+ >+ //NDIS_SWITCH_DEFAULT_PORT_ID (i.e. 0), if not connected >+ NDIS_SWITCH_PORT_ID hvPortId; >+ NDIS_SWITCH_NIC_INDEX hvNicIndex; >+ >+ //if it's the external port of the switch or not >+ BOOLEAN isExternal; >+}OVS_DPPORT; >+ >+#define PORT_LOCK_READ(pPort, pLockState) >NdisAcquireRWLockRead(((OVS_FXDARRAY_ITEM*)pPort)->pRwLock, pLockState, 0) >+#define PORT_LOCK_WRITE(pPort, pLockState) >NdisAcquireRWLockWrite(((OVS_FXDARRAY_ITEM*)pPort)->pRwLock, pLockState, >0) >+#define PORT_UNLOCK(pPort, pLockState) >NdisReleaseRWLock(((OVS_FXDARRAY_ITEM*)pPort)->pRwLock, pLockState) >+#define PORT_UNLOCK_IF(pPort, pLockState, locked) { if ((locked) && >(pPort)) PORT_UNLOCK((pPort), pLockState); } >+ >+typedef struct _OVS_TUNNELING_PORT_OPTIONS >+{ >+ //OVS_TUNNEL_OPTIONS_HAVE_* >+ DWORD optionsFlags; >+ >+ //OVS_TUNNEL_PORT_FLAG_* >+ BE32 tunnelFlags; >+ BE32 destIpv4; >+ BE32 sourceIpv4; >+ BE64 outKey; >+ BE64 inKey; >+ UINT8 tos; >+ UINT8 ttl; >+ >+ UINT16 udpDestPort; >+}OVS_TUNNELING_PORT_OPTIONS; >+ >+//used in a list of "logical" ports: list in which we keep the GRE, all >VXLAN, etc. ports >+typedef struct _OVS_LOGICAL_PORT_ENTRY >+{ >+ LIST_ENTRY listEntry; >+ OVS_DPPORT* pPort; >+}OVS_LOGICAL_PORT_ENTRY; >+ >+typedef struct _OF_PI_IPV4_TUNNEL OF_PI_IPV4_TUNNEL; >+ >+/********************************************************************/ >+ >+OVS_DPPORT* DpPort_Create_Ref(OVS_SWITCH_CONTEXT* pSwitchInfo, _In_opt_ >const char* portName, _In_opt_ const UINT16* pPortNumber, OVS_DPPORT_TYPE >portType); >+UINT16 DpPort_SetHvNicIndexAndPortId(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId, NDIS_SWITCH_NIC_INDEX nicIndex); >+UINT16 DpPort_SetHvPortId(_In_ OVS_DATAPATH* pDatapath, const char* >dpPortName, NDIS_SWITCH_PORT_ID portId); >+ >+OVS_DPPORT* DpPort_FindByName_Ref(OVS_DATAPATH* pDatapath, const char* >dpPortName); >+OVS_DPPORT* DpPort_FindByNumber_Ref(OVS_DATAPATH* pDatapath, UINT16 >portNumber); >+ >+OVS_DPPORT* DpPort_FindById_Unsafe(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId); >+OVS_DPPORT* DpPort_FindById_Ref(OVS_DATAPATH* pDatapath, >NDIS_SWITCH_PORT_ID portId); >+ >+BOOLEAN DpPort_Delete(OVS_DATAPATH* pDatapath, OVS_DPPORT* pDpPort); >+ >+_Ret_maybenull_ >+OVS_DPPORT* DpPort_FindExternal_Ref(OVS_DATAPATH* pDatapath); >+ >+_Ret_maybenull_ >+OVS_DPPORT* DpPort_FindInternal_Ref(OVS_DATAPATH* pDatapath); >+ >+_Ret_maybenull_ >+OVS_DPPORT* DpPort_FindGre_Ref(); >+ >+_Ret_maybenull_ >+OVS_DPPORT* DpPort_FindVxlan_Ref(LE16 udpDestPort); >+ >+BOOLEAN DpPort_InitializeLogicalPorts(); >+VOID DpPort_UninitializeLogicalPorts(); >+ >+VOID DpPort_DestroyNow_Unsafe(OVS_DPPORT* pDpPort); >diff --git a/datapath-windows/ovsext/ovsext.vcxproj >b/datapath-windows/ovsext/ovsext.vcxproj >index ee69327..a42bdc9 100644 >--- a/datapath-windows/ovsext/ovsext.vcxproj >+++ b/datapath-windows/ovsext/ovsext.vcxproj >@@ -81,9 +81,12 @@ > <ClInclude Include="Core\SpookyHash.h" /> > <ClInclude Include="Core\Types.h" /> > <ClInclude Include="Core\Util.h" /> >+ <ClInclude Include="Hyper-V\HvNic.h" /> >+ <ClInclude Include="Hyper-V\HvPort.h" /> > <ClInclude Include="Hyper-V\Oid.h" /> > <ClInclude Include="Hyper-V\Switch.h" /> > <ClInclude Include="OpenFlow\Flow.h" /> >+ <ClInclude Include="OpenFlow\DpPort.h" /> > <ClInclude Include="OpenFlow\PacketParser.h" /> > <ClInclude Include="OpenFlow\Pub.h" /> > <ClInclude Include="OpenFlow\Vport.h" /> >@@ -143,10 +146,13 @@ > <ClCompile Include="Core\Jhash.c" /> > <ClCompile Include="Core\SpookyHash.c" /> > <ClCompile Include="Core\Util.c" /> >+ <ClCompile Include="Hyper-V\HvNic.c" /> >+ <ClCompile Include="Hyper-V\HvPort.c" /> > <ClCompile Include="Hyper-V\Oid.c" /> > <ClCompile Include="Hyper-V\Switch.c" /> > <ClCompile Include="OpenFlow\Actions.c" /> > <ClCompile Include="OpenFlow\Flow.c" /> >+ <ClCompile Include="OpenFlow\DpPort.c" /> > <ClCompile Include="OpenFlow\PacketParser.c" /> > <ClCompile Include="OpenFlow\Vport.c" /> > <ClCompile Include="precompsrc.c"> >diff --git a/datapath-windows/ovsext/ovsext.vcxproj.filters >b/datapath-windows/ovsext/ovsext.vcxproj.filters >index 78d041b..3beed7f 100644 >--- a/datapath-windows/ovsext/ovsext.vcxproj.filters >+++ b/datapath-windows/ovsext/ovsext.vcxproj.filters >@@ -92,6 +92,15 @@ > <ClInclude Include="Core\Core.h"> > <Filter>Core</Filter> > </ClInclude> >+ <ClInclude Include="Hyper-V\HvNic.h"> >+ <Filter>Hyper-V</Filter> >+ </ClInclude> >+ <ClInclude Include="Hyper-V\HvPort.h"> >+ <Filter>Hyper-V</Filter> >+ </ClInclude> >+ <ClInclude Include="OpenFlow\DpPort.h"> >+ <Filter>OpenFlow</Filter> >+ </ClInclude> > </ItemGroup> > <ItemGroup> > <ResourceCompile Include="ovsext.rc" /> >@@ -187,5 +196,14 @@ > <ClCompile Include="Core\FixedSizedArray.c"> > <Filter>Core</Filter> > </ClCompile> >+ <ClCompile Include="Hyper-V\HvNic.c"> >+ <Filter>Hyper-V</Filter> >+ </ClCompile> >+ <ClCompile Include="Hyper-V\HvPort.c"> >+ <Filter>Hyper-V</Filter> >+ </ClCompile> >+ <ClCompile Include="OpenFlow\DpPort.c"> >+ <Filter>OpenFlow</Filter> >+ </ClCompile> > </ItemGroup> > </Project> >\ No newline at end of file >-- >1.8.3.msysgit.0 > > >_______________________________________________ >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=pEkjsHfytvHEWufeZPpgqSO >JMdMjuZPbesVsNhCUc0E%3D%0A&m=rMyshbVzg7JjbsLBmZ63esZiT3wVv3iF4NDNF9c6omE%3 >D%0A&s=6026fe9ec0dd1bf7945ac2ee0864204dc1775baf57e8bc7a85795c61d9b804a7 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev