On 15 December 2016 at 11:39, Alin Serdean <aserd...@cloudbasesolutions.com>
wrote:

>
> This patch adds multiple internal ports support to the windows datapath.
> All tunnels types have been updated to accommodate this new functionality.
>
> Signed-off-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com>
> Co-authored-by: Sorin Vinturis <svintu...@cloudbasesolutions.com>
>

This needs a Signed-off-by from Sorin


> Acked-by: Paul Boca <pb...@cloudbasesolutions.com>
>

I get a conflict with this patch. Please rebase.


> ---
> v7: Rebase
> v6: Rebase
> v5: Rebase
> v4: Address comments (fix aligment, switch goto labels)
> v3: Add acked
> v2: Rebase
> ---
>  datapath-windows/ovsext/Actions.c  |  42 +-
>  datapath-windows/ovsext/Geneve.c   |   7 +-
>  datapath-windows/ovsext/Geneve.h   |   6 +-
>  datapath-windows/ovsext/Gre.c      |   7 +-
>  datapath-windows/ovsext/Gre.h      |   8 +-
>  datapath-windows/ovsext/IpHelper.c | 919 +++++++++++++++++++++++++++---
> -------
>  datapath-windows/ovsext/IpHelper.h |  22 +-
>  datapath-windows/ovsext/Stt.c      |   7 +-
>  datapath-windows/ovsext/Stt.h      |   7 +-
>  datapath-windows/ovsext/Switch.h   |   9 +-
>  datapath-windows/ovsext/Vport.c    | 131 +++---
>  datapath-windows/ovsext/Vport.h    | 104 ++---
>  datapath-windows/ovsext/Vxlan.c    |  10 +-
>  datapath-windows/ovsext/Vxlan.h    |  10 +-
>  14 files changed, 864 insertions(+), 425 deletions(-)
>
> diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/
> Actions.c
> index 9a58fbd..8ba977f 100644
> --- a/datapath-windows/ovsext/Actions.c
> +++ b/datapath-windows/ovsext/Actions.c
> @@ -301,7 +301,6 @@ OvsDetectTunnelPkt(OvsForwardingContext *ovsFwdCtx,
>              return TRUE;
>          }
>      } else if (OvsIsTunnelVportType(dstVport->ovsType)) {
> -        ASSERT(ovsFwdCtx->tunnelTxNic == NULL);
>          ASSERT(ovsFwdCtx->tunnelRxNic == NULL);
>
>          /*
> @@ -322,7 +321,7 @@ OvsDetectTunnelPkt(OvsForwardingContext *ovsFwdCtx,
>
>              if (!vport ||
>                  (vport->ovsType != OVS_VPORT_TYPE_NETDEV &&
> -                 !OvsIsBridgeInternalVport(vport) &&
> +                 vport->ovsType != OVS_VPORT_TYPE_INTERNAL &&
>                   !OvsIsTunnelVportType(vport->ovsType))) {
>                  ovsFwdCtx->tunKey.dst = 0;
>              }
> @@ -403,10 +402,6 @@ OvsAddPorts(OvsForwardingContext *ovsFwdCtx,
>      vport->stats.txBytes +=
>          NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(
> ovsFwdCtx->curNbl));
>
> -    if (OvsIsBridgeInternalVport(vport)) {
> -        return NDIS_STATUS_SUCCESS;
> -    }
> -
>      if (OvsDetectTunnelPkt(ovsFwdCtx, vport, flowKey)) {
>          return NDIS_STATUS_SUCCESS;
>      }
> @@ -668,41 +663,36 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx)
>       * Setup the source port to be the internal port to as to facilitate
> the
>       * second OvsLookupFlow.
>       */
> -    if (ovsFwdCtx->switchContext->internalVport == NULL ||
> +    if (ovsFwdCtx->switchContext->countInternalVports <= 0 ||
>          ovsFwdCtx->switchContext->virtualExternalVport == NULL) {
>          OvsClearTunTxCtx(ovsFwdCtx);
>          OvsCompleteNBLForwardingCtx(ovsFwdCtx,
>              L"OVS-Dropped since either internal or external port is
> absent");
>          return NDIS_STATUS_FAILURE;
>      }
> -    ovsFwdCtx->srcVportNo =
> -        ((POVS_VPORT_ENTRY)ovsFwdCtx->switchContext->internalVport)-
> >portNo;
>
> -    ovsFwdCtx->fwdDetail->SourcePortId = ovsFwdCtx->switchContext->
> internalPortId;
> -    ovsFwdCtx->fwdDetail->SourceNicIndex =
> -        ((POVS_VPORT_ENTRY)ovsFwdCtx->switchContext->internalVport)-
> >nicIndex;
> -
> -    /* Do the encap. Encap function does not consume the NBL. */
> +    OVS_FWD_INFO switchFwdInfo = { 0 };
> +    /* Apply the encapsulation. The encapsulation will not consume the
> NBL. */
>      switch(ovsFwdCtx->tunnelTxNic->ovsType) {
>      case OVS_VPORT_TYPE_GRE:
>          status = OvsEncapGre(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
>                               &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
> -                             &ovsFwdCtx->layers, &newNbl);
> +                             &ovsFwdCtx->layers, &newNbl, &switchFwdInfo);
>          break;
>      case OVS_VPORT_TYPE_VXLAN:
>          status = OvsEncapVxlan(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
>                                 &ovsFwdCtx->tunKey,
> ovsFwdCtx->switchContext,
> -                               &ovsFwdCtx->layers, &newNbl);
> +                               &ovsFwdCtx->layers, &newNbl,
> &switchFwdInfo);
>          break;
>      case OVS_VPORT_TYPE_STT:
>          status = OvsEncapStt(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
>                               &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
> -                             &ovsFwdCtx->layers, &newNbl);
> +                             &ovsFwdCtx->layers, &newNbl, &switchFwdInfo);
>          break;
>      case OVS_VPORT_TYPE_GENEVE:
>          status = OvsEncapGeneve(ovsFwdCtx->tunnelTxNic,
> ovsFwdCtx->curNbl,
>                                  &ovsFwdCtx->tunKey,
> ovsFwdCtx->switchContext,
> -                                &ovsFwdCtx->layers, &newNbl);
> +                                &ovsFwdCtx->layers, &newNbl,
> &switchFwdInfo);
>          break;
>      default:
>          ASSERT(! "Tx: Unhandled tunnel type");
> @@ -711,8 +701,11 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx)
>      /* Reset the tunnel context so that it doesn't get used after this
> point. */
>      OvsClearTunTxCtx(ovsFwdCtx);
>
> -    if (status == NDIS_STATUS_SUCCESS) {
> +    if (status == NDIS_STATUS_SUCCESS && switchFwdInfo.vport != NULL) {
>          ASSERT(newNbl);
> +        ovsFwdCtx->srcVportNo = switchFwdInfo.vport->portNo;
> +        ovsFwdCtx->fwdDetail->SourcePortId = switchFwdInfo.vport->portId;
> +        ovsFwdCtx->fwdDetail->SourceNicIndex =
> switchFwdInfo.vport->nicIndex;
>          OvsCompleteNBLForwardingCtx(ovsFwdCtx,
>                                      L"Complete after cloning NBL for
> encapsulation");
>          ovsFwdCtx->curNbl = newNbl;
> @@ -720,7 +713,7 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx)
>          ASSERT(ovsFwdCtx->curNbl == NULL);
>      } else {
>          /*
> -        * XXX: Temporary freeing of the packet until we register a
> +         * XXX: Temporary freeing of the packet until we register a
>           * callback to IP helper.
>           */
>          OvsCompleteNBLForwardingCtx(ovsFwdCtx,
> @@ -956,12 +949,11 @@ dropit:
>  VOID
>  OvsLookupFlowOutput(POVS_SWITCH_CONTEXT switchContext,
>                      VOID *compList,
> -                    PNET_BUFFER_LIST curNbl)
> +                    PNET_BUFFER_LIST curNbl,
> +                    POVS_VPORT_ENTRY internalVport)
>  {
>      NDIS_STATUS status;
>      OvsForwardingContext ovsFwdCtx;
> -    POVS_VPORT_ENTRY internalVport =
> -        (POVS_VPORT_ENTRY)switchContext->internalVport;
>
>      /* XXX: make sure comp list was not a stack variable previously. */
>      OvsCompletionList *completionList = (OvsCompletionList *)compList;
> @@ -971,7 +963,7 @@ OvsLookupFlowOutput(POVS_SWITCH_CONTEXT switchContext,
>       * It could, but will we get this callback from IP helper in that
> case. Need
>       * to check.
>       */
> -    ASSERT(switchContext->internalVport);
> +    ASSERT(switchContext->countInternalVports > 0);
>      status = OvsInitForwardingCtx(&ovsFwdCtx, switchContext, curNbl,
>                                    internalVport->portNo, 0,
>                                    NET_BUFFER_LIST_SWITCH_
> FORWARDING_DETAIL(curNbl),
> @@ -1061,7 +1053,7 @@ OvsOutputBeforeSetAction(OvsForwardingContext
> *ovsFwdCtx)
>   * ------------------------------------------------------------
> --------------
>   * OvsPopFieldInPacketBuf --
>   *     Function to pop a specified field of length 'shiftLength' located
> at
> - *     'shiftOffset' from the ethernet header. The data on the left of the
> + *     'shiftOffset' from the Ethernet header. The data on the left of the
>   *     'shiftOffset' is right shifted.
>   *
>   *     Returns a pointer to the new start in 'bufferData'.
> diff --git a/datapath-windows/ovsext/Geneve.c b/datapath-windows/ovsext/
> Geneve.c
> index efdf9f7..d38a656 100644
> --- a/datapath-windows/ovsext/Geneve.c
> +++ b/datapath-windows/ovsext/Geneve.c
> @@ -72,7 +72,8 @@ NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
>                             OvsIPv4TunnelKey *tunKey,
>                             POVS_SWITCH_CONTEXT switchContext,
>                             POVS_PACKET_HDR_INFO layers,
> -                           PNET_BUFFER_LIST *newNbl)
> +                           PNET_BUFFER_LIST *newNbl,
> +                           POVS_FWD_INFO switchFwdInfo)
>  {
>      NTSTATUS status;
>      OVS_FWD_INFO fwdInfo;
> @@ -90,7 +91,7 @@ NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
>      ULONG mss = 0;
>      NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
>
> -    status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
> +    status = OvsLookupIPFwdInfo(tunKey->src, tunKey->dst, &fwdInfo);
>      if (status != STATUS_SUCCESS) {
>          OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL);
>          // return NDIS_STATUS_PENDING;
> @@ -104,6 +105,8 @@ NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
>          return NDIS_STATUS_FAILURE;
>      }
>
> +    RtlCopyMemory(switchFwdInfo->value, fwdInfo.value, sizeof
> fwdInfo.value);
> +
>      curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
>      packetLength = NET_BUFFER_DATA_LENGTH(curNb);
>
> diff --git a/datapath-windows/ovsext/Geneve.h b/datapath-windows/ovsext/
> Geneve.h
> index 057f80a..be8a834 100644
> --- a/datapath-windows/ovsext/Geneve.h
> +++ b/datapath-windows/ovsext/Geneve.h
> @@ -19,6 +19,9 @@
>  #define __GENEVE_H_ 1
>
>  #include "NetProto.h"
> +
> +typedef union _OVS_FWD_INFO *POVS_FWD_INFO;
> +
>  typedef struct _OVS_GENEVE_VPORT {
>      UINT16 dstPort;
>      UINT64 filterID;
> @@ -87,7 +90,8 @@ NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
>                             OvsIPv4TunnelKey *tunKey,
>                             POVS_SWITCH_CONTEXT switchContext,
>                             POVS_PACKET_HDR_INFO layers,
> -                           PNET_BUFFER_LIST *newNbl);
> +                           PNET_BUFFER_LIST *newNbl,
> +                           POVS_FWD_INFO switchFwdInfo);
>
>  NDIS_STATUS OvsDecapGeneve(POVS_SWITCH_CONTEXT switchContext,
>                             PNET_BUFFER_LIST curNbl,
> diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
> index 7d6c0a2..c5da064 100644
> --- a/datapath-windows/ovsext/Gre.c
> +++ b/datapath-windows/ovsext/Gre.c
> @@ -96,17 +96,20 @@ OvsEncapGre(POVS_VPORT_ENTRY vport,
>              OvsIPv4TunnelKey *tunKey,
>              POVS_SWITCH_CONTEXT switchContext,
>              POVS_PACKET_HDR_INFO layers,
> -            PNET_BUFFER_LIST *newNbl)
> +            PNET_BUFFER_LIST *newNbl,
> +            POVS_FWD_INFO switchFwdInfo)
>  {
>      OVS_FWD_INFO fwdInfo;
>      NDIS_STATUS status;
>
> -    status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
> +    status = OvsLookupIPFwdInfo(tunKey->src, tunKey->dst, &fwdInfo);
>      if (status != STATUS_SUCCESS) {
>          OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL);
>          return NDIS_STATUS_FAILURE;
>      }
>
> +    RtlCopyMemory(switchFwdInfo->value, fwdInfo.value, sizeof
> fwdInfo.value);
> +
>      status = OvsDoEncapGre(vport, curNbl, tunKey, &fwdInfo, layers,
>                             switchContext, newNbl);
>      return status;
> diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h
> index 7e20ced..c45df8f 100644
> --- a/datapath-windows/ovsext/Gre.h
> +++ b/datapath-windows/ovsext/Gre.h
> @@ -17,8 +17,11 @@
>  #ifndef __GRE_H_
>  #define __GRE_H_ 1
>
> -#include "NetProto.h"
>  #include "Flow.h"
> +#include "IpHelper.h"
> +#include "NetProto.h"
> +
> +typedef union _OVS_FWD_INFO *POVS_FWD_INFO;
>
>  typedef struct _OVS_GRE_VPORT {
>      UINT64 ipId;
> @@ -66,7 +69,8 @@ NDIS_STATUS OvsEncapGre(POVS_VPORT_ENTRY vport,
>                          OvsIPv4TunnelKey *tunKey,
>                          POVS_SWITCH_CONTEXT switchContext,
>                          POVS_PACKET_HDR_INFO layers,
> -                        PNET_BUFFER_LIST *newNbl);
> +                        PNET_BUFFER_LIST *newNbl,
> +                        POVS_FWD_INFO switchFwdInfo);
>
>  NDIS_STATUS OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
>                          PNET_BUFFER_LIST curNbl,
> diff --git a/datapath-windows/ovsext/IpHelper.c b/datapath-windows/ovsext/
> IpHelper.c
> index 636cf95..0220572 100644
> --- a/datapath-windows/ovsext/IpHelper.c
> +++ b/datapath-windows/ovsext/IpHelper.c
> @@ -19,6 +19,8 @@
>  #include "Switch.h"
>  #include "Jhash.h"
>
> +extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
> +
>  #ifdef OVS_DBG_MOD
>  #undef OVS_DBG_MOD
>  #endif
> @@ -26,28 +28,44 @@
>  #include "Debug.h"
>
>  /*
> - * Fow now, we assume only one internal adapter
> + * IpHelper supports multiple internal adapters.
>   */
>
>  KSTART_ROUTINE             OvsStartIpHelper;
>
> +/* Contains the entries of internal adapter objects. */
> +static LIST_ENTRY          ovsInstanceList;
> +
> +/* Passive-level lock used to protect the internal adapter object list. */
> +static ERESOURCE           ovsInstanceListLock;
>
>  /*
> + * This structure is used to define each adapter instance.
> + *
> + * Note:
>   * Only when the internal IP is configured and virtual
>   * internal port is connected, the IP helper request can be
>   * queued.
> + *
> + * We only keep internal IP for reference, it will not be used for
> determining
> + * SRC IP of the Tunnel.
> + *
> + * The lock must not raise the IRQL higher than PASSIVE_LEVEL in order
> for the
> + * route manipulation functions, i.e. GetBestRoute, to work.
>   */
> -static BOOLEAN             ovsInternalIPConfigured;
> -static BOOLEAN             ovsInternalAdapterUp;
> -static GUID                ovsInternalNetCfgId;
> -static MIB_IF_ROW2         ovsInternalRow;
> -static MIB_IPINTERFACE_ROW ovsInternalIPRow;
> -
> -/* we only keep one internal IP for reference, it will not be used for
> - * determining SRC IP of Tunnel
> - */
> -static UINT32               ovsInternalIP;
> +typedef struct _OVS_IPHELPER_INSTANCE
> +{
> +    LIST_ENTRY          link;
> +
> +    BOOLEAN             isIpConfigured;
> +    UINT32              portNo;
> +    GUID                netCfgId;
> +    MIB_IF_ROW2         internalRow;
> +    MIB_IPINTERFACE_ROW internalIPRow;
> +    UINT32              ipAddress;
>
> +    ERESOURCE           lock;
> +} OVS_IPHELPER_INSTANCE, *POVS_IPHELPER_INSTANCE;
>
>  /*
>   * FWD_ENTRY -------->  IPFORWARD_ENTRY
> @@ -82,9 +100,22 @@ static OVS_IP_HELPER_THREAD_CONTEXT
> ovsIpHelperThreadContext;
>  static POVS_IPFORWARD_ENTRY OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX
> prefix);
>  static VOID OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf);
>  static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);
> +static VOID OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo);
>  static VOID OvsCleanupIpHelperRequestList(VOID);
>  static VOID OvsCleanupFwdTable(VOID);
>  static VOID OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn);
> +static POVS_IPHELPER_INSTANCE OvsIpHelperAllocateInstance(
> +                                               POVS_IP_HELPER_REQUEST
> request);
> +static VOID OvsIpHelperDeleteInstance(POVS_IPHELPER_INSTANCE instance);
> +
> +
> +static VOID
> +OvsDumpMessageWithGuid(char* message, GUID guid)
> +{
> +    OVS_LOG_INFO(message, guid.Data1, guid.Data2, guid.Data3,
> +                 *(UINT16 *)guid.Data4, guid.Data4[2], guid.Data4[3],
> +                 guid.Data4[4], guid.Data4[5], guid.Data4[6],
> guid.Data4[7]);
> +}
>
>  static VOID
>  OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
> @@ -94,17 +125,9 @@ OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
>                   ifRow->InterfaceLuid.Info.IfType);
>      OVS_LOG_INFO("InterfaceIndex: %d", ifRow->InterfaceIndex);
>
> -    OVS_LOG_INFO("Interface GUID: %08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> -                 ifRow->InterfaceGuid.Data1,
> -                 ifRow->InterfaceGuid.Data2,
> -                 ifRow->InterfaceGuid.Data3,
> -                 *(UINT16 *)ifRow->InterfaceGuid.Data4,
> -                 ifRow->InterfaceGuid.Data4[2],
> -                 ifRow->InterfaceGuid.Data4[3],
> -                 ifRow->InterfaceGuid.Data4[4],
> -                 ifRow->InterfaceGuid.Data4[5],
> -                 ifRow->InterfaceGuid.Data4[6],
> -                 ifRow->InterfaceGuid.Data4[7]);
> +    OvsDumpMessageWithGuid("Interface GUID: "
> +                           "%08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> +                           ifRow->InterfaceGuid);
>      OVS_LOG_INFO("Perm MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
>                   ifRow->PermanentPhysicalAddress[0],
>                   ifRow->PermanentPhysicalAddress[1],
> @@ -114,7 +137,6 @@ OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
>                   ifRow->PermanentPhysicalAddress[5]);
>  }
>
> -
>  static VOID
>  OvsDumpIfTable(PMIB_IF_TABLE2 ifTable)
>  {
> @@ -325,30 +347,72 @@ OvsDumpRoute(const SOCKADDR_INET *sourceAddress,
>
>
>  NTSTATUS
> -OvsGetRoute(NET_LUID interfaceLuid,
> -            const SOCKADDR_INET *destinationAddress,
> +OvsGetRoute(SOCKADDR_INET *destinationAddress,
>              PMIB_IPFORWARD_ROW2 route,
> -            SOCKADDR_INET *sourceAddress)
> +            SOCKADDR_INET *sourceAddress,
> +            POVS_IPHELPER_INSTANCE *instance,
> +            POVS_VPORT_ENTRY* vport,
> +            UINT32 srcIp)
>  {
> -    NTSTATUS status;
> +    NTSTATUS status = STATUS_NETWORK_UNREACHABLE;
> +    NTSTATUS result = STATUS_SUCCESS;
> +    PLIST_ENTRY head, link, next;
> +    ULONG minMetric = MAXULONG;
>
>      if (destinationAddress == NULL || route == NULL) {
>          return STATUS_INVALID_PARAMETER;
>      }
>
> -    status = GetBestRoute2(&interfaceLuid, 0,
> -                           NULL, destinationAddress,
> -                           0, route, sourceAddress);
> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +    head = &(ovsInstanceList);
> +    LIST_FORALL_SAFE(head, link, next) {
> +        SOCKADDR_INET crtSrcAddr = { 0 };
> +        MIB_IPFORWARD_ROW2 crtRoute = { 0 };
> +        POVS_IPHELPER_INSTANCE crtInstance = NULL;
> +        WCHAR interfaceName[IF_MAX_STRING_SIZE] = { 0 };
>
> -    if (status != STATUS_SUCCESS) {
> -        UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
> -        OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
> -                     ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> -                     (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
> status);
> -        return status;
> +        crtInstance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE,
> link);
> +
> +        ExAcquireResourceExclusiveLite(&crtInstance->lock, TRUE);
> +        result = GetBestRoute2(&crtInstance->internalRow.InterfaceLuid,
> 0,
> +                               NULL, destinationAddress, 0, &crtRoute,
> +                               &crtSrcAddr);
> +
> +        if (result != STATUS_SUCCESS) {
> +            ExReleaseResourceLite(&crtInstance->lock);
> +            continue;
> +        }
> +
> +        if (minMetric > crtRoute.Metric &&
> +            (!srcIp || srcIp == crtSrcAddr.Ipv4.sin_addr.S_un.S_addr)) {
> +            status = STATUS_SUCCESS;
> +            size_t len = 0;
> +            minMetric = crtRoute.Metric;
> +            LOCK_STATE_EX lockState;
> +
> +            RtlCopyMemory(sourceAddress, &crtSrcAddr,
> sizeof(*sourceAddress));
> +            RtlCopyMemory(route, &crtRoute, sizeof(*route));
> +            *instance = crtInstance;
> +
> +            ConvertInterfaceLuidToAlias(&crtInstance->internalRow.
> InterfaceLuid,
> +                                        interfaceName, IF_MAX_STRING_SIZE
> + 1);
> +            RtlStringCbLengthW(interfaceName, IF_MAX_STRING_SIZE, &len);
> +
> +            if (gOvsSwitchContext != NULL) {
> +                NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock,
> +                                      &lockState, 0);
> +                *vport = OvsFindVportByHvNameW(gOvsSwitchContext,
> +                                               interfaceName,
> +                                               len);
> +                NdisReleaseRWLock(gOvsSwitchContext->dispatchLock,
> &lockState);
> +            }
> +        }
> +        ExReleaseResourceLite(&crtInstance->lock);
>      }
> +    ExReleaseResourceLite(&ovsInstanceListLock);
>
>      OvsDumpRoute(sourceAddress, destinationAddress, route);
> +
>      return status;
>  }
>
> @@ -358,8 +422,8 @@ OvsDumpIPNeigh(PMIB_IPNET_ROW2 ipNeigh)
>      UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
>
>      OVS_LOG_INFO("Neigh: %d.%d.%d.%d",
> -                     ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> -                     (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
> +                 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> +                 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
>      OVS_LOG_INFO("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
>                   ipNeigh->PhysicalAddress[0],
>                   ipNeigh->PhysicalAddress[1],
> @@ -421,7 +485,8 @@ OvsResolveIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
>
>
>  NTSTATUS
> -OvsGetOrResolveIPNeigh(UINT32 ipAddr,
> +OvsGetOrResolveIPNeigh(MIB_IF_ROW2 ipRow,
> +                       UINT32 ipAddr,
>                         PMIB_IPNET_ROW2 ipNeigh)
>  {
>      NTSTATUS status;
> @@ -429,8 +494,8 @@ OvsGetOrResolveIPNeigh(UINT32 ipAddr,
>      ASSERT(ipNeigh);
>
>      RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
> -    ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
> -    ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
> +    ipNeigh->InterfaceLuid.Value = ipRow.InterfaceLuid.Value;
> +    ipNeigh->InterfaceIndex = ipRow.InterfaceIndex;
>      ipNeigh->Address.si_family = AF_INET;
>      ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
>
> @@ -438,8 +503,8 @@ OvsGetOrResolveIPNeigh(UINT32 ipAddr,
>
>      if (status != STATUS_SUCCESS) {
>          RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
> -        ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.
> Value;
> -        ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
> +        ipNeigh->InterfaceLuid.Value = ipRow.InterfaceLuid.Value;
> +        ipNeigh->InterfaceIndex = ipRow.InterfaceIndex;
>          ipNeigh->Address.si_family = AF_INET;
>          ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
>          status = OvsResolveIPNeighEntry(ipNeigh);
> @@ -447,57 +512,225 @@ OvsGetOrResolveIPNeigh(UINT32 ipAddr,
>      return status;
>  }
>
> +static __inline BOOLEAN
> +OvsCheckInstanceRow(PMIB_IF_ROW2 instanceRow,
> +                    PNET_LUID netLuid,
> +                    NET_IFINDEX ifIndex)
> +{
> +    return (instanceRow->InterfaceLuid.Info.NetLuidIndex ==
> +            netLuid->Info.NetLuidIndex &&
> +            instanceRow->InterfaceLuid.Info.IfType ==
> +            netLuid->Info.IfType &&
> +            instanceRow->InterfaceIndex ==
> +            ifIndex);
> +}
>
>  static VOID
> -OvsChangeCallbackIpInterface(PVOID context,
> -                             PMIB_IPINTERFACE_ROW ipRow,
> -                             MIB_NOTIFICATION_TYPE notificationType)
> +OvsUpdateIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
>  {
> -    UNREFERENCED_PARAMETER(context);
> -    switch (notificationType) {
> -    case MibParameterNotification:
> -    case MibAddInstance:
> -        if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
> -            ipRow->InterfaceLuid.Info.IfType ==
> -            ovsInternalRow.InterfaceLuid.Info.IfType &&
> -            ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
> +    PLIST_ENTRY head, link, next;
> +
> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +    head = &(ovsInstanceList);
> +    LIST_FORALL_SAFE(head, link, next) {
> +        POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +        instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
> +
> +        ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +        if (OvsCheckInstanceRow(&instance->internalRow,
> +                                &ipRow->InterfaceLuid,
> +                                ipRow->InterfaceIndex)) {
> +
>              /*
>               * Update the IP Interface Row
>               */
> -            NdisAcquireSpinLock(&ovsIpHelperLock);
> -            RtlCopyMemory(&ovsInternalIPRow, ipRow,
> -                          sizeof (PMIB_IPINTERFACE_ROW));
> -            ovsInternalIPConfigured = TRUE;
> -            NdisReleaseSpinLock(&ovsIpHelperLock);
> +            RtlCopyMemory(&instance->internalIPRow, ipRow,
> +                          sizeof(PMIB_IPINTERFACE_ROW));
> +            instance->isIpConfigured = TRUE;
> +
> +            OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is
> %s",
> +                         ipRow->InterfaceLuid.Info.NetLuidIndex,
> +                         ipRow->InterfaceLuid.Info.IfType,
> +                         "modified");
> +
> +            ExReleaseResourceLite(&instance->lock);
> +            break;
>          }
> -        OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",
> -                     ipRow->InterfaceLuid.Info.NetLuidIndex,
> -                     ipRow->InterfaceLuid.Info.IfType,
> -                     notificationType == MibAddInstance ? "added" :
> "modified");
> -        break;
> -    case MibDeleteInstance:
> -        OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d,
> deleted",
> -                     ipRow->InterfaceLuid.Info.NetLuidIndex,
> -                     ipRow->InterfaceLuid.Info.IfType);
> -        if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
> -            ipRow->InterfaceLuid.Info.IfType ==
> -            ovsInternalRow.InterfaceLuid.Info.IfType &&
> -            ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
> +        ExReleaseResourceLite(&instance->lock);
> +    }
> +    ExReleaseResourceLite(&ovsInstanceListLock);
>
> -            NdisAcquireSpinLock(&ovsIpHelperLock);
> -            ovsInternalIPConfigured = FALSE;
> -            NdisReleaseSpinLock(&ovsIpHelperLock);
> +    return;
> +}
> +
> +static VOID
> +OvsAddIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
> +{
> +    PLIST_ENTRY head, link, next;
> +    BOOLEAN found = FALSE;
> +
> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +    head = &(ovsInstanceList);
> +    LIST_FORALL_SAFE(head, link, next) {
> +        POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +        instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
> +
> +        ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +        if (OvsCheckInstanceRow(&instance->internalRow,
> &ipRow->InterfaceLuid,
> +                                ipRow->InterfaceIndex)) {
> +
> +            instance->isIpConfigured = FALSE;
> +            ExReleaseResourceLite(&instance->lock);
> +
> +            found = TRUE;
> +
> +            break;
> +        }
> +        ExReleaseResourceLite(&instance->lock);
> +    }
> +    ExReleaseResourceLite(&ovsInstanceListLock);
>
> -            OvsCleanupIpHelperRequestList();
> +    if (found != TRUE) {
> +        NTSTATUS status;
> +        POVS_IPHELPER_INSTANCE instance = NULL;
> +        MIB_UNICASTIPADDRESS_ROW ipEntry;
> +        BOOLEAN error = TRUE;
> +        LOCK_STATE_EX lockState;
>
> -            OvsCleanupFwdTable();
> +        instance = (POVS_IPHELPER_INSTANCE)OvsAllocateMemoryWithTag(
> +            sizeof(*instance), OVS_IPHELPER_POOL_TAG);
> +        if (instance == NULL) {
> +            goto error;
> +        }
> +        RtlZeroMemory(instance, sizeof(*instance));
> +
> +        InitializeListHead(&instance->link);
> +        ExInitializeResourceLite(&instance->lock);
> +        WCHAR interfaceName[IF_MAX_STRING_SIZE] = { 0 };
> +        status = ConvertInterfaceLuidToAlias(&ipRow->InterfaceLuid,
> +                                             interfaceName,
> +                                             IF_MAX_STRING_SIZE + 1);
> +        if (gOvsSwitchContext == NULL) {
> +            goto error;
> +        }
> +        NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock,
> &lockState, 0);
> +        POVS_VPORT_ENTRY vport = OvsFindVportByHvNameW(gOvsSwitchContext,
> +                                                       interfaceName,
> +                                                       sizeof(WCHAR) *
> +
>  wcslen(interfaceName));
> +
> +        if (vport != NULL) {
> +            RtlCopyMemory(&instance->netCfgId,
> +                          &vport->netCfgInstanceId,
> +                          sizeof(instance->netCfgId));
> +            instance->portNo = vport->portNo;
> +        }
> +        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
> +        RtlZeroMemory(&instance->internalRow, sizeof(MIB_IF_ROW2));
> +        RtlZeroMemory(&instance->internalIPRow,
> sizeof(MIB_IPINTERFACE_ROW));
> +        status = OvsGetIfEntry(&instance->netCfgId,
> +                               &instance->internalRow);
> +
> +        if (status != STATUS_SUCCESS) {
> +            OvsDumpMessageWithGuid("Fail to get IF entry for internal
> port with GUID"
> +                                   "  %08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> +                                   instance->netCfgId);
> +            goto error;
>          }
>
> +        status = OvsGetIPInterfaceEntry(instance->internalRow.
> InterfaceLuid,
> +                                        &instance->internalIPRow);
> +
> +        if (status == STATUS_SUCCESS) {
> +            instance->isIpConfigured = TRUE;
> +        } else {
> +            goto error;
> +        }
> +
> +        status = OvsGetIPEntry(instance->internalRow.InterfaceLuid,
> &ipEntry);
> +        if (status != STATUS_SUCCESS) {
> +            OvsDumpMessageWithGuid("Failed to get IP entry for internal
> port with GUID"
> +                                   " %08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> +                                   instance->netCfgId);
> +        }
> +
> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +        InsertHeadList(&ovsInstanceList, &instance->link);
> +        ExReleaseResourceLite(&ovsInstanceListLock);
> +
> +        error = FALSE;
> +
> +error:
> +        if (error) {
> +            OvsIpHelperDeleteInstance(instance);
> +        }
> +    }
> +
> +    return;
> +}
> +
> +static VOID
> +OvsRemoveIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
> +{
> +    PLIST_ENTRY head, link, next;
> +
> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +    head = &(ovsInstanceList);
> +    LIST_FORALL_SAFE(head, link, next) {
> +        POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +        instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
> +
> +        ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +        if (OvsCheckInstanceRow(&instance->internalRow,
> &ipRow->InterfaceLuid,
> +                                ipRow->InterfaceIndex)) {
> +
> +            instance->isIpConfigured = FALSE;
> +            RemoveEntryList(&instance->link);
> +
> +            ExReleaseResourceLite(&instance->lock);
> +            OvsIpHelperDeleteInstance(instance);
> +
> +            OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is
> "\
> +                         "deleted",
> +                         ipRow->InterfaceLuid.Info.NetLuidIndex,
> +                         ipRow->InterfaceLuid.Info.IfType);
> +
> +            break;
> +        }
> +        ExReleaseResourceLite(&instance->lock);
> +    }
> +    ExReleaseResourceLite(&ovsInstanceListLock);
> +
> +    if (IsListEmpty(&ovsInstanceList)) {
> +        OvsCleanupIpHelperRequestList();
> +        OvsCleanupFwdTable();
> +    }
> +
> +    return;
> +}
> +
> +static VOID
> +OvsChangeCallbackIpInterface(PVOID context,
> +                             PMIB_IPINTERFACE_ROW ipRow,
> +                             MIB_NOTIFICATION_TYPE notificationType)
> +{
> +    UNREFERENCED_PARAMETER(context);
> +    switch (notificationType) {
> +    case MibParameterNotification:
> +        OvsUpdateIpInterfaceNotification(ipRow);
> +        break;
> +    case MibAddInstance:
> +        OvsAddIpInterfaceNotification(ipRow);
> +        break;
> +
> +    case MibDeleteInstance:
> +        OvsRemoveIpInterfaceNotification(ipRow);
>          break;
>      case MibInitialNotification:
> -        OVS_LOG_INFO("Get Initial notification for IP Interface change.");
> +        OVS_LOG_INFO("Got Initial notification for IP Interface change.");
>      default:
>          return;
>      }
> @@ -529,10 +762,21 @@ OvsChangeCallbackIpRoute(PVOID context,
>
>      case MibParameterNotification:
>      case MibDeleteInstance:
> +    {
>          ASSERT(ipRoute);
>          ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
>          nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
>
> +        POVS_IPFORWARD_ENTRY ipf;
> +        LOCK_STATE_EX lockState;
> +
> +        NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
> +        ipf = OvsLookupIPForwardEntry(&ipRoute->DestinationPrefix);
> +        if (ipf != NULL) {
> +            OvsRemoveIPForwardEntry(ipf);
> +        }
> +        NdisReleaseRWLock(ovsTableLock, &lockState);
> +
>          OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d %s.",
>                       ipAddr & 0xff, (ipAddr >> 8) & 0xff,
>                       (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
> @@ -541,24 +785,8 @@ OvsChangeCallbackIpRoute(PVOID context,
>                       (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
>                       notificationType == MibDeleteInstance ? "deleted" :
>                       "modified");
> -
> -        if (ipRoute->InterfaceLuid.Info.NetLuidIndex ==
> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
> -            ipRoute->InterfaceLuid.Info.IfType ==
> -            ovsInternalRow.InterfaceLuid.Info.IfType &&
> -            ipRoute->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
> -
> -            POVS_IPFORWARD_ENTRY ipf;
> -            LOCK_STATE_EX lockState;
> -
> -            NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
> -            ipf = OvsLookupIPForwardEntry(&ipRoute->DestinationPrefix);
> -            if (ipf != NULL) {
> -                OvsRemoveIPForwardEntry(ipf);
> -            }
> -            NdisReleaseRWLock(ovsTableLock, &lockState);
> -        }
>          break;
> +    }
>
>      case MibInitialNotification:
>          OVS_LOG_INFO("Get Initial notification for IP Route change.");
> @@ -579,40 +807,85 @@ OvsChangeCallbackUnicastIpAddress(PVOID context,
>      switch (notificationType) {
>      case MibParameterNotification:
>      case MibAddInstance:
> +    {
> +        PLIST_ENTRY head, link, next;
> +
>          ASSERT(unicastRow);
>          ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
> -        if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
> -            unicastRow->InterfaceLuid.Info.IfType ==
> -            ovsInternalRow.InterfaceLuid.Info.IfType &&
> -            unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
> -            ovsInternalIP = ipAddr;
> +
> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +        head = &(ovsInstanceList);
> +        LIST_FORALL_SAFE(head, link, next) {
> +            POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE,
> link);
> +
> +            ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +            if (instance->isIpConfigured &&
> +                OvsCheckInstanceRow(&instance->internalRow,
> +                                    &unicastRow->InterfaceLuid,
> +                                    unicastRow->InterfaceIndex)) {
> +
> +                instance->ipAddress = ipAddr;
> +
> +                OVS_LOG_INFO("IP Address: %d.%d.%d.%d is %s",
> +                             ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> +                             (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
> +                             notificationType == MibAddInstance ?
> "added": "modified");
> +
> +                ExReleaseResourceLite(&instance->lock);
> +                break;
> +            }
> +            ExReleaseResourceLite(&instance->lock);
>          }
> -        OVS_LOG_INFO("IP Address: %d.%d.%d.%d is %s",
> -                     ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> -                     (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
> -                     notificationType == MibAddInstance ? "added":
> "modified");
> +        ExReleaseResourceLite(&ovsInstanceListLock);
> +
>          break;
> +    }
>
>      case MibDeleteInstance:
> +    {
> +        PLIST_ENTRY head, link, next;
> +        LOCK_STATE_EX lockState;
> +        BOOLEAN found = FALSE;
> +
>          ASSERT(unicastRow);
>          ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
> -        OVS_LOG_INFO("IP Address removed: %d.%d.%d.%d",
> -                     ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> -                     (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
> -        if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
> -            unicastRow->InterfaceLuid.Info.IfType ==
> -            ovsInternalRow.InterfaceLuid.Info.IfType &&
> -            unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
>
> -            LOCK_STATE_EX lockState;
> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +        head = &(ovsInstanceList);
> +        LIST_FORALL_SAFE(head, link, next) {
> +            POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE,
> link);
> +
> +            ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +            if (instance->isIpConfigured &&
> +                OvsCheckInstanceRow(&instance->internalRow,
> +                                    &unicastRow->InterfaceLuid,
> +                                    unicastRow->InterfaceIndex)) {
> +
> +                found = TRUE;
> +
> +                ExReleaseResourceLite(&instance->lock);
> +                break;
> +            }
> +            ExReleaseResourceLite(&instance->lock);
> +        }
> +        ExReleaseResourceLite(&ovsInstanceListLock);
> +
> +        if (found) {
>              NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
>              OvsRemoveAllFwdEntriesWithSrc(ipAddr);
>              NdisReleaseRWLock(ovsTableLock, &lockState);
>
> +            OVS_LOG_INFO("IP Address removed: %d.%d.%d.%d",
> +                         ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> +                         (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
>          }
> +
>          break;
> +    }
>
>      case MibInitialNotification:
>          OVS_LOG_INFO("Get Initial notification for Unicast IP Address
> change.");
> @@ -651,7 +924,7 @@ OvsRegisterChangeNotification()
>                                       &ipInterfaceNotificationHandle);
>      if (status != STATUS_SUCCESS) {
>          OVS_LOG_ERROR("Fail to register Notify IP interface change,
> status:%x.",
> -                     status);
> +                      status);
>          return status;
>      }
>
> @@ -659,7 +932,7 @@ OvsRegisterChangeNotification()
>                                  TRUE, &ipRouteNotificationHandle);
>      if (status != STATUS_SUCCESS) {
>          OVS_LOG_ERROR("Fail to regiter ip route change, status: %x.",
> -                     status);
> +                      status);
>          goto register_cleanup;
>      }
>      status = NotifyUnicastIpAddressChange(AF_INET,
> @@ -682,10 +955,11 @@ static POVS_IPNEIGH_ENTRY
>  OvsLookupIPNeighEntry(UINT32 ipAddr)
>  {
>      PLIST_ENTRY link;
> -    POVS_IPNEIGH_ENTRY entry;
>      UINT32 hash = OvsJhashWords(&ipAddr, 1, OVS_HASH_BASIS);
>
>      LIST_FORALL(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK],
> link) {
> +        POVS_IPNEIGH_ENTRY entry;
> +
>          entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, link);
>          if (entry->ipAddr == ipAddr) {
>              return entry;
> @@ -709,7 +983,6 @@ OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
>  {
>
>      PLIST_ENTRY link;
> -    POVS_IPFORWARD_ENTRY ipfEntry;
>      UINT32 hash;
>      ASSERT(prefix->Prefix.si_family == AF_INET);
>
> @@ -720,6 +993,8 @@ OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
>
>      hash = OvsHashIPPrefix(prefix);
>      LIST_FORALL(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK],
> link) {
> +        POVS_IPFORWARD_ENTRY ipfEntry;
> +
>          ipfEntry = CONTAINING_RECORD(link, OVS_IPFORWARD_ENTRY, link);
>          if (ipfEntry->prefix.PrefixLength == prefix->PrefixLength &&
>              ipfEntry->prefix.Prefix.Ipv4.sin_addr.s_addr ==
> @@ -732,15 +1007,17 @@ OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
>
>
>  static POVS_FWD_ENTRY
> -OvsLookupIPFwdEntry(UINT32 dstIp)
> +OvsLookupIPFwdEntry(UINT32 srcIp, UINT32 dstIp)
>  {
>      PLIST_ENTRY link;
> -    POVS_FWD_ENTRY entry;
>      UINT32 hash = OvsJhashWords(&dstIp, 1, OVS_HASH_BASIS);
>
>      LIST_FORALL(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK], link) {
> +        POVS_FWD_ENTRY entry;
> +
>          entry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
> -        if (entry->info.dstIpAddr == dstIp) {
> +        if (entry->info.dstIpAddr == dstIp &&
> +            (!srcIp || entry->info.srcIpAddr == srcIp)) {
>              return entry;
>          }
>      }
> @@ -749,7 +1026,8 @@ OvsLookupIPFwdEntry(UINT32 dstIp)
>
>
>  NTSTATUS
> -OvsLookupIPFwdInfo(UINT32 dstIp,
> +OvsLookupIPFwdInfo(UINT32 srcIp,
> +                   UINT32 dstIp,
>                     POVS_FWD_INFO info)
>  {
>      POVS_FWD_ENTRY entry;
> @@ -757,11 +1035,10 @@ OvsLookupIPFwdInfo(UINT32 dstIp,
>      NTSTATUS status = STATUS_NOT_FOUND;
>
>      NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
> -    entry = OvsLookupIPFwdEntry(dstIp);
> +    entry = OvsLookupIPFwdEntry(srcIp, dstIp);
>      if (entry) {
> -        info->value[0] = entry->info.value[0];
> -        info->value[1] = entry->info.value[1];
> -        info->value[2] = entry->info.value[2];
> +        RtlCopyMemory(info->value, entry->info.value,
> +                      sizeof entry->info.value);
>          status = STATUS_SUCCESS;
>      }
>      NdisReleaseRWLock(ovsTableLock, &lockState);
> @@ -770,7 +1047,8 @@ OvsLookupIPFwdInfo(UINT32 dstIp,
>
>
>  static POVS_IPNEIGH_ENTRY
> -OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
> +OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh,
> +                      POVS_IPHELPER_INSTANCE instance)
>  {
>
>      POVS_IPNEIGH_ENTRY entry;
> @@ -790,6 +1068,7 @@ OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
>      RtlCopyMemory(entry->macAddr, ipNeigh->PhysicalAddress,
>                    ETH_ADDR_LEN);
>      InitializeListHead(&entry->fwdList);
> +    entry->context = (PVOID)instance;
>
>      return entry;
>  }
> @@ -798,7 +1077,6 @@ OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
>  static POVS_IPFORWARD_ENTRY
>  OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
>  {
> -
>      POVS_IPFORWARD_ENTRY entry;
>
>      ASSERT(ipRoute);
> @@ -876,12 +1154,13 @@ OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
>  static VOID
>  OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf)
>  {
> -    POVS_FWD_ENTRY fwdEntry;
>      PLIST_ENTRY link, next;
>
>      ipf->refCount++;
>
>      LIST_FORALL_SAFE(&ipf->fwdList, link, next) {
> +        POVS_FWD_ENTRY fwdEntry;
> +
>          fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
>          OvsRemoveFwdEntry(fwdEntry);
>      }
> @@ -896,11 +1175,12 @@ static VOID
>  OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn)
>  {
>      PLIST_ENTRY link, next;
> -    POVS_FWD_ENTRY fwdEntry;
>
>      ipn->refCount++;
>
>      LIST_FORALL_SAFE(&ipn->fwdList, link, next) {
> +        POVS_FWD_ENTRY fwdEntry;
> +
>          fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
>          OvsRemoveFwdEntry(fwdEntry);
>      }
> @@ -919,10 +1199,10 @@ static VOID
>  OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn)
>  {
>      PLIST_ENTRY link;
> -    POVS_IPNEIGH_ENTRY entry;
>
>      if (!IsListEmpty(&ovsSortedIPNeighList)) {
>          link = ovsSortedIPNeighList.Blink;
> +        POVS_IPNEIGH_ENTRY entry;
>          entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
>          if (entry->timeout > ipn->timeout) {
>              ipn->timeout++;
> @@ -973,11 +1253,12 @@ static VOID
>  OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr)
>  {
>      UINT32 i;
> -    POVS_FWD_ENTRY fwdEntry;
>      PLIST_ENTRY link, next;
>
>      for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
>          LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
> +            POVS_FWD_ENTRY fwdEntry;
> +
>              fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
>              if (fwdEntry->info.srcIpAddr == ipAddr) {
>                  OvsRemoveFwdEntry(fwdEntry);
> @@ -988,19 +1269,38 @@ OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr)
>
>
>  static VOID
> +OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo)
> +{
> +    UINT32 i;
> +    PLIST_ENTRY link, next;
> +
> +    for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
> +        LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
> +            POVS_FWD_ENTRY fwdEntry;
> +
> +            fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
> +            if (fwdEntry->info.srcPortNo == portNo) {
> +                OvsRemoveFwdEntry(fwdEntry);
> +            }
> +        }
> +    }
> +}
> +
> +static VOID
>  OvsCleanupFwdTable(VOID)
>  {
>      PLIST_ENTRY link, next;
> -    POVS_IPNEIGH_ENTRY ipn;
>      UINT32 i;
>      LOCK_STATE_EX lockState;
>
>      NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
>      if (ovsNumFwdEntries) {
> -       LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) {
> -           ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
> -           OvsRemoveIPNeighEntry(ipn);
> -       }
> +        LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) {
> +            POVS_IPNEIGH_ENTRY ipn;
> +
> +            ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
> +            OvsRemoveIPNeighEntry(ipn);
> +        }
>      }
>      for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
>          ASSERT(IsListEmpty(&ovsFwdHashTable[i]));
> @@ -1017,20 +1317,16 @@ OvsCleanupIpHelperRequestList(VOID)
>  {
>      LIST_ENTRY list;
>      PLIST_ENTRY next, link;
> -    POVS_IP_HELPER_REQUEST request;
>
>      NdisAcquireSpinLock(&ovsIpHelperLock);
> -    if (ovsNumIpHelperRequests == 0) {
> -       NdisReleaseSpinLock(&ovsIpHelperLock);
> -       return;
> -    }
> -
>      InitializeListHead(&list);
> -    OvsAppendList(&list,  &ovsIpHelperRequestList);
> +    OvsAppendList(&list, &ovsIpHelperRequestList);
>      ovsNumIpHelperRequests = 0;
>      NdisReleaseSpinLock(&ovsIpHelperLock);
>
>      LIST_FORALL_SAFE(&list, link, next) {
> +        POVS_IP_HELPER_REQUEST request;
> +
>          request = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
>
>          if (request->command == OVS_IP_HELPER_FWD_REQUEST &&
> @@ -1056,27 +1352,40 @@ OvsWakeupIPHelper(VOID)
>  }
>
>  VOID
> -OvsInternalAdapterDown(VOID)
> +OvsInternalAdapterDown(UINT32 portNo,
> +                       GUID netCfgInstanceId)
>  {
> -    NdisAcquireSpinLock(&ovsIpHelperLock);
> -    ovsInternalAdapterUp = FALSE;
> -    ovsInternalIPConfigured = FALSE;
> -    NdisReleaseSpinLock(&ovsIpHelperLock);
> +    POVS_IP_HELPER_REQUEST request;
>
> -    OvsCleanupIpHelperRequestList();
> +    request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
> +        sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
> +    if (request == NULL) {
> +        OVS_LOG_ERROR("Fail to initialize Internal Adapter");
> +        return;
> +    }
> +    RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
> +    RtlCopyMemory(&request->instanceReq.netCfgInstanceId,
> +                  &netCfgInstanceId,
> +                  sizeof(netCfgInstanceId));
> +    request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN;
> +    request->instanceReq.portNo = portNo;
>
> -    OvsCleanupFwdTable();
> +    NdisAcquireSpinLock(&ovsIpHelperLock);
> +    InsertHeadList(&ovsIpHelperRequestList, &request->link);
> +    ovsNumIpHelperRequests++;
> +    if (ovsNumIpHelperRequests == 1) {
> +        OvsWakeupIPHelper();
> +    }
> +    NdisReleaseSpinLock(&ovsIpHelperLock);
>  }
>
>
>  VOID
> -OvsInternalAdapterUp(GUID *netCfgInstanceId)
> +OvsInternalAdapterUp(UINT32 portNo,
> +                     GUID *netCfgInstanceId)
>  {
>      POVS_IP_HELPER_REQUEST request;
>
> -    RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
> -    RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
> -
>      request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
>          sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
>      if (request == NULL) {
> @@ -1084,10 +1393,13 @@ OvsInternalAdapterUp(GUID *netCfgInstanceId)
>          return;
>      }
>      RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
> +    RtlCopyMemory(&request->instanceReq.netCfgInstanceId,
> +                  netCfgInstanceId,
> +                  sizeof(*netCfgInstanceId));
>      request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
> +    request->instanceReq.portNo = portNo;
>
>      NdisAcquireSpinLock(&ovsIpHelperLock);
> -    ovsInternalAdapterUp = TRUE;
>      InsertHeadList(&ovsIpHelperRequestList, &request->link);
>      ovsNumIpHelperRequests++;
>      if (ovsNumIpHelperRequests == 1) {
> @@ -1099,58 +1411,116 @@ OvsInternalAdapterUp(GUID *netCfgInstanceId)
>  }
>
>
> +static POVS_IPHELPER_INSTANCE
> +OvsIpHelperAllocateInstance(POVS_IP_HELPER_REQUEST request)
> +{
> +    POVS_IPHELPER_INSTANCE instance = NULL;
> +
> +    instance = (POVS_IPHELPER_INSTANCE)OvsAllocateMemoryWithTag(
> +        sizeof(*instance), OVS_IPHELPER_POOL_TAG);
> +    if (instance) {
> +        RtlZeroMemory(instance, sizeof(*instance));
> +
> +        RtlCopyMemory(&instance->netCfgId,
> +                      &request->instanceReq.netCfgInstanceId,
> +                      sizeof(instance->netCfgId));
> +        instance->portNo = request->instanceReq.portNo;
> +
> +        InitializeListHead(&instance->link);
> +        ExInitializeResourceLite(&instance->lock);
> +    }
> +
> +    return instance;
> +}
> +
> +
> +static VOID
> +OvsIpHelperDeleteInstance(POVS_IPHELPER_INSTANCE instance)
> +{
> +    if (instance) {
> +        ExDeleteResourceLite(&instance->lock);
> +        OvsFreeMemoryWithTag(instance, OVS_IPHELPER_POOL_TAG);
> +    }
> +}
> +
> +
> +static VOID
> +OvsIpHelperDeleteAllInstances()
> +{
> +    PLIST_ENTRY head, link, next;
> +
> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +    head = &ovsInstanceList;
> +    if (!IsListEmpty(head)) {
> +        LIST_FORALL_SAFE(head, link, next) {
> +            POVS_IPHELPER_INSTANCE instance = NULL;
> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE,
> link);
> +
> +            ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
> +
> +            instance->isIpConfigured = FALSE;
> +            RemoveEntryList(&instance->link);
> +
> +            ExReleaseResourceLite(&instance->lock);
> +
> +            OvsIpHelperDeleteInstance(instance);
> +        }
> +    }
> +    ExReleaseResourceLite(&ovsInstanceListLock);
> +}
> +
> +
>  static VOID
>  OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
>  {
>      NTSTATUS status;
> +    POVS_IPHELPER_INSTANCE instance = NULL;
>      MIB_UNICASTIPADDRESS_ROW ipEntry;
> -    GUID *netCfgInstanceId = &ovsInternalNetCfgId;
> +    BOOLEAN error = TRUE;
>
> -    OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
> +    do {
> +        instance = OvsIpHelperAllocateInstance(request);
> +        if (instance == NULL) {
> +            break;
> +        }
> +        RtlZeroMemory(&instance->internalRow, sizeof(MIB_IF_ROW2));
> +        RtlZeroMemory(&instance->internalIPRow,
> sizeof(MIB_IPINTERFACE_ROW));
> +        status = OvsGetIfEntry(&instance->netCfgId,
> +                               &instance->internalRow);
>
> -    status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
> +        if (status != STATUS_SUCCESS) {
> +            OvsDumpMessageWithGuid("Fail to get IF entry for internal
> port with GUID"
> +                                   "  %08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> +                                   instance->netCfgId);
> +            break;
> +        }
>
> -    if (status != STATUS_SUCCESS) {
> -        OVS_LOG_ERROR("Fali to get IF entry for internal port with GUID"
> -                      "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
> -                      netCfgInstanceId->Data1,
> -                      netCfgInstanceId->Data2,
> -                      netCfgInstanceId->Data3,
> -                      *(UINT16 *)netCfgInstanceId->Data4,
> -                      netCfgInstanceId->Data4[2],
> -                      netCfgInstanceId->Data4[3],
> -                      netCfgInstanceId->Data4[4],
> -                      netCfgInstanceId->Data4[5],
> -                      netCfgInstanceId->Data4[6],
> -                      netCfgInstanceId->Data4[7]);
> -        return;
> -    }
> +        status = OvsGetIPInterfaceEntry(instance->internalRow.
> InterfaceLuid,
> +                                        &instance->internalIPRow);
>
> -    status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
> -                                    &ovsInternalIPRow);
> +        if (status == STATUS_SUCCESS) {
> +            instance->isIpConfigured = TRUE;
> +        } else {
> +            break;
> +        }
>
> -    if (status == STATUS_SUCCESS) {
> -        NdisAcquireSpinLock(&ovsIpHelperLock);
> -        ovsInternalIPConfigured = TRUE;
> -        NdisReleaseSpinLock(&ovsIpHelperLock);
> -    } else {
> -        return;
> -    }
> +        status = OvsGetIPEntry(instance->internalRow.InterfaceLuid,
> &ipEntry);
> +        if (status != STATUS_SUCCESS) {
> +            OvsDumpMessageWithGuid("Fail to get IP entry for internal
> port with GUID"
> +                                   "  %08x-%04x-%04x-%04x-%02x%02x%
> 02x%02x%02x%02x",
> +                                   instance->netCfgId);
> +        }
>
> -    status = OvsGetIPEntry(ovsInternalRow.InterfaceLuid, &ipEntry);
> -    if (status != STATUS_SUCCESS) {
> -        OVS_LOG_INFO("Fali to get IP entry for internal port with GUID"
> -                     "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
> -                     netCfgInstanceId->Data1,
> -                     netCfgInstanceId->Data2,
> -                     netCfgInstanceId->Data3,
> -                     *(UINT16 *)netCfgInstanceId->Data4,
> -                     netCfgInstanceId->Data4[2],
> -                     netCfgInstanceId->Data4[3],
> -                     netCfgInstanceId->Data4[4],
> -                     netCfgInstanceId->Data4[5],
> -                     netCfgInstanceId->Data4[6],
> -                     netCfgInstanceId->Data4[7]);
> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
> +        InsertHeadList(&ovsInstanceList, &instance->link);
> +        ExReleaseResourceLite(&ovsInstanceListLock);
> +
> +        error = FALSE;
> +    } while (error);
> +
> +    OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
> +    if (error) {
> +        OvsIpHelperDeleteInstance(instance);
>      }
>  }
>
> @@ -1158,15 +1528,11 @@ OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST
> request)
>  static NTSTATUS
>  OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
>  {
> -
> -    NdisAcquireSpinLock(&ovsIpHelperLock);
> -
> -    if (ovsInternalAdapterUp == FALSE ||
> -        ovsInternalIPConfigured == FALSE) {
> -        NdisReleaseSpinLock(&ovsIpHelperLock);
> +    if (IsListEmpty(&ovsInstanceList)) {
>          OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
>          return STATUS_NDIS_ADAPTER_NOT_READY;
>      } else {
> +        NdisAcquireSpinLock(&ovsIpHelperLock);
>          InsertHeadList(&ovsIpHelperRequestList, &request->link);
>          ovsNumIpHelperRequests++;
>          if (ovsNumIpHelperRequests == 1) {
> @@ -1214,7 +1580,7 @@ OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
>      NTSTATUS status;
>      MIB_IPFORWARD_ROW2 ipRoute;
>      MIB_IPNET_ROW2 ipNeigh;
> -    OVS_FWD_INFO fwdInfo;
> +    OVS_FWD_INFO fwdInfo = { 0 };
>      UINT32 ipAddr;
>      UINT32 srcAddr;
>      POVS_FWD_ENTRY fwdEntry = NULL;
> @@ -1224,8 +1590,10 @@ OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
>      BOOLEAN  newIPF = FALSE;
>      BOOLEAN  newIPN = FALSE;
>      BOOLEAN  newFWD = FALSE;
> +    POVS_IPHELPER_INSTANCE instance = NULL;
>
> -    status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.dst,
> +    status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.src,
> +                                request->fwdReq.tunnelKey.dst,
>                                  &fwdInfo);
>      if (status == STATUS_SUCCESS) {
>          goto fwd_handle_nbl;
> @@ -1238,10 +1606,23 @@ OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST
> request)
>      dst.si_family = AF_INET;
>      dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
>
> -    status = OvsGetRoute(ovsInternalRow.InterfaceLuid, &dst, &ipRoute,
> &src);
> -    if (status != STATUS_SUCCESS) {
> +    status = OvsGetRoute(&dst, &ipRoute, &src, &instance, &fwdInfo.vport,
> request->fwdReq.tunnelKey.src);
> +    if (request->fwdReq.tunnelKey.src && request->fwdReq.tunnelKey.src !=
> src.Ipv4.sin_addr.s_addr) {
> +        UINT32 ipAddr = dst.Ipv4.sin_addr.s_addr;
> +        OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
> +            ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> +            (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
> +        goto fwd_handle_nbl;
> +    }
> +    if (status != STATUS_SUCCESS || instance == NULL) {
> +        UINT32 ipAddr = dst.Ipv4.sin_addr.s_addr;
> +        OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
> +                     ipAddr & 0xff, (ipAddr >> 8) & 0xff,
> +                     (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
> status);
>          goto fwd_handle_nbl;
>      }
> +
> +    ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
>      srcAddr = src.Ipv4.sin_addr.s_addr;
>
>      /* find IPNeigh */
> @@ -1254,13 +1635,16 @@ OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST
> request)
>          }
>          NdisReleaseRWLock(ovsTableLock, &lockState);
>      }
> +
>      RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
> -    ipNeigh.InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
> +    ipNeigh.InterfaceLuid.Value = instance->internalRow.
> InterfaceLuid.Value;
>      if (ipAddr == 0) {
>          ipAddr = request->fwdReq.tunnelKey.dst;
>      }
> -    status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
> +    status = OvsGetOrResolveIPNeigh(instance->internalRow,
> +                                    ipAddr, &ipNeigh);
>      if (status != STATUS_SUCCESS) {
> +        ExReleaseResourceLite(&instance->lock);
>          goto fwd_handle_nbl;
>      }
>
> @@ -1276,6 +1660,7 @@ fwd_request_done:
>          ipf = OvsCreateIPForwardEntry(&ipRoute);
>          if (ipf == NULL) {
>              NdisReleaseRWLock(ovsTableLock, &lockState);
> +            ExReleaseResourceLite(&instance->lock);
>              status = STATUS_INSUFFICIENT_RESOURCES;
>              goto fwd_handle_nbl;
>          }
> @@ -1284,6 +1669,13 @@ fwd_request_done:
>          PLIST_ENTRY link;
>          link = ipf->fwdList.Flink;
>          fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
> +        if (fwdEntry->info.srcIpAddr != srcAddr) {
> +            OvsRemoveFwdEntry(fwdEntry);
> +            NdisReleaseRWLock(ovsTableLock, &lockState);
> +            ExReleaseResourceLite(&instance->lock);
> +            status = STATUS_INSUFFICIENT_RESOURCES;
> +            goto fwd_handle_nbl;
> +        }
>          srcAddr = fwdEntry->info.srcIpAddr;
>      }
>
> @@ -1293,9 +1685,10 @@ fwd_request_done:
>      if (ipn == NULL) {
>          ipn = OvsLookupIPNeighEntry(ipAddr);
>          if (ipn == NULL) {
> -            ipn = OvsCreateIPNeighEntry(&ipNeigh);
> +            ipn = OvsCreateIPNeighEntry(&ipNeigh, instance);
>              if (ipn == NULL) {
>                  NdisReleaseRWLock(ovsTableLock, &lockState);
> +                ExReleaseResourceLite(&instance->lock);
>                  status = STATUS_INSUFFICIENT_RESOURCES;
>                  goto fwd_handle_nbl;
>              }
> @@ -1309,22 +1702,26 @@ fwd_request_done:
>      fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
>      fwdInfo.srcIpAddr = srcAddr;
>      RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
> -    RtlCopyMemory(fwdInfo.srcMacAddr, ovsInternalRow.PhysicalAddress,
> +    RtlCopyMemory(fwdInfo.srcMacAddr, instance->internalRow.
> PhysicalAddress,
>                    ETH_ADDR_LEN);
>      fwdInfo.srcPortNo = request->fwdReq.inPort;
>
>      fwdEntry = OvsCreateFwdEntry(&fwdInfo);
>      if (fwdEntry == NULL) {
>          NdisReleaseRWLock(ovsTableLock, &lockState);
> +        ExReleaseResourceLite(&instance->lock);
>          status = STATUS_INSUFFICIENT_RESOURCES;
>          goto fwd_handle_nbl;
>      }
>      newFWD = TRUE;
> -    /*
> -     * Cache the result
> -     */
> -    OvsAddIPFwdCache(fwdEntry, ipf, ipn);
> -    NdisReleaseRWLock(ovsTableLock, &lockState);
> +    if (status == STATUS_SUCCESS) {
> +        /*
> +         * Cache the result
> +         */
> +        OvsAddIPFwdCache(fwdEntry, ipf, ipn);
> +        NdisReleaseRWLock(ovsTableLock, &lockState);
> +        ExReleaseResourceLite(&instance->lock);
> +    }
>
>  fwd_handle_nbl:
>
> @@ -1391,7 +1788,6 @@ OvsUpdateIPNeighEntry(UINT32 ipAddr,
>                 (const PVOID)ipNeigh->PhysicalAddress,
>                 (size_t)ETH_ADDR_LEN)) {
>          PLIST_ENTRY link;
> -        POVS_FWD_ENTRY fwdEntry;
>          NdisReleaseRWLock(ovsTableLock, &lockState);
>          /*
>           * need update, release and acquire write lock
> @@ -1407,6 +1803,7 @@ OvsUpdateIPNeighEntry(UINT32 ipAddr,
>          }
>
>          LIST_FORALL(&ipn->fwdList, link) {
> +            POVS_FWD_ENTRY fwdEntry;
>              fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
>              RtlCopyMemory(fwdEntry->info.dstMacAddr,
>                            ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
> @@ -1425,28 +1822,15 @@ OvsUpdateIPNeighEntry(UINT32 ipAddr,
>      NdisReleaseRWLock(ovsTableLock, &lockState);
>  }
>
> -
> -static VOID
> -OvsHandleIPNeighTimeout(UINT32 ipAddr)
> -{
> -    MIB_IPNET_ROW2 ipNeigh;
> -    NTSTATUS status;
> -
> -    status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
> -
> -    OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
> -}
> -
> -
>  /*
>   *-----------------------------------------------------------
> -----------------
> - *  IP Helper system threash handle following request
> + *  IP Helper system thread handles the following requests:
>   *    1. Intialize Internal port row when internal port is connected
>   *    2. Handle FWD request
>   *    3. Handle IP Neigh timeout
>   *
>   *    IP Interface, unicast address, and IP route change will be handled
> - *    by the revelant callback.
> + *    by the revelant callbacks.
>   *-----------------------------------------------------------
> -----------------
>   */
>  VOID
> @@ -1479,6 +1863,45 @@ OvsStartIpHelper(PVOID data)
>              case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
>                  OvsHandleInternalAdapterUp(req);
>                  break;
> +            case OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN:
> +            {
> +                PLIST_ENTRY head, link, next;
> +                UINT32 portNo = req->instanceReq.portNo;
> +                GUID netCfgInstanceId = req->instanceReq.
> netCfgInstanceId;
> +
> +                ExAcquireResourceExclusiveLite(&ovsInstanceListLock,
> TRUE);
> +                head = &ovsInstanceList;
> +                LIST_FORALL_SAFE(head, link, next) {
> +                    POVS_IPHELPER_INSTANCE instance = NULL;
> +                    LOCK_STATE_EX lockState;
> +
> +                    instance = CONTAINING_RECORD(link,
> OVS_IPHELPER_INSTANCE, link);
> +
> +                    ExAcquireResourceExclusiveLite(&instance->lock,
> TRUE);
> +                    if (instance->portNo == portNo &&
> +                        IsEqualGUID(&instance->netCfgId,
> &netCfgInstanceId)) {
> +
> +                        NdisAcquireRWLockWrite(ovsTableLock, &lockState,
> 0);
> +                        OvsRemoveAllFwdEntriesWithPort
> No(instance->portNo);
> +                        NdisReleaseRWLock(ovsTableLock, &lockState);
> +
> +                        RemoveEntryList(&instance->link);
> +
> +                        ExReleaseResourceLite(&instance->lock);
> +
> +                        OvsIpHelperDeleteInstance(instance);
> +                        break;
> +                    }
> +                    ExReleaseResourceLite(&instance->lock);
> +                }
> +
> +                if (IsListEmpty(&ovsInstanceList)) {
> +                    OvsCleanupIpHelperRequestList();
> +
> +                    OvsCleanupFwdTable();
> +                }
> +                ExReleaseResourceLite(&ovsInstanceListLock);
> +            }
>              case OVS_IP_HELPER_FWD_REQUEST:
>                  OvsHandleFwdRequest(req);
>                  break;
> @@ -1506,10 +1929,18 @@ OvsStartIpHelper(PVOID data)
>                  break;
>              }
>              ipAddr = ipn->ipAddr;
> -
> +            MIB_IPNET_ROW2 ipNeigh;
> +            NTSTATUS status;
> +            POVS_IPHELPER_INSTANCE instance =
> (POVS_IPHELPER_INSTANCE)ipn->context;
> +            MIB_IF_ROW2 internalRow = instance->internalRow;
>              NdisReleaseSpinLock(&ovsIpHelperLock);
> +            ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
>
> -            OvsHandleIPNeighTimeout(ipAddr);
> +            status = OvsGetOrResolveIPNeigh(internalRow,
> +                                            ipAddr, &ipNeigh);
> +            OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
> +
> +            ExReleaseResourceLite(&ovsInstanceListLock);
>
>              NdisAcquireSpinLock(&ovsIpHelperLock);
>          }
> @@ -1537,7 +1968,6 @@ ip_helper_wait:
>      NdisReleaseSpinLock(&ovsIpHelperLock);
>      OvsCleanupFwdTable();
>      OvsCleanupIpHelperRequestList();
> -
>      OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
>
>      PsTerminateSystemThread(STATUS_SUCCESS);
> @@ -1547,7 +1977,7 @@ ip_helper_wait:
>  NTSTATUS
>  OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
>  {
> -    NTSTATUS status;
> +    NTSTATUS status = NDIS_STATUS_SUCCESS;
>      HANDLE threadHandle;
>      UINT32 i;
>
> @@ -1560,12 +1990,6 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
>      ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
>          sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE,
> OVS_IPHELPER_POOL_TAG);
>
> -    RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
> -    RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
> -    ovsInternalIP = 0;
> -
> -    ovsInternalAdapterUp = FALSE;
> -
>      InitializeListHead(&ovsSortedIPNeighList);
>
>      ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
> @@ -1577,6 +2001,9 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
>      ipRouteNotificationHandle = NULL;
>      unicastIPNotificationHandle = NULL;
>
> +    ExInitializeResourceLite(&ovsInstanceListLock);
> +    InitializeListHead(&ovsInstanceList);
> +
>      if (ovsFwdHashTable == NULL ||
>          ovsRouteHashTable == NULL ||
>          ovsNeighHashTable == NULL ||
> @@ -1636,6 +2063,7 @@ init_cleanup:
>              NdisFreeRWLock(ovsTableLock);
>              ovsTableLock = NULL;
>          }
> +        ExDeleteResourceLite(&ovsInstanceListLock);
>          NdisFreeSpinLock(&ovsIpHelperLock);
>      }
>      return STATUS_SUCCESS;
> @@ -1662,6 +2090,9 @@ OvsCleanupIpHelper(VOID)
>
>      NdisFreeRWLock(ovsTableLock);
>      NdisFreeSpinLock(&ovsIpHelperLock);
> +
> +    OvsIpHelperDeleteAllInstances();
> +    ExDeleteResourceLite(&ovsInstanceListLock);
>  }
>
>  VOID
> diff --git a/datapath-windows/ovsext/IpHelper.h b/datapath-windows/ovsext/
> IpHelper.h
> index 8562f86..6bda1b1 100644
> --- a/datapath-windows/ovsext/IpHelper.h
> +++ b/datapath-windows/ovsext/IpHelper.h
> @@ -19,6 +19,7 @@
>
>  #include <ntddk.h>
>  #include <netioapi.h>
> +#include <Vport.h>
>
>  #define OVS_FWD_HASH_TABLE_SIZE ((UINT32)1 << 10)
>  #define OVS_FWD_HASH_TABLE_MASK (OVS_FWD_HASH_TABLE_SIZE - 1)
> @@ -41,6 +42,7 @@ typedef struct _OVS_IPNEIGH_ENTRY {
>      LIST_ENTRY        link;
>      LIST_ENTRY        slink;
>      LIST_ENTRY        fwdList;
> +    PVOID             context;
>  } OVS_IPNEIGH_ENTRY, *POVS_IPNEIGH_ENTRY;
>
>  typedef struct _OVS_IPFORWARD_ENTRY {
> @@ -51,15 +53,16 @@ typedef struct _OVS_IPFORWARD_ENTRY {
>      LIST_ENTRY        fwdList;
>  } OVS_IPFORWARD_ENTRY, *POVS_IPFORWARD_ENTRY;
>
> -typedef union  _OVS_FWD_INFO {
> +typedef union _OVS_FWD_INFO {
>      struct {
>          UINT32        dstIpAddr;
>          UINT32        srcIpAddr;
>          UINT8         dstMacAddr[ETH_ADDR_LEN];
>          UINT8         srcMacAddr[ETH_ADDR_LEN];
>          UINT32        srcPortNo;
> +        POVS_VPORT_ENTRY   vport;
>      };
> -    UINT64            value[3];
> +    UINT64            value[4];
>  } OVS_FWD_INFO, *POVS_FWD_INFO;
>
>  typedef struct _OVS_FWD_ENTRY {
> @@ -74,6 +77,7 @@ typedef struct _OVS_FWD_ENTRY {
>
>  enum {
>      OVS_IP_HELPER_INTERNAL_ADAPTER_UP,
> +    OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN,
>      OVS_IP_HELPER_FWD_REQUEST,
>  };
>
> @@ -94,13 +98,17 @@ typedef struct _OVS_FWD_REQUEST_INFO {
>      PVOID             cbData2;
>  } OVS_FWD_REQUEST_INFO, *POVS_FWD_REQUEST_INFO;
>
> +typedef struct _OVS_INSTANCE_REQUEST_INFO {
> +    GUID              netCfgInstanceId;
> +    UINT32            portNo;
> +} OVS_INSTANCE_REQUEST_INFO, *POVS_INSTANCE_REQUEST_INFO;
>
>  typedef struct _OVS_IP_HELPER_REQUEST {
>      LIST_ENTRY        link;
>      UINT32            command;
>      union {
> -        OVS_FWD_REQUEST_INFO    fwdReq;
> -        UINT32                  dummy;
> +        OVS_FWD_REQUEST_INFO        fwdReq;
> +        OVS_INSTANCE_REQUEST_INFO   instanceReq;
>      };
>  } OVS_IP_HELPER_REQUEST, *POVS_IP_HELPER_REQUEST;
>
> @@ -114,15 +122,15 @@ typedef struct _OVS_IP_HELPER_THREAD_CONTEXT {
>  NTSTATUS OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle);
>  VOID OvsCleanupIpHelper(VOID);
>
> -VOID OvsInternalAdapterUp(GUID *netCfgInstanceId);
> -VOID OvsInternalAdapterDown(VOID);
> +VOID OvsInternalAdapterUp(UINT32 portNo, GUID *netCfgInstanceId);
> +VOID OvsInternalAdapterDown(UINT32 portNo, GUID netCfgInstanceId);
>
>  NTSTATUS OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl, UINT32 inPort,
>                                 const PVOID tunnelKey,
>                                 OvsIPHelperCallback cb,
>                                 PVOID cbData1,
>                                 PVOID cbData2);
> -NTSTATUS OvsLookupIPFwdInfo(UINT32 dstIp, POVS_FWD_INFO info);
> +NTSTATUS OvsLookupIPFwdInfo(UINT32 srcIp, UINT32 dstIp, POVS_FWD_INFO
> info);
>  VOID OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl);
>
>  #endif /* __IP_HELPER_H_ */
> diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c
> index b04a77f..9da81dc 100644
> --- a/datapath-windows/ovsext/Stt.c
> +++ b/datapath-windows/ovsext/Stt.c
> @@ -107,13 +107,14 @@ OvsEncapStt(POVS_VPORT_ENTRY vport,
>              OvsIPv4TunnelKey *tunKey,
>              POVS_SWITCH_CONTEXT switchContext,
>              POVS_PACKET_HDR_INFO layers,
> -            PNET_BUFFER_LIST *newNbl)
> +            PNET_BUFFER_LIST *newNbl,
> +            POVS_FWD_INFO switchFwdInfo)
>  {
>      OVS_FWD_INFO fwdInfo;
>      NDIS_STATUS status;
>
>      UNREFERENCED_PARAMETER(switchContext);
> -    status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
> +    status = OvsLookupIPFwdInfo(tunKey->src, tunKey->dst, &fwdInfo);
>      if (status != STATUS_SUCCESS) {
>          OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL);
>          /*
> @@ -123,6 +124,8 @@ OvsEncapStt(POVS_VPORT_ENTRY vport,
>          return NDIS_STATUS_FAILURE;
>      }
>
> +    RtlCopyMemory(switchFwdInfo->value, fwdInfo.value, sizeof
> fwdInfo.value);
> +
>      status = OvsDoEncapStt(vport, curNbl, tunKey, &fwdInfo, layers,
>                             switchContext, newNbl);
>      return status;
> diff --git a/datapath-windows/ovsext/Stt.h b/datapath-windows/ovsext/Stt.h
> index 1b7e797..988a1c1 100644
> --- a/datapath-windows/ovsext/Stt.h
> +++ b/datapath-windows/ovsext/Stt.h
> @@ -17,6 +17,10 @@
>  #ifndef __OVS_STT_H_
>  #define __OVS_STT_H_ 1
>
> +#include "IpHelper.h"
> +
> +typedef union _OVS_FWD_INFO *POVS_FWD_INFO;
> +
>  #define STT_TCP_PORT 7471
>  #define STT_TCP_PORT_NBO 0x2f1d
>
> @@ -91,7 +95,8 @@ NDIS_STATUS OvsEncapStt(POVS_VPORT_ENTRY vport,
>                          OvsIPv4TunnelKey *tunKey,
>                          POVS_SWITCH_CONTEXT switchContext,
>                          POVS_PACKET_HDR_INFO layers,
> -                        PNET_BUFFER_LIST *newNbl);
> +                        PNET_BUFFER_LIST *newNbl,
> +                        POVS_FWD_INFO switchFwdInfo);
>
>
>  NDIS_STATUS OvsDecapStt(POVS_SWITCH_CONTEXT switchContext,
> diff --git a/datapath-windows/ovsext/Switch.h b/datapath-windows/ovsext/
> Switch.h
> index 001335a..7c98621 100644
> --- a/datapath-windows/ovsext/Switch.h
> +++ b/datapath-windows/ovsext/Switch.h
> @@ -103,7 +103,7 @@ typedef struct _OVS_SWITCH_CONTEXT
>       *
>       * The "real" physical external NIC has 'NicIndex' > 0. For each
>       * external interface, virtual or physical, NDIS gives an NIC level
> -     * OID callback. Note that, even though there are multile "NICs",
> +     * OID callback. Note that, even though there are multiple "NICs",
>       * there's only one underlying Hyper-V port. Thus, we get a single
>       * NDIS port-level callback, but multiple NDIS NIC-level callbacks.
>       *
> @@ -127,9 +127,10 @@ typedef struct _OVS_SWITCH_CONTEXT
>       * 'numPhysicalNics'.
>       */
>      NDIS_SWITCH_PORT_ID     virtualExternalPortId;
> -    NDIS_SWITCH_PORT_ID     internalPortId;
> -    POVS_VPORT_ENTRY        virtualExternalVport;   // the virtual
> adapter vport
> -    POVS_VPORT_ENTRY        internalVport;
> +    POVS_VPORT_ENTRY        virtualExternalVport;   /* the virtual adapter
> +                                                     * vport */
> +    INT32                   countInternalVports;    /* the number of
> internal
> +                                                     * vports */
>
>      /*
>       * 'portIdHashArray' ONLY contains ports that exist on the Hyper-V
> switch,
> diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/
> Vport.c
> index 428259b..e9e22aa 100644
> --- a/datapath-windows/ovsext/Vport.c
> +++ b/datapath-windows/ovsext/Vport.c
> @@ -82,8 +82,6 @@ static NTSTATUS 
> CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO
> info,
>                                             PVOID outBuffer,
>                                             UINT32 outBufLen,
>                                             int dpIfIndex);
> -static POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT
> switchContext,
> -                                              PWSTR wsName, SIZE_T
> wstrSize);
>  static VOID UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT switchContext,
>                                       POVS_VPORT_ENTRY vport, BOOLEAN
> newPort);
>  static NTSTATUS OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT
> usrParamsCtx,
> @@ -97,8 +95,11 @@ static VOID OvsTunnelVportPendingInit(PVOID context,
>  static VOID OvsTunnelVportPendingRemove(PVOID context,
>                                          NTSTATUS status,
>                                          UINT32 *replyLen);
> -static NTSTATUS GetNICAlias(GUID *netCfgInstanceId,
> +static NTSTATUS GetNICAlias(PNDIS_SWITCH_NIC_PARAMETERS nicParam,
>                              IF_COUNTED_STRING *portFriendlyName);
> +static NTSTATUS OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
> +                                                CHAR *str,
> +                                                UINT16 maxStrLen);
>
>  /*
>   * ------------------------------------------------------------
> --------------
> @@ -340,7 +341,7 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
>
>      if (OvsIsInternalNIC(nicParam->NicType) ||
>          OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
> -        GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
> +        GetNICAlias(nicParam, &portFriendlyName);
>      }
>
>      NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
> @@ -350,26 +351,46 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
>       * from the parent external port.
>       */
>      if (OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
> -        NDIS_SWITCH_PORT_PARAMETERS portParam;
> -        POVS_VPORT_ENTRY virtExtVport =
> -            (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
> -
> -        ASSERT(virtExtVport);
> +        /* The VPORT can be bound to OVS datapath already. Search for it
> +         * using its friendly name and if not found allocate a new port
> +         */
>          ASSERT(OvsFindVportByPortIdAndNicIndex(switchContext,
>                                                 nicParam->PortId,
>                                                 nicParam->NicIndex) ==
> NULL);
> -        OvsCopyPortParamsFromVport(virtExtVport, &portParam);
> +        char convertString[256];
> +        RtlZeroMemory(convertString, 256);
>          NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
> -        status = HvCreatePort(switchContext, &portParam,
> -                              nicParam->NicIndex);
> +        status = OvsConvertIfCountedStrToAnsiStr(&portFriendlyName,
> +                                                 convertString,
> +
>  OVS_MAX_PORT_NAME_LENGTH);
>          NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState,
> 0);
>          if (status != NDIS_STATUS_SUCCESS) {
>              goto add_nic_done;
>          }
> +        POVS_VPORT_ENTRY ovsVport = OvsFindVportByOvsName(switchContext,
> +                                                          convertString);
> +        if (ovsVport != NULL) {
> +            UpdateSwitchCtxWithVport(switchContext, ovsVport, FALSE);
> +        } else {
> +            NDIS_SWITCH_PORT_PARAMETERS portParam;
> +            POVS_VPORT_ENTRY virtExtVport =
> +                (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
> +
> +            ASSERT(virtExtVport);
> +            OvsCopyPortParamsFromVport(virtExtVport, &portParam);
> +            NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
> +            status = HvCreatePort(switchContext, &portParam,
> +                                  nicParam->NicIndex);
> +            NdisAcquireRWLockWrite(switchContext->dispatchLock,
> &lockState, 0);
> +            if (status != NDIS_STATUS_SUCCESS) {
> +                goto add_nic_done;
> +            }
> +        }
>      }
>
>      vport = OvsFindVportByPortIdAndNicIndex(switchContext,
> nicParam->PortId,
>                                              nicParam->NicIndex);
> +
>      if (vport == NULL) {
>          OVS_LOG_ERROR("Create NIC without Switch Port,"
>                        " PortId: %x, NicIndex: %d",
> @@ -434,7 +455,7 @@ HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
>      NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
>
>      if (nicParam->NicType == NdisSwitchNicTypeInternal) {
> -        OvsInternalAdapterUp(&nicParam->NetCfgInstanceId);
> +        OvsInternalAdapterUp(vport->portNo, &vport->netCfgInstanceId);
>      }
>
>  done:
> @@ -471,7 +492,7 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
>      /* GetNICAlias() must be called outside of a lock. */
>      if (nicParam->NicType == NdisSwitchNicTypeInternal ||
>          OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
> -        GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
> +        GetNICAlias(nicParam, &portFriendlyName);
>          aliasLookup = TRUE;
>      }
>
> @@ -614,7 +635,9 @@ HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
>      NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
>
>      if (isInternalPort) {
> -        OvsInternalAdapterDown();
> +        OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);
> +        OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
> +        OvsPostVportEvent(&event);
>      }
>
>  done:
> @@ -870,10 +893,6 @@ OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT
> switchContext,
>              portId == switchContext->virtualExternalPortId &&
>              index == switchContext->virtualExternalVport->nicIndex) {
>          return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
> -    } else if (switchContext->internalVport &&
> -               portId == switchContext->internalPortId &&
> -               index == switchContext->internalVport->nicIndex) {
> -        return (POVS_VPORT_ENTRY)switchContext->internalVport;
>      } else {
>          PLIST_ENTRY head, link;
>          POVS_VPORT_ENTRY vport;
> @@ -920,7 +939,6 @@ OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
>      vport->portId = portParam->PortId;
>      vport->nicState = NdisSwitchNicStateUnknown;
>      vport->isExternal = FALSE;
> -    vport->isBridgeInternal = FALSE;
>
>      switch (vport->portType) {
>      case NdisSwitchPortTypeExternal:
> @@ -962,7 +980,6 @@ OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT
> switchContext,
>                           PNDIS_SWITCH_NIC_PARAMETERS nicParam)
>  {
>      ASSERT(vport->portId == nicParam->PortId);
> -    ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
>
>      UNREFERENCED_PARAMETER(switchContext);
>
> @@ -980,6 +997,8 @@ OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT
> switchContext,
>      } else {
>          RtlCopyMemory(&vport->netCfgInstanceId,
> &nicParam->NetCfgInstanceId,
>                        sizeof (nicParam->NetCfgInstanceId));
> +        RtlCopyMemory(&vport->nicFriendlyName,
> &nicParam->NicFriendlyName,
> +                      sizeof (nicParam->NicFriendlyName));
>      }
>      RtlCopyMemory(&vport->nicName, &nicParam->NicName,
>                    sizeof (nicParam->NicName));
> @@ -1041,7 +1060,6 @@ OvsInitTunnelVport(PVOID userContext,
>      POVS_USER_PARAMS_CONTEXT usrParamsCtx =
>          (POVS_USER_PARAMS_CONTEXT)userContext;
>
> -    vport->isBridgeInternal = FALSE;
>      vport->ovsType = ovsType;
>      vport->ovsState = OVS_STATE_PORT_CREATED;
>      switch (ovsType) {
> @@ -1088,37 +1106,27 @@ OvsInitTunnelVport(PVOID userContext,
>
>  /*
>   * ------------------------------------------------------------
> --------------
> - * Initializes a bridge internal vport ie. a port of type
> - * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
> - * ------------------------------------------------------------
> --------------
> - */
> -NTSTATUS
> -OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
> -{
> -    vport->isBridgeInternal = TRUE;
> -    vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
> -    /* Mark the status to be connected, since there is no other
> initialization
> -     * for this port. */
> -    vport->ovsState = OVS_STATE_CONNECTED;
> -    return STATUS_SUCCESS;
> -}
> -
> -/*
> - * ------------------------------------------------------------
> --------------
>   * For external and internal vports 'portFriendlyName' parameter,
> provided by
> - * Hyper-V, is overwritten with the interface alias name.
> +  * Hyper-V, is overwritten with the interface alias name and NIC
> friendly name
> +  * equivalent.
>   * ------------------------------------------------------------
> --------------
>   */
>  static NTSTATUS
> -GetNICAlias(GUID *netCfgInstanceId,
> +GetNICAlias(PNDIS_SWITCH_NIC_PARAMETERS nicParam,
>              IF_COUNTED_STRING *portFriendlyName)
>  {
> -    NTSTATUS status;
> +    NTSTATUS status = STATUS_SUCCESS;
>      WCHAR interfaceName[IF_MAX_STRING_SIZE + 1];
>      NET_LUID interfaceLuid;
>      size_t len;
>
> -    status = ConvertInterfaceGuidToLuid(netCfgInstanceId,
> +    if (nicParam->NicType == NdisSwitchNicTypeInternal) {
> +        RtlCopyMemory(portFriendlyName, &nicParam->NicFriendlyName,
> +                      sizeof nicParam->NicFriendlyName);
> +    return status;
> +    }
> +
> +    status = ConvertInterfaceGuidToLuid(&nicParam->NetCfgInstanceId,
>                                          &interfaceLuid);
>      if (status == STATUS_SUCCESS) {
>          /*
> @@ -1167,14 +1175,12 @@ UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT
> switchContext,
>          if (vport->nicIndex == 0) {
>              switchContext->virtualExternalPortId = vport->portId;
>              switchContext->virtualExternalVport = vport;
> -        } else {
> +        } else if (newPort == TRUE) {
>              switchContext->numPhysicalNics++;
>          }
>          break;
>      case NdisSwitchPortTypeInternal:
> -        ASSERT(vport->isBridgeInternal == FALSE);
> -        switchContext->internalPortId = vport->portId;
> -        switchContext->internalVport = vport;
> +        switchContext->countInternalVports++;
>          break;
>      case NdisSwitchPortTypeSynthetic:
>      case NdisSwitchPortTypeEmulated:
> @@ -1235,10 +1241,6 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT
> switchContext,
>          switchContext->numNonHvVports++;
>          break;
>      }
> -    case OVS_VPORT_TYPE_INTERNAL:
> -        if (vport->isBridgeInternal) {
> -            switchContext->numNonHvVports++;
> -        }
>      default:
>          break;
>      }
> @@ -1289,14 +1291,12 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
>
>      switch (vport->ovsType) {
>      case OVS_VPORT_TYPE_INTERNAL:
> -        if (!vport->isBridgeInternal) {
> -            if (hvDelete && vport->isAbsentOnHv == FALSE) {
> -                switchContext->internalPortId = 0;
> -                switchContext->internalVport = NULL;
> -                OvsInternalAdapterDown();
> -            }
> -            hvSwitchPort = TRUE;
> +        if (hvDelete && vport->isAbsentOnHv == FALSE) {
> +            switchContext->countInternalVports--;
> +            ASSERT(switchContext->countInternalVports >= 0);
> +            OvsInternalAdapterDown(vport->portNo,
> vport->netCfgInstanceId);
>          }
> +        hvSwitchPort = TRUE;
>          break;
>      case OVS_VPORT_TYPE_VXLAN:
>      {
> @@ -1557,14 +1557,13 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT
> switchContext)
>              POVS_VPORT_ENTRY vport;
>              vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
>              ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
> -                   (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
> -                    vport->isBridgeInternal) || vport->isAbsentOnHv ==
> TRUE);
> +                   vport->isAbsentOnHv == TRUE);
>              OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE,
> TRUE);
>          }
>      }
>
>      ASSERT(switchContext->virtualExternalVport == NULL);
> -    ASSERT(switchContext->internalVport == NULL);
> +    ASSERT(switchContext->countInternalVports == 0);
>  }
>
>
> @@ -2246,12 +2245,12 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT
> usrParamsCtx,
>          goto Cleanup;
>      }
>
> -    if (portType == OVS_VPORT_TYPE_NETDEV) {
> -        /* External ports can also be looked up like VIF ports. */
> +    if (portType == OVS_VPORT_TYPE_NETDEV ||
> +        portType == OVS_VPORT_TYPE_INTERNAL) {
> +        /* External and internal ports can also be looked up like VIF
> ports. */
>          vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
>      } else {
> -        ASSERT(OvsIsTunnelVportType(portType) ||
> -               portType == OVS_VPORT_TYPE_INTERNAL);
> +        ASSERT(OvsIsTunnelVportType(portType));
>
>          vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
>          if (vport == NULL) {
> @@ -2315,8 +2314,6 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT
> usrParamsCtx,
>                                          transportPortDest);
>
>              nlError = NlMapStatusToNlErr(status);
> -        } else {
> -            OvsInitBridgeInternalVport(vport);
>          }
>
>          vportInitialized = TRUE;
> diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/
> Vport.h
> index 1f4968e..4dc4e00 100644
> --- a/datapath-windows/ovsext/Vport.h
> +++ b/datapath-windows/ovsext/Vport.h
> @@ -26,7 +26,7 @@
>  #define OVS_MAX_DPPORTS             MAXUINT16
>  #define OVS_DPPORT_NUMBER_INVALID   OVS_MAX_DPPORTS
>  /*
> - * The local port (0) is a reserved port, that is not allowed to be be
> + * The local port (0) is a reserved port, that is not allowed to be
>   * created by the netlink command vport add. On linux, this port is
> created
>   * at netlink command datapath new. However, on windows, we do not need to
>   * create it, and more, we shouldn't. The userspace attempts to create two
> @@ -80,58 +80,44 @@ typedef struct _OVS_VPORT_FULL_STATS {
>   * tunnel type, such as vxlan, gre
>   */
>  typedef struct _OVS_VPORT_ENTRY {
> -    LIST_ENTRY             ovsNameLink;
> -    LIST_ENTRY             portIdLink;
> -    LIST_ENTRY             portNoLink;
> -    LIST_ENTRY             tunnelVportLink;
> -
> -    OVS_VPORT_STATE        ovsState;
> -    OVS_VPORT_TYPE         ovsType;
> -    OVS_VPORT_STATS        stats;
> -    OVS_VPORT_ERR_STATS    errStats;
> -    UINT32                 portNo;
> -    UINT32                 mtu;
> +    LIST_ENTRY                   ovsNameLink;
> +    LIST_ENTRY                   portIdLink;
> +    LIST_ENTRY                   portNoLink;
> +    LIST_ENTRY                   tunnelVportLink;
> +
> +    OVS_VPORT_STATE              ovsState;
> +    OVS_VPORT_TYPE               ovsType;
> +    OVS_VPORT_STATS              stats;
> +    OVS_VPORT_ERR_STATS          errStats;
> +    UINT32                       portNo;
> +    UINT32                       mtu;
>      /* ovsName is the ovs (datapath) port name - it is null terminated. */
> -    CHAR                   ovsName[OVS_MAX_PORT_NAME_LENGTH];
> -
> -    PVOID                  priv;
> -    NDIS_SWITCH_PORT_ID    portId;
> -    NDIS_SWITCH_NIC_INDEX  nicIndex;
> -    NDIS_SWITCH_NIC_TYPE   nicType;
> -    UINT16                 numaNodeId;
> -    NDIS_SWITCH_PORT_STATE portState;
> -    NDIS_SWITCH_NIC_STATE  nicState;
> -    NDIS_SWITCH_PORT_TYPE  portType;
> -
> -    UINT8                  permMacAddress[ETH_ADDR_LEN];
> -    UINT8                  currMacAddress[ETH_ADDR_LEN];
> -    UINT8                  vmMacAddress[ETH_ADDR_LEN];
> -
> -    NDIS_SWITCH_PORT_NAME  hvPortName;
> -    IF_COUNTED_STRING      portFriendlyName;
> -    NDIS_SWITCH_NIC_NAME   nicName;
> -    NDIS_VM_NAME           vmName;
> -    GUID                   netCfgInstanceId;
> -    /*
> -     * OVS userpace has a notion of bridges which basically defines an
> -     * L2-domain. Each "bridge" has an "internal" port of type
> -     * OVS_VPORT_TYPE_INTERNAL. Such a port is connected to the OVS
> datapath in
> -     * one end, and the other end is a virtual adapter on the hypervisor
> host.
> -     * This is akin to the Hyper-V "internal" NIC. It is intuitive to map
> the
> -     * Hyper-V "internal" NIC to the OVS bridge's "internal" port, but
> there's
> -     * only one Hyper-V NIC but multiple bridges. To support multiple OVS
> bridge
> -     * "internal" ports, we use the flag 'isBridgeInternal' in each
> vport. We
> -     * support addition of multiple bridge-internal ports. A vport with
> -     * 'isBridgeInternal' == TRUE is a dummy port and has no backing
> currently.
> -     * If a flow actions specifies the output port to be a
> bridge-internal port,
> -     * the port is silently ignored.
> -     */
> -    BOOLEAN                isBridgeInternal;
> -    BOOLEAN                isExternal;
> -    UINT32                 upcallPid; /* netlink upcall port id */
> -    PNL_ATTR               portOptions;
> -    BOOLEAN                isAbsentOnHv; /* Is this port present on the
> -                                             Hyper-V switch? */
> +    CHAR                         ovsName[OVS_MAX_PORT_NAME_LENGTH];
> +
> +    PVOID                        priv;
> +    NDIS_SWITCH_PORT_ID          portId;
> +    NDIS_SWITCH_NIC_INDEX        nicIndex;
> +    NDIS_SWITCH_NIC_TYPE         nicType;
> +    UINT16                       numaNodeId;
> +    NDIS_SWITCH_PORT_STATE       portState;
> +    NDIS_SWITCH_NIC_STATE        nicState;
> +    NDIS_SWITCH_PORT_TYPE        portType;
> +
> +    UINT8                        permMacAddress[ETH_ADDR_LEN];
> +    UINT8                        currMacAddress[ETH_ADDR_LEN];
> +    UINT8                        vmMacAddress[ETH_ADDR_LEN];
> +
> +    NDIS_SWITCH_PORT_NAME        hvPortName;
> +    IF_COUNTED_STRING            portFriendlyName;
> +    NDIS_SWITCH_NIC_NAME         nicName;
> +    NDIS_SWITCH_NIC_FRIENDLYNAME nicFriendlyName;
> +    NDIS_VM_NAME                 vmName;
> +    GUID                         netCfgInstanceId;
> +    BOOLEAN                      isExternal;
> +    UINT32                       upcallPid; /* netlink upcall port id */
> +    PNL_ATTR                     portOptions;
> +    BOOLEAN                      isAbsentOnHv; /* Is this port present on
> the
> +                                                  Hyper-V switch? */
>  } OVS_VPORT_ENTRY, *POVS_VPORT_ENTRY;
>
>  struct _OVS_SWITCH_CONTEXT;
> @@ -143,6 +129,8 @@ POVS_VPORT_ENTRY OvsFindVportByOvsName(POVS_SWITCH_CONTEXT
> switchContext,
>                                         PSTR name);
>  POVS_VPORT_ENTRY OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
>                                         PSTR name);
> +POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
> +                                       PWSTR wsName, SIZE_T wstrSize);
>  POVS_VPORT_ENTRY OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT
> switchContext,
>                                                   NDIS_SWITCH_PORT_ID
> portId,
>                                                   NDIS_SWITCH_NIC_INDEX
> index);
> @@ -217,14 +205,6 @@ OvsIsRealExternalVport(POVS_VPORT_ENTRY vport)
>  }
>
>  static __inline BOOLEAN
> -OvsIsBridgeInternalVport(POVS_VPORT_ENTRY vport)
> -{
> -    ASSERT(vport->isBridgeInternal != TRUE ||
> -           vport->ovsType == OVS_VPORT_TYPE_INTERNAL);
> -    return vport->isBridgeInternal == TRUE;
> -}
> -
> -static __inline BOOLEAN
>  OvsIsInternalNIC(NDIS_SWITCH_NIC_TYPE   nicType)
>  {
>      return nicType == NdisSwitchNicTypeInternal;
> @@ -261,7 +241,7 @@ GetPortFromPriv(POVS_VPORT_ENTRY vport)
>      UINT16 dstPort = 0;
>      PVOID vportPriv = GetOvsVportPriv(vport);
>
> -    /* XXX would better to have a commom tunnel "parent" structure */
> +    /* XXX would better to have a common tunnel "parent" structure */
>      ASSERT(vportPriv);
>      switch(vport->ovsType) {
>      case OVS_VPORT_TYPE_GRE:
> @@ -273,7 +253,7 @@ GetPortFromPriv(POVS_VPORT_ENTRY vport)
>          dstPort = ((POVS_VXLAN_VPORT)vportPriv)->dstPort;
>          break;
>      case OVS_VPORT_TYPE_GENEVE:
> -        dstPort = ((POVS_GENEVE_VPORT) vportPriv)->dstPort;
> +        dstPort = ((POVS_GENEVE_VPORT)vportPriv)->dstPort;
>          break;
>      default:
>          ASSERT(! "Port is not a tunnel port");
> diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/
> Vxlan.c
> index db45248..949e069 100644
> --- a/datapath-windows/ovsext/Vxlan.c
> +++ b/datapath-windows/ovsext/Vxlan.c
> @@ -334,7 +334,7 @@ ret_error:
>   *-----------------------------------------------------------
> -----------------
>   * OvsEncapVxlan --
>   *     Encapsulates the packet if L2/L3 for destination resolves.
> Otherwise,
> - *     enqueues a callback that does encapsulatation after resolution.
> + *     enqueues a callback that does encapsulation after resolution.
>   *-----------------------------------------------------------
> -----------------
>   */
>  NDIS_STATUS
> @@ -343,15 +343,15 @@ OvsEncapVxlan(POVS_VPORT_ENTRY vport,
>                OvsIPv4TunnelKey *tunKey,
>                POVS_SWITCH_CONTEXT switchContext,
>                POVS_PACKET_HDR_INFO layers,
> -              PNET_BUFFER_LIST *newNbl)
> +              PNET_BUFFER_LIST *newNbl,
> +              POVS_FWD_INFO switchFwdInfo)
>  {
>      NTSTATUS status;
>      OVS_FWD_INFO fwdInfo;
>
> -    status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
> +    status = OvsLookupIPFwdInfo(tunKey->src, tunKey->dst, &fwdInfo);
>      if (status != STATUS_SUCCESS) {
>          OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL);
> -        // return NDIS_STATUS_PENDING;
>          /*
>           * XXX: Don't know if the completionList will make any sense when
>           * accessed in the callback. Make sure the caveats are known.
> @@ -362,6 +362,8 @@ OvsEncapVxlan(POVS_VPORT_ENTRY vport,
>          return NDIS_STATUS_FAILURE;
>      }
>
> +    RtlCopyMemory(switchFwdInfo->value, fwdInfo.value, sizeof
> fwdInfo.value);
> +
>      return OvsDoEncapVxlan(vport, curNbl, tunKey, &fwdInfo, layers,
>                             switchContext, newNbl);
>  }
> diff --git a/datapath-windows/ovsext/Vxlan.h b/datapath-windows/ovsext/
> Vxlan.h
> index b9462f0..f4a8bce 100644
> --- a/datapath-windows/ovsext/Vxlan.h
> +++ b/datapath-windows/ovsext/Vxlan.h
> @@ -17,7 +17,11 @@
>  #ifndef __VXLAN_H_
>  #define __VXLAN_H_ 1
>
> +#include "IpHelper.h"
>  #include "NetProto.h"
> +
> +typedef union _OVS_FWD_INFO *POVS_FWD_INFO;
> +
>  typedef struct _OVS_VXLAN_VPORT {
>      UINT16 dstPort;
>      UINT64 filterID;
> @@ -31,7 +35,8 @@ typedef struct _OVS_VXLAN_VPORT {
>  typedef struct VXLANHdr {
>      /* Flags. */
>      UINT32   flags1:2;
> -    /* Packet needs replication to multicast group (used for multicast
> proxy). */
> +    /* Packet needs replication to multicast group (used for multicast
> proxy).
> +     */
>      UINT32   locallyReplicate:1;
>      /* Instance ID flag, must be set to 1. */
>      UINT32   instanceID:1;
> @@ -64,7 +69,8 @@ NDIS_STATUS OvsEncapVxlan(POVS_VPORT_ENTRY vport,
>                            OvsIPv4TunnelKey *tunKey,
>                            POVS_SWITCH_CONTEXT switchContext,
>                            POVS_PACKET_HDR_INFO layers,
> -                          PNET_BUFFER_LIST *newNbl);
> +                          PNET_BUFFER_LIST *newNbl,
> +                          POVS_FWD_INFO switchFwdInfo);
>
>  NDIS_STATUS OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
>                            PNET_BUFFER_LIST curNbl,
> --
> 2.10.2.windows.1
>
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to