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

Samuel Ghinet sghinet at cloudbasesolutions.com
Fri Aug 8 13:38:11 UTC 2014


Hello Saurabh,

I think you're right. I should have had a bit of patience :)
This code is mostly taken from our working ovs, so it should be ok - but you're right, it cannot be tested yet, and should be postponed for the future.
Also, the netlink part dealing with vports and packet upcall is a bit tightly coupled with vports, which I wonder how we could integrate together incrementally.

I would like to ask you though, if you had taken a look upon the code, for a future integration of it:
a) do you think it would be ok to put these hyper-v related functionalities in a hyper-v folder? or you think they should better go in the main datapath-win dir?
b) How do you think the function naming looks? Do you think it would be ok to allow such naming in the project?

Thanks!
Sam
________________________________________
From: Saurabh Shah [ssaurabh at vmware.com]
Sent: Wednesday, August 06, 2014 10:29 PM
To: Samuel Ghinet; dev at openvswitch.org
Subject: Re: [ovs-dev] [PATCH 14/15] datapath-windows: Add functionality for dp ports, hv nics, hv ports

>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 <sghinet at 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 at 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




More information about the dev mailing list