[ovs-dev] [PATCH 14/15] datapath-windows: Add functionality for dp ports, hv nics, hv ports

Samuel Ghinet sghinet at cloudbasesolutions.com
Wed Aug 6 16:25:06 UTC 2014


Add functionality for dp ports, hv nics, hv ports

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 replacement is to be done in a future commit.

Signed-off-by: Samuel Ghinet <sghinet at cloudbasesolutions.com>
---
 datapath-windows/ovsext/Core/FixedSizedArray.c |   4 +-
 datapath-windows/ovsext/Core/FixedSizedArray.h |   4 +-
 datapath-windows/ovsext/Hyper-V/HvNic.c        | 515 ++++++++++++++++++++
 datapath-windows/ovsext/Hyper-V/HvNic.h        |  66 +++
 datapath-windows/ovsext/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(-)
 create 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/OpenFlow/DpPort.h

diff --git a/datapath-windows/ovsext/Core/FixedSizedArray.c b/datapath-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 @@ OVS_FXDARRAY_ITEM* FxdArray_Find_Ref(const OVS_FIXED_SIZED_ARRAY* pArray, FxdArr
     OVS_FXDARRAY_ITEM* pOutItem = NULL;
     LOCK_STATE_EX lockState;

-    FXARRAY_LOCK_READ(pArray, &lockState);
+    FXDARRAY_LOCK_READ(pArray, &lockState);

     pOutItem = FxdArray_Find_Unsafe(pArray, condition, pCondData);

-    FXARRAY_UNLOCK(pArray, &lockState);
+    FXDARRAY_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 OVS_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* pSwitchContext, _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:
+    //http://msdn.microsoft.com/en-us/library/windows/hardware/hh598215(v=vs.85).aspx
+    //"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->NdisSwitchContext, 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->NdisSwitchContext, 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





More information about the dev mailing list