[ovs-dev] datapath-windows: IpHelper support for multiple adapter instances
diff mbox

Message ID 1441115375-11520-1-git-send-email-svinturis@cloudbasesolutions.com
State Not Applicable
Headers show

Commit Message

Sorin Vinturis Sept. 3, 2015, 11:54 a.m. UTC
Added support for multiple internal adapter instances to the IpHelper
module.

Signed-off-by: Sorin Vinturis <svinturis@cloudbasesolutions.com>
Reported-by: Sorin Vinturis <svinturis@cloudbasesolutions.com>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/101
---
 datapath-windows/ovsext/IpHelper.c | 648 ++++++++++++++++++++++++++-----------
 datapath-windows/ovsext/IpHelper.h |  11 +-
 datapath-windows/ovsext/Vport.c    |   4 +-
 3 files changed, 477 insertions(+), 186 deletions(-)

Comments

Nithin Raju Sept. 3, 2015, 1:50 p.m. UTC | #1
hi Sorin/Alin,
I suppose this is a patch that helps with supporting multiple hyper-v switches in one datapath.

We had spoken about this a couple of weeks ago during the IRC meeting. I was proposing a solution involves writing a teaming driver that can connect to multiple physical adapters. In order to support multiple internal adapters, we can write another driver similar to a TUN/TAP driver that allows us to create as many virtual adapters as we want. On the backend these virtual adapters can inject packets directly into the hyper-v switch.

We had signed off by saying we’ll writeup the proposal that talks about the workflow end-to-end, and take it from there. Would it be possible to send out the proposal before we make heavy duty changes?

Some concerns I have with supporting multiple switches are:

1. I am not sure how sound/great it is to forward packets from one hyper-v switch to another. Would it be possible to get a technical clarification from MSFT about this? I’ll ask around if we have any contacts.

2. How would compute provisioning work? With the current workflow we have, we pick a particular hyper-v switch (Eg. Overlay Switch) and connect all of the VMs to that switch, and OVS would take care of networking them up. If we support multiple Hyper-V switches, what would be the basis for connecting VMs to different Hyper-V switches?

3. It does not take away the need for a teaming driver.

thanks,
-- Nithin


> On Sep 3, 2015, at 4:54 AM, Sorin Vinturis <svinturis@cloudbasesolutions.com> wrote:

> 

> Added support for multiple internal adapter instances to the IpHelper

> module.

> 

> Signed-off-by: Sorin Vinturis <svinturis@cloudbasesolutions.com>

> Reported-by: Sorin Vinturis <svinturis@cloudbasesolutions.com>

> Reported-at: https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_openvswitch_ovs-2Dissues_issues_101&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pNHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=qGum5o5AOAacL3zQu_AHdhnVXoD8hib7nyXXg1JuQr8&s=iXoc-btgG4cPIdPKi_vFiw9g6JJS-Beqf0HUA6_dz2o&e= 

> ---

> datapath-windows/ovsext/IpHelper.c | 648 ++++++++++++++++++++++++++-----------

> datapath-windows/ovsext/IpHelper.h |  11 +-

> datapath-windows/ovsext/Vport.c    |   4 +-

> 3 files changed, 477 insertions(+), 186 deletions(-)

> 

> diff --git a/datapath-windows/ovsext/IpHelper.c b/datapath-windows/ovsext/IpHelper.c

> index de0d457..964b675 100644

> --- a/datapath-windows/ovsext/IpHelper.c

> +++ b/datapath-windows/ovsext/IpHelper.c

> @@ -26,28 +26,45 @@

> #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 UINT32              ovsInternalPortNo;

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

> @@ -85,6 +102,9 @@ static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);

> 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

> OvsDumpIfRow(PMIB_IF_ROW2 ifRow)

> @@ -325,30 +345,53 @@ 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)

> {

> -    NTSTATUS status;

> +    NTSTATUS status = STATUS_NETWORK_UNREACHABLE;

> +    NTSTATUS result = STATUS_SUCCESS;

> +    PLIST_ENTRY head, link, next;

> 

>     if (destinationAddress == NULL || route == NULL) {

>         return STATUS_INVALID_PARAMETER;

>     }

> 

> -    status = GetBestRoute2(&interfaceLuid, 0,

> -                           NULL, destinationAddress,

> -                           0, route, sourceAddress);

> +    ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);

> +    head = &(ovsInstanceList);

> +    LIST_FORALL_SAFE(head, link, next) {

> +        ULONG minMetric = (ULONG)-1;

> +        SOCKADDR_INET crtSrcAddr = { 0 };

> +        MIB_IPFORWARD_ROW2 crtRoute = { 0 };

> +        POVS_IPHELPER_INSTANCE crtInstance = NULL;

> 

> -    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);

> +

> +        ExAcquireResourceSharedLite(&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) {

> +            minMetric = crtRoute.Metric;

> +

> +            RtlCopyMemory(sourceAddress, &crtSrcAddr, sizeof(*sourceAddress));

> +            RtlCopyMemory(route, &crtRoute, sizeof(*route));

> +            *instance = crtInstance;

> +

> +            status = STATUS_SUCCESS;

> +        }

> +        ExReleaseResourceLite(&crtInstance->lock);

>     }

> +    ExReleaseResourceLite(&ovsInstanceListLock);

> 

>     OvsDumpRoute(sourceAddress, destinationAddress, route);

> +

>     return status;

> }

> 

> @@ -358,8 +401,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 +464,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 +473,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 +482,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);

> @@ -457,47 +501,91 @@ OvsChangeCallbackIpInterface(PVOID 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) {

> -            /*

> -             * Update the IP Interface Row

> -             */

> -            NdisAcquireSpinLock(&ovsIpHelperLock);

> -            RtlCopyMemory(&ovsInternalIPRow, ipRow,

> -                          sizeof (PMIB_IPINTERFACE_ROW));

> -            ovsInternalIPConfigured = TRUE;

> -            NdisReleaseSpinLock(&ovsIpHelperLock);

> +    {

> +        PLIST_ENTRY head, link, next;

> +

> +        ExAcquireResourceSharedLite(&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->internalRow.InterfaceLuid.Info.NetLuidIndex ==

> +                    ipRow->InterfaceLuid.Info.NetLuidIndex &&

> +                instance->internalRow.InterfaceLuid.Info.IfType ==

> +                    ipRow->InterfaceLuid.Info.IfType &&

> +                instance->internalRow.InterfaceIndex ==

> +                    ipRow->InterfaceIndex) {

> +

> +                /*

> +                 * Update the IP Interface Row

> +                 */

> +                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,

> +                             notificationType == MibAddInstance ?

> +                                 "added" : "modified");

> +

> +                ExReleaseResourceLite(&instance->lock);

> +                break;

> +            }

> +            ExReleaseResourceLite(&instance->lock);

>         }

> -        OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",

> -                     ipRow->InterfaceLuid.Info.NetLuidIndex,

> -                     ipRow->InterfaceLuid.Info.IfType,

> -                     notificationType == MibAddInstance ? "added" : "modified");

> +        ExReleaseResourceLite(&ovsInstanceListLock);

> +

>         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) {

> +    {

> +        PLIST_ENTRY head, link, next;

> 

> -            NdisAcquireSpinLock(&ovsIpHelperLock);

> -            ovsInternalIPConfigured = FALSE;

> -            NdisReleaseSpinLock(&ovsIpHelperLock);

> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);

> +        head = &(ovsInstanceList);

> +        LIST_FORALL_SAFE(head, link, next) {

> +            POVS_IPHELPER_INSTANCE instance = NULL;

> 

> -            OvsCleanupIpHelperRequestList();

> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);

> +

> +            ExAcquireResourceExclusiveLite(&instance->lock, TRUE);

> +            if (instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==

> +                    ipRow->InterfaceLuid.Info.NetLuidIndex &&

> +                instance->internalRow.InterfaceLuid.Info.IfType ==

> +                    ipRow->InterfaceLuid.Info.IfType &&

> +                instance->internalRow.InterfaceIndex ==

> +                    ipRow->InterfaceIndex) {

> +

> +                instance->isIpConfigured = FALSE;

> +                ExReleaseResourceLite(&instance->lock);

> +

> +                RemoveEntryList(&instance->link);

> +                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();

>         }

> 

>         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,25 +617,40 @@ OvsChangeCallbackIpRoute(PVOID context,

> 

>     case MibParameterNotification:

>     case MibDeleteInstance:

> +    {

> +        PLIST_ENTRY head, link, next;

> +        BOOLEAN found = FALSE;

> +

>         ASSERT(ipRoute);

>         ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;

>         nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;

> 

> -        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,

> -                     ipRoute->DestinationPrefix.PrefixLength,

> -                     nextHop & 0xff, (nextHop >> 8) & 0xff,

> -                     (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,

> -                     notificationType == MibDeleteInstance ? "deleted" :

> -                     "modified");

> +        ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);

> +        head = &(ovsInstanceList);

> +        LIST_FORALL_SAFE(head, link, next) {

> +            POVS_IPHELPER_INSTANCE instance = NULL;

> 

> -        if (ipRoute->InterfaceLuid.Info.NetLuidIndex ==

> -            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&

> -            ipRoute->InterfaceLuid.Info.IfType ==

> -            ovsInternalRow.InterfaceLuid.Info.IfType &&

> -            ipRoute->InterfaceIndex == ovsInternalRow.InterfaceIndex) {

> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);

> +

> +            ExAcquireResourceSharedLite(&instance->lock, TRUE);

> +            if (instance->isIpConfigured &&

> +                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==

> +                    ipRoute->InterfaceLuid.Info.NetLuidIndex &&

> +                instance->internalRow.InterfaceLuid.Info.IfType ==

> +                    ipRoute->InterfaceLuid.Info.IfType &&

> +                instance->internalRow.InterfaceIndex ==

> +                    ipRoute->InterfaceIndex) {

> +

> +                found = TRUE;

> +

> +                ExReleaseResourceLite(&instance->lock);

> +                break;

> +            }

> +            ExReleaseResourceLite(&instance->lock);

> +        }

> +        ExReleaseResourceLite(&ovsInstanceListLock);

> 

> +        if (found) {

>             POVS_IPFORWARD_ENTRY ipf;

>             LOCK_STATE_EX lockState;

> 

> @@ -557,8 +660,18 @@ OvsChangeCallbackIpRoute(PVOID context,

>                 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,

> +                         ipRoute->DestinationPrefix.PrefixLength,

> +                         nextHop & 0xff, (nextHop >> 8) & 0xff,

> +                         (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,

> +                         notificationType == MibDeleteInstance ? "deleted" :

> +                         "modified");

>         }

>         break;

> +    }

> 

>     case MibInitialNotification:

>         OVS_LOG_INFO("Get Initial notification for IP Route change.");

> @@ -579,40 +692,91 @@ 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;

> +

> +        ExAcquireResourceSharedLite(&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 &&

> +                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==

> +                    unicastRow->InterfaceLuid.Info.NetLuidIndex &&

> +                instance->internalRow.InterfaceLuid.Info.IfType ==

> +                    unicastRow->InterfaceLuid.Info.IfType &&

> +                instance->internalRow.InterfaceIndex ==

> +                    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;

> +        ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);

> +        head = &(ovsInstanceList);

> +        LIST_FORALL_SAFE(head, link, next) {

> +            POVS_IPHELPER_INSTANCE instance = NULL;

> +

> +            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);

> +

> +            ExAcquireResourceSharedLite(&instance->lock, TRUE);

> +            if (instance->isIpConfigured &&

> +                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==

> +                    unicastRow->InterfaceLuid.Info.NetLuidIndex &&

> +                instance->internalRow.InterfaceLuid.Info.IfType ==

> +                    unicastRow->InterfaceLuid.Info.IfType &&

> +                instance->internalRow.InterfaceIndex ==

> +                    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 +815,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 +823,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 +846,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 +874,6 @@ OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)

> {

> 

>     PLIST_ENTRY link;

> -    POVS_IPFORWARD_ENTRY ipfEntry;

>     UINT32 hash;

>     ASSERT(prefix->Prefix.si_family == AF_INET);

> 

> @@ -720,6 +884,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 ==

> @@ -735,10 +901,11 @@ static POVS_FWD_ENTRY

> OvsLookupIPFwdEntry(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) {

>             return entry;

> @@ -770,7 +937,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 +958,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 +967,6 @@ OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)

> static POVS_IPFORWARD_ENTRY

> OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)

> {

> -

>     POVS_IPFORWARD_ENTRY entry;

> 

>     ASSERT(ipRoute);

> @@ -876,12 +1044,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 +1065,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);

>     }

> @@ -973,11 +1143,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);

> @@ -991,13 +1162,14 @@ 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) {

> +           POVS_IPNEIGH_ENTRY ipn;

> +           

>            ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);

>            OvsRemoveIPNeighEntry(ipn);

>        }

> @@ -1017,7 +1189,6 @@ OvsCleanupIpHelperRequestList(VOID)

> {

>     LIST_ENTRY list;

>     PLIST_ENTRY next, link;

> -    POVS_IP_HELPER_REQUEST request;

> 

>     NdisAcquireSpinLock(&ovsIpHelperLock);

>     if (ovsNumIpHelperRequests == 0) {

> @@ -1031,6 +1202,8 @@ OvsCleanupIpHelperRequestList(VOID)

>     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,16 +1229,38 @@ OvsWakeupIPHelper(VOID)

> }

> 

> VOID

> -OvsInternalAdapterDown(VOID)

> +OvsInternalAdapterDown(UINT32 portNo,

> +                       GUID netCfgInstanceId)

> {

> -    NdisAcquireSpinLock(&ovsIpHelperLock);

> -    ovsInternalPortNo = OVS_DEFAULT_PORT_NO;

> -    ovsInternalIPConfigured = FALSE;

> -    NdisReleaseSpinLock(&ovsIpHelperLock);

> +    PLIST_ENTRY head, link, next;

> 

> -    OvsCleanupIpHelperRequestList();

> +    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);

> +    head = &ovsInstanceList;

> +    LIST_FORALL_SAFE(head, link, next) {

> +        POVS_IPHELPER_INSTANCE instance = NULL;

> 

> -    OvsCleanupFwdTable();

> +        instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);

> +

> +        ExAcquireResourceExclusiveLite(&instance->lock, TRUE);

> +        if (instance->portNo == portNo &&

> +            IsEqualGUID(&instance->netCfgId, &netCfgInstanceId)) {

> +

> +            RemoveEntryList(&instance->link);

> +

> +            ExReleaseResourceLite(&instance->lock);

> +

> +            OvsIpHelperDeleteInstance(instance);

> +            break;

> +        }

> +        ExReleaseResourceLite(&instance->lock);

> +    }

> +    ExReleaseResourceLite(&ovsInstanceListLock);

> +

> +    if (IsListEmpty(&ovsInstanceList)) {

> +        OvsCleanupIpHelperRequestList();

> +

> +        OvsCleanupFwdTable();

> +    }

> }

> 

> 

> @@ -1075,9 +1270,6 @@ OvsInternalAdapterUp(UINT32 portNo,

> {

>     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) {

> @@ -1085,10 +1277,13 @@ OvsInternalAdapterUp(UINT32 portNo,

>         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);

> -    ovsInternalPortNo = portNo;

>     InsertHeadList(&ovsIpHelperRequestList, &request->link);

>     ovsNumIpHelperRequests++;

>     if (ovsNumIpHelperRequests == 1) {

> @@ -1098,58 +1293,134 @@ OvsInternalAdapterUp(UINT32 portNo,

> }

> 

> 

> +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;

> +            ExReleaseResourceLite(&instance->lock);

> +

> +            RemoveEntryList(&instance->link);

> +

> +            OvsIpHelperDeleteInstance(instance);

> +            instance = NULL;

> +        }

> +    }

> +    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;

> +        }

> 

> -    status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);

> +        status = OvsGetIfEntry(&instance->netCfgId,

> +                               &instance->internalRow);

> 

> -    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;

> -    }

> +        if (status != STATUS_SUCCESS) {

> +            OVS_LOG_ERROR("Fail to get IF entry for internal port with GUID"

> +                          "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",

> +                          instance->netCfgId.Data1,

> +                          instance->netCfgId.Data2,

> +                          instance->netCfgId.Data3,

> +                          *(UINT16 *)instance->netCfgId.Data4,

> +                          instance->netCfgId.Data4[2],

> +                          instance->netCfgId.Data4[3],

> +                          instance->netCfgId.Data4[4],

> +                          instance->netCfgId.Data4[5],

> +                          instance->netCfgId.Data4[6],

> +                          instance->netCfgId.Data4[7]);

> +            break;

> +        }

> 

> -    status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,

> -                                    &ovsInternalIPRow);

> +        status = OvsGetIPInterfaceEntry(instance->internalRow.InterfaceLuid,

> +                                        &instance->internalIPRow);

> 

> -    if (status == STATUS_SUCCESS) {

> -        NdisAcquireSpinLock(&ovsIpHelperLock);

> -        ovsInternalIPConfigured = TRUE;

> -        NdisReleaseSpinLock(&ovsIpHelperLock);

> -    } else {

> -        return;

> -    }

> +        if (status == STATUS_SUCCESS) {

> +            instance->isIpConfigured = TRUE;

> +        } else {

> +            break;

> +        }

> 

> -    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]);

> +        status = OvsGetIPEntry(instance->internalRow.InterfaceLuid, &ipEntry);

> +        if (status != STATUS_SUCCESS) {

> +            OVS_LOG_INFO("Fail to get IP entry for internal port with GUID"

> +                         "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",

> +                         instance->netCfgId.Data1,

> +                         instance->netCfgId.Data2,

> +                         instance->netCfgId.Data3,

> +                         *(UINT16 *)instance->netCfgId.Data4,

> +                         instance->netCfgId.Data4[2],

> +                         instance->netCfgId.Data4[3],

> +                         instance->netCfgId.Data4[4],

> +                         instance->netCfgId.Data4[5],

> +                         instance->netCfgId.Data4[6],

> +                         instance->netCfgId.Data4[7]);

> +            break;

> +        }

> +

> +        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);

> +        InsertHeadList(&ovsInstanceList, &instance->link);

> +        ExReleaseResourceLite(&ovsInstanceListLock);

> +

> +        error = FALSE;

> +    } while (error);

> +

> +    OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);

> +    if (error) {

> +        OvsIpHelperDeleteInstance(instance);

>     }

> }

> 

> @@ -1157,15 +1428,11 @@ OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)

> static NTSTATUS

> OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)

> {

> -

> -    NdisAcquireSpinLock(&ovsIpHelperLock);

> -

> -    if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO ||

> -        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) {

> @@ -1223,6 +1490,7 @@ 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,

>                                 &fwdInfo);

> @@ -1237,10 +1505,16 @@ 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);

> +    status = OvsGetRoute(&dst, &ipRoute, &src, &instance);

>     if (status != STATUS_SUCCESS) {

> +        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;

>     }

> +

> +    ExAcquireResourceSharedLite(&instance->lock, TRUE);

>     srcAddr = src.Ipv4.sin_addr.s_addr;

> 

>     /* find IPNeigh */

> @@ -1253,13 +1527,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;

>     }

> 

> @@ -1275,6 +1552,7 @@ fwd_request_done:

>         ipf = OvsCreateIPForwardEntry(&ipRoute);

>         if (ipf == NULL) {

>             NdisReleaseRWLock(ovsTableLock, &lockState);

> +            ExReleaseResourceLite(&instance->lock);

>             status = STATUS_INSUFFICIENT_RESOURCES;

>             goto fwd_handle_nbl;

>         }

> @@ -1292,9 +1570,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;

>             }

> @@ -1308,13 +1587,14 @@ 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;

>     }

> @@ -1324,6 +1604,7 @@ fwd_request_done:

>      */

>     OvsAddIPFwdCache(fwdEntry, ipf, ipn);

>     NdisReleaseRWLock(ovsTableLock, &lockState);

> +    ExReleaseResourceLite(&instance->lock);

> 

> fwd_handle_nbl:

> 

> @@ -1426,12 +1707,17 @@ OvsUpdateIPNeighEntry(UINT32 ipAddr,

> 

> 

> static VOID

> -OvsHandleIPNeighTimeout(UINT32 ipAddr)

> +OvsHandleIPNeighTimeout(UINT32 ipAddr,

> +                        PVOID context)

> {

>     MIB_IPNET_ROW2 ipNeigh;

>     NTSTATUS status;

> +    POVS_IPHELPER_INSTANCE instance = (POVS_IPHELPER_INSTANCE)context;

> 

> -    status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);

> +    ExAcquireResourceSharedLite(&instance->lock, TRUE);

> +    status = OvsGetOrResolveIPNeigh(instance->internalRow,

> +                                    ipAddr, &ipNeigh);

> +    ExReleaseResourceLite(&instance->lock);

> 

>     OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);

> }

> @@ -1439,13 +1725,13 @@ OvsHandleIPNeighTimeout(UINT32 ipAddr)

> 

> /*

>  *----------------------------------------------------------------------------

> - *  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

> @@ -1455,7 +1741,7 @@ OvsStartIpHelper(PVOID data)

>     POVS_IP_HELPER_REQUEST req;

>     POVS_IPNEIGH_ENTRY ipn;

>     PLIST_ENTRY link;

> -    UINT64   timeVal, timeout;

> +    UINT64 timeVal, timeout;

> 

>     OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);

> 

> @@ -1504,7 +1790,7 @@ OvsStartIpHelper(PVOID data)

> 

>             NdisReleaseSpinLock(&ovsIpHelperLock);

> 

> -            OvsHandleIPNeighTimeout(ipAddr);

> +            OvsHandleIPNeighTimeout(ipAddr, ipn->context);

> 

>             NdisAcquireSpinLock(&ovsIpHelperLock);

>         }

> @@ -1550,12 +1836,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;

> -

> -    ovsInternalPortNo = OVS_DEFAULT_PORT_NO;

> -

>     InitializeListHead(&ovsSortedIPNeighList);

> 

>     ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);

> @@ -1567,6 +1847,9 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)

>     ipRouteNotificationHandle = NULL;

>     unicastIPNotificationHandle = NULL;

> 

> +    ExInitializeResourceLite(&ovsInstanceListLock);

> +    InitializeListHead(&ovsInstanceList);

> +

>     if (ovsFwdHashTable == NULL ||

>         ovsRouteHashTable == NULL ||

>         ovsNeighHashTable == NULL ||

> @@ -1587,7 +1870,6 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)

>         InitializeListHead(&ovsNeighHashTable[i]);

>     }

> 

> -

>     KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,

>                       FALSE);

>     status = OvsRegisterChangeNotification();

> @@ -1626,6 +1908,7 @@ init_cleanup:

>             NdisFreeRWLock(ovsTableLock);

>             ovsTableLock = NULL;

>         }

> +        ExDeleteResourceLite(&ovsInstanceListLock);

>         NdisFreeSpinLock(&ovsIpHelperLock);

>     }

>     return STATUS_SUCCESS;

> @@ -1652,6 +1935,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 19702a2..4d8d034 100644

> --- a/datapath-windows/ovsext/IpHelper.h

> +++ b/datapath-windows/ovsext/IpHelper.h

> @@ -41,6 +41,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 {

> @@ -94,13 +95,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;

> 

> @@ -115,7 +120,7 @@ NTSTATUS OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle);

> VOID OvsCleanupIpHelper(VOID);

> 

> VOID OvsInternalAdapterUp(UINT32 portNo, GUID *netCfgInstanceId);

> -VOID OvsInternalAdapterDown(VOID);

> +VOID OvsInternalAdapterDown(UINT32 portNo, GUID netCfgInstanceId);

> 

> NTSTATUS OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl, UINT32 inPort,

>                                const PVOID tunnelKey,

> diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c

> index 65a4134..dbd9a50 100644

> --- a/datapath-windows/ovsext/Vport.c

> +++ b/datapath-windows/ovsext/Vport.c

> @@ -525,7 +525,7 @@ HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,

>     OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);

> 

>     if (isInternalPort) {

> -        OvsInternalAdapterDown();

> +        OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);

>     }

> 

> done:

> @@ -1160,7 +1160,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,

>             if (hvDelete && vport->isAbsentOnHv == FALSE) {

>                 switchContext->internalPortId = 0;

>                 switchContext->internalVport = NULL;

> -                OvsInternalAdapterDown();

> +                OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);

>             }

>             hvSwitchPort = TRUE;

>         }

> -- 

> 1.9.0.msysgit.0

> 

> _______________________________________________

> dev mailing list

> dev@openvswitch.org

> https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailman_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pNHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=qGum5o5AOAacL3zQu_AHdhnVXoD8hib7nyXXg1JuQr8&s=Fe2_m9sZZzPkihUJPIQXx4AGUwFZ8bnPCv6X0nh0Lfg&e=

Patch
diff mbox

diff --git a/datapath-windows/ovsext/IpHelper.c b/datapath-windows/ovsext/IpHelper.c
index de0d457..964b675 100644
--- a/datapath-windows/ovsext/IpHelper.c
+++ b/datapath-windows/ovsext/IpHelper.c
@@ -26,28 +26,45 @@ 
 #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 UINT32              ovsInternalPortNo;
-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
@@ -85,6 +102,9 @@  static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);
 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
 OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
@@ -325,30 +345,53 @@  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)
 {
-    NTSTATUS status;
+    NTSTATUS status = STATUS_NETWORK_UNREACHABLE;
+    NTSTATUS result = STATUS_SUCCESS;
+    PLIST_ENTRY head, link, next;
 
     if (destinationAddress == NULL || route == NULL) {
         return STATUS_INVALID_PARAMETER;
     }
 
-    status = GetBestRoute2(&interfaceLuid, 0,
-                           NULL, destinationAddress,
-                           0, route, sourceAddress);
+    ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);
+    head = &(ovsInstanceList);
+    LIST_FORALL_SAFE(head, link, next) {
+        ULONG minMetric = (ULONG)-1;
+        SOCKADDR_INET crtSrcAddr = { 0 };
+        MIB_IPFORWARD_ROW2 crtRoute = { 0 };
+        POVS_IPHELPER_INSTANCE crtInstance = NULL;
 
-    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);
+
+        ExAcquireResourceSharedLite(&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) {
+            minMetric = crtRoute.Metric;
+
+            RtlCopyMemory(sourceAddress, &crtSrcAddr, sizeof(*sourceAddress));
+            RtlCopyMemory(route, &crtRoute, sizeof(*route));
+            *instance = crtInstance;
+
+            status = STATUS_SUCCESS;
+        }
+        ExReleaseResourceLite(&crtInstance->lock);
     }
+    ExReleaseResourceLite(&ovsInstanceListLock);
 
     OvsDumpRoute(sourceAddress, destinationAddress, route);
+
     return status;
 }
 
@@ -358,8 +401,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 +464,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 +473,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 +482,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);
@@ -457,47 +501,91 @@  OvsChangeCallbackIpInterface(PVOID 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) {
-            /*
-             * Update the IP Interface Row
-             */
-            NdisAcquireSpinLock(&ovsIpHelperLock);
-            RtlCopyMemory(&ovsInternalIPRow, ipRow,
-                          sizeof (PMIB_IPINTERFACE_ROW));
-            ovsInternalIPConfigured = TRUE;
-            NdisReleaseSpinLock(&ovsIpHelperLock);
+    {
+        PLIST_ENTRY head, link, next;
+
+        ExAcquireResourceSharedLite(&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->internalRow.InterfaceLuid.Info.NetLuidIndex ==
+                    ipRow->InterfaceLuid.Info.NetLuidIndex &&
+                instance->internalRow.InterfaceLuid.Info.IfType ==
+                    ipRow->InterfaceLuid.Info.IfType &&
+                instance->internalRow.InterfaceIndex ==
+                    ipRow->InterfaceIndex) {
+
+                /*
+                 * Update the IP Interface Row
+                 */
+                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,
+                             notificationType == MibAddInstance ?
+                                 "added" : "modified");
+
+                ExReleaseResourceLite(&instance->lock);
+                break;
+            }
+            ExReleaseResourceLite(&instance->lock);
         }
-        OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",
-                     ipRow->InterfaceLuid.Info.NetLuidIndex,
-                     ipRow->InterfaceLuid.Info.IfType,
-                     notificationType == MibAddInstance ? "added" : "modified");
+        ExReleaseResourceLite(&ovsInstanceListLock);
+
         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) {
+    {
+        PLIST_ENTRY head, link, next;
 
-            NdisAcquireSpinLock(&ovsIpHelperLock);
-            ovsInternalIPConfigured = FALSE;
-            NdisReleaseSpinLock(&ovsIpHelperLock);
+        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
+        head = &(ovsInstanceList);
+        LIST_FORALL_SAFE(head, link, next) {
+            POVS_IPHELPER_INSTANCE instance = NULL;
 
-            OvsCleanupIpHelperRequestList();
+            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
+
+            ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
+            if (instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==
+                    ipRow->InterfaceLuid.Info.NetLuidIndex &&
+                instance->internalRow.InterfaceLuid.Info.IfType ==
+                    ipRow->InterfaceLuid.Info.IfType &&
+                instance->internalRow.InterfaceIndex ==
+                    ipRow->InterfaceIndex) {
+
+                instance->isIpConfigured = FALSE;
+                ExReleaseResourceLite(&instance->lock);
+
+                RemoveEntryList(&instance->link);
+                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();
         }
 
         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,25 +617,40 @@  OvsChangeCallbackIpRoute(PVOID context,
 
     case MibParameterNotification:
     case MibDeleteInstance:
+    {
+        PLIST_ENTRY head, link, next;
+        BOOLEAN found = FALSE;
+
         ASSERT(ipRoute);
         ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
         nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
 
-        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,
-                     ipRoute->DestinationPrefix.PrefixLength,
-                     nextHop & 0xff, (nextHop >> 8) & 0xff,
-                     (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
-                     notificationType == MibDeleteInstance ? "deleted" :
-                     "modified");
+        ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);
+        head = &(ovsInstanceList);
+        LIST_FORALL_SAFE(head, link, next) {
+            POVS_IPHELPER_INSTANCE instance = NULL;
 
-        if (ipRoute->InterfaceLuid.Info.NetLuidIndex ==
-            ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
-            ipRoute->InterfaceLuid.Info.IfType ==
-            ovsInternalRow.InterfaceLuid.Info.IfType &&
-            ipRoute->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
+            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
+
+            ExAcquireResourceSharedLite(&instance->lock, TRUE);
+            if (instance->isIpConfigured &&
+                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==
+                    ipRoute->InterfaceLuid.Info.NetLuidIndex &&
+                instance->internalRow.InterfaceLuid.Info.IfType ==
+                    ipRoute->InterfaceLuid.Info.IfType &&
+                instance->internalRow.InterfaceIndex ==
+                    ipRoute->InterfaceIndex) {
+
+                found = TRUE;
+
+                ExReleaseResourceLite(&instance->lock);
+                break;
+            }
+            ExReleaseResourceLite(&instance->lock);
+        }
+        ExReleaseResourceLite(&ovsInstanceListLock);
 
+        if (found) {
             POVS_IPFORWARD_ENTRY ipf;
             LOCK_STATE_EX lockState;
 
@@ -557,8 +660,18 @@  OvsChangeCallbackIpRoute(PVOID context,
                 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,
+                         ipRoute->DestinationPrefix.PrefixLength,
+                         nextHop & 0xff, (nextHop >> 8) & 0xff,
+                         (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
+                         notificationType == MibDeleteInstance ? "deleted" :
+                         "modified");
         }
         break;
+    }
 
     case MibInitialNotification:
         OVS_LOG_INFO("Get Initial notification for IP Route change.");
@@ -579,40 +692,91 @@  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;
+
+        ExAcquireResourceSharedLite(&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 &&
+                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==
+                    unicastRow->InterfaceLuid.Info.NetLuidIndex &&
+                instance->internalRow.InterfaceLuid.Info.IfType ==
+                    unicastRow->InterfaceLuid.Info.IfType &&
+                instance->internalRow.InterfaceIndex ==
+                    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;
+        ExAcquireResourceSharedLite(&ovsInstanceListLock, TRUE);
+        head = &(ovsInstanceList);
+        LIST_FORALL_SAFE(head, link, next) {
+            POVS_IPHELPER_INSTANCE instance = NULL;
+
+            instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
+
+            ExAcquireResourceSharedLite(&instance->lock, TRUE);
+            if (instance->isIpConfigured &&
+                instance->internalRow.InterfaceLuid.Info.NetLuidIndex ==
+                    unicastRow->InterfaceLuid.Info.NetLuidIndex &&
+                instance->internalRow.InterfaceLuid.Info.IfType ==
+                    unicastRow->InterfaceLuid.Info.IfType &&
+                instance->internalRow.InterfaceIndex ==
+                    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 +815,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 +823,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 +846,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 +874,6 @@  OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
 {
 
     PLIST_ENTRY link;
-    POVS_IPFORWARD_ENTRY ipfEntry;
     UINT32 hash;
     ASSERT(prefix->Prefix.si_family == AF_INET);
 
@@ -720,6 +884,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 ==
@@ -735,10 +901,11 @@  static POVS_FWD_ENTRY
 OvsLookupIPFwdEntry(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) {
             return entry;
@@ -770,7 +937,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 +958,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 +967,6 @@  OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
 static POVS_IPFORWARD_ENTRY
 OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
 {
-
     POVS_IPFORWARD_ENTRY entry;
 
     ASSERT(ipRoute);
@@ -876,12 +1044,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 +1065,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);
     }
@@ -973,11 +1143,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);
@@ -991,13 +1162,14 @@  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) {
+           POVS_IPNEIGH_ENTRY ipn;
+           
            ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
            OvsRemoveIPNeighEntry(ipn);
        }
@@ -1017,7 +1189,6 @@  OvsCleanupIpHelperRequestList(VOID)
 {
     LIST_ENTRY list;
     PLIST_ENTRY next, link;
-    POVS_IP_HELPER_REQUEST request;
 
     NdisAcquireSpinLock(&ovsIpHelperLock);
     if (ovsNumIpHelperRequests == 0) {
@@ -1031,6 +1202,8 @@  OvsCleanupIpHelperRequestList(VOID)
     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,16 +1229,38 @@  OvsWakeupIPHelper(VOID)
 }
 
 VOID
-OvsInternalAdapterDown(VOID)
+OvsInternalAdapterDown(UINT32 portNo,
+                       GUID netCfgInstanceId)
 {
-    NdisAcquireSpinLock(&ovsIpHelperLock);
-    ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
-    ovsInternalIPConfigured = FALSE;
-    NdisReleaseSpinLock(&ovsIpHelperLock);
+    PLIST_ENTRY head, link, next;
 
-    OvsCleanupIpHelperRequestList();
+    ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
+    head = &ovsInstanceList;
+    LIST_FORALL_SAFE(head, link, next) {
+        POVS_IPHELPER_INSTANCE instance = NULL;
 
-    OvsCleanupFwdTable();
+        instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
+
+        ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
+        if (instance->portNo == portNo &&
+            IsEqualGUID(&instance->netCfgId, &netCfgInstanceId)) {
+
+            RemoveEntryList(&instance->link);
+
+            ExReleaseResourceLite(&instance->lock);
+
+            OvsIpHelperDeleteInstance(instance);
+            break;
+        }
+        ExReleaseResourceLite(&instance->lock);
+    }
+    ExReleaseResourceLite(&ovsInstanceListLock);
+
+    if (IsListEmpty(&ovsInstanceList)) {
+        OvsCleanupIpHelperRequestList();
+
+        OvsCleanupFwdTable();
+    }
 }
 
 
@@ -1075,9 +1270,6 @@  OvsInternalAdapterUp(UINT32 portNo,
 {
     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) {
@@ -1085,10 +1277,13 @@  OvsInternalAdapterUp(UINT32 portNo,
         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);
-    ovsInternalPortNo = portNo;
     InsertHeadList(&ovsIpHelperRequestList, &request->link);
     ovsNumIpHelperRequests++;
     if (ovsNumIpHelperRequests == 1) {
@@ -1098,58 +1293,134 @@  OvsInternalAdapterUp(UINT32 portNo,
 }
 
 
+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;
+            ExReleaseResourceLite(&instance->lock);
+
+            RemoveEntryList(&instance->link);
+
+            OvsIpHelperDeleteInstance(instance);
+            instance = NULL;
+        }
+    }
+    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;
+        }
 
-    status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
+        status = OvsGetIfEntry(&instance->netCfgId,
+                               &instance->internalRow);
 
-    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;
-    }
+        if (status != STATUS_SUCCESS) {
+            OVS_LOG_ERROR("Fail to get IF entry for internal port with GUID"
+                          "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+                          instance->netCfgId.Data1,
+                          instance->netCfgId.Data2,
+                          instance->netCfgId.Data3,
+                          *(UINT16 *)instance->netCfgId.Data4,
+                          instance->netCfgId.Data4[2],
+                          instance->netCfgId.Data4[3],
+                          instance->netCfgId.Data4[4],
+                          instance->netCfgId.Data4[5],
+                          instance->netCfgId.Data4[6],
+                          instance->netCfgId.Data4[7]);
+            break;
+        }
 
-    status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
-                                    &ovsInternalIPRow);
+        status = OvsGetIPInterfaceEntry(instance->internalRow.InterfaceLuid,
+                                        &instance->internalIPRow);
 
-    if (status == STATUS_SUCCESS) {
-        NdisAcquireSpinLock(&ovsIpHelperLock);
-        ovsInternalIPConfigured = TRUE;
-        NdisReleaseSpinLock(&ovsIpHelperLock);
-    } else {
-        return;
-    }
+        if (status == STATUS_SUCCESS) {
+            instance->isIpConfigured = TRUE;
+        } else {
+            break;
+        }
 
-    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]);
+        status = OvsGetIPEntry(instance->internalRow.InterfaceLuid, &ipEntry);
+        if (status != STATUS_SUCCESS) {
+            OVS_LOG_INFO("Fail to get IP entry for internal port with GUID"
+                         "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+                         instance->netCfgId.Data1,
+                         instance->netCfgId.Data2,
+                         instance->netCfgId.Data3,
+                         *(UINT16 *)instance->netCfgId.Data4,
+                         instance->netCfgId.Data4[2],
+                         instance->netCfgId.Data4[3],
+                         instance->netCfgId.Data4[4],
+                         instance->netCfgId.Data4[5],
+                         instance->netCfgId.Data4[6],
+                         instance->netCfgId.Data4[7]);
+            break;
+        }
+
+        ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
+        InsertHeadList(&ovsInstanceList, &instance->link);
+        ExReleaseResourceLite(&ovsInstanceListLock);
+
+        error = FALSE;
+    } while (error);
+
+    OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
+    if (error) {
+        OvsIpHelperDeleteInstance(instance);
     }
 }
 
@@ -1157,15 +1428,11 @@  OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
 static NTSTATUS
 OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
 {
-
-    NdisAcquireSpinLock(&ovsIpHelperLock);
-
-    if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO ||
-        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) {
@@ -1223,6 +1490,7 @@  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,
                                 &fwdInfo);
@@ -1237,10 +1505,16 @@  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);
+    status = OvsGetRoute(&dst, &ipRoute, &src, &instance);
     if (status != STATUS_SUCCESS) {
+        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;
     }
+
+    ExAcquireResourceSharedLite(&instance->lock, TRUE);
     srcAddr = src.Ipv4.sin_addr.s_addr;
 
     /* find IPNeigh */
@@ -1253,13 +1527,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;
     }
 
@@ -1275,6 +1552,7 @@  fwd_request_done:
         ipf = OvsCreateIPForwardEntry(&ipRoute);
         if (ipf == NULL) {
             NdisReleaseRWLock(ovsTableLock, &lockState);
+            ExReleaseResourceLite(&instance->lock);
             status = STATUS_INSUFFICIENT_RESOURCES;
             goto fwd_handle_nbl;
         }
@@ -1292,9 +1570,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;
             }
@@ -1308,13 +1587,14 @@  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;
     }
@@ -1324,6 +1604,7 @@  fwd_request_done:
      */
     OvsAddIPFwdCache(fwdEntry, ipf, ipn);
     NdisReleaseRWLock(ovsTableLock, &lockState);
+    ExReleaseResourceLite(&instance->lock);
 
 fwd_handle_nbl:
 
@@ -1426,12 +1707,17 @@  OvsUpdateIPNeighEntry(UINT32 ipAddr,
 
 
 static VOID
-OvsHandleIPNeighTimeout(UINT32 ipAddr)
+OvsHandleIPNeighTimeout(UINT32 ipAddr,
+                        PVOID context)
 {
     MIB_IPNET_ROW2 ipNeigh;
     NTSTATUS status;
+    POVS_IPHELPER_INSTANCE instance = (POVS_IPHELPER_INSTANCE)context;
 
-    status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
+    ExAcquireResourceSharedLite(&instance->lock, TRUE);
+    status = OvsGetOrResolveIPNeigh(instance->internalRow,
+                                    ipAddr, &ipNeigh);
+    ExReleaseResourceLite(&instance->lock);
 
     OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
 }
@@ -1439,13 +1725,13 @@  OvsHandleIPNeighTimeout(UINT32 ipAddr)
 
 /*
  *----------------------------------------------------------------------------
- *  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
@@ -1455,7 +1741,7 @@  OvsStartIpHelper(PVOID data)
     POVS_IP_HELPER_REQUEST req;
     POVS_IPNEIGH_ENTRY ipn;
     PLIST_ENTRY link;
-    UINT64   timeVal, timeout;
+    UINT64 timeVal, timeout;
 
     OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
 
@@ -1504,7 +1790,7 @@  OvsStartIpHelper(PVOID data)
 
             NdisReleaseSpinLock(&ovsIpHelperLock);
 
-            OvsHandleIPNeighTimeout(ipAddr);
+            OvsHandleIPNeighTimeout(ipAddr, ipn->context);
 
             NdisAcquireSpinLock(&ovsIpHelperLock);
         }
@@ -1550,12 +1836,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;
-
-    ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
-
     InitializeListHead(&ovsSortedIPNeighList);
 
     ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
@@ -1567,6 +1847,9 @@  OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
     ipRouteNotificationHandle = NULL;
     unicastIPNotificationHandle = NULL;
 
+    ExInitializeResourceLite(&ovsInstanceListLock);
+    InitializeListHead(&ovsInstanceList);
+
     if (ovsFwdHashTable == NULL ||
         ovsRouteHashTable == NULL ||
         ovsNeighHashTable == NULL ||
@@ -1587,7 +1870,6 @@  OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
         InitializeListHead(&ovsNeighHashTable[i]);
     }
 
-
     KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
                       FALSE);
     status = OvsRegisterChangeNotification();
@@ -1626,6 +1908,7 @@  init_cleanup:
             NdisFreeRWLock(ovsTableLock);
             ovsTableLock = NULL;
         }
+        ExDeleteResourceLite(&ovsInstanceListLock);
         NdisFreeSpinLock(&ovsIpHelperLock);
     }
     return STATUS_SUCCESS;
@@ -1652,6 +1935,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 19702a2..4d8d034 100644
--- a/datapath-windows/ovsext/IpHelper.h
+++ b/datapath-windows/ovsext/IpHelper.h
@@ -41,6 +41,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 {
@@ -94,13 +95,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;
 
@@ -115,7 +120,7 @@  NTSTATUS OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle);
 VOID OvsCleanupIpHelper(VOID);
 
 VOID OvsInternalAdapterUp(UINT32 portNo, GUID *netCfgInstanceId);
-VOID OvsInternalAdapterDown(VOID);
+VOID OvsInternalAdapterDown(UINT32 portNo, GUID netCfgInstanceId);
 
 NTSTATUS OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl, UINT32 inPort,
                                const PVOID tunnelKey,
diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index 65a4134..dbd9a50 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -525,7 +525,7 @@  HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
     OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
 
     if (isInternalPort) {
-        OvsInternalAdapterDown();
+        OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);
     }
 
 done:
@@ -1160,7 +1160,7 @@  OvsRemoveAndDeleteVport(PVOID usrParamsContext,
             if (hvDelete && vport->isAbsentOnHv == FALSE) {
                 switchContext->internalPortId = 0;
                 switchContext->internalVport = NULL;
-                OvsInternalAdapterDown();
+                OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);
             }
             hvSwitchPort = TRUE;
         }