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

Message ID 1441199397-20449-2-git-send-email-svinturis@cloudbasesolutions.com
State Deferred
Headers show

Commit Message

Sorin Vinturis Sept. 30, 2015, 1:29 p.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(-)

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 baab056..43aec75 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -524,7 +524,7 @@  HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
     OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
 
     if (isInternalPort) {
-        OvsInternalAdapterDown();
+        OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);
     }
 
 done:
@@ -1168,7 +1168,7 @@  OvsRemoveAndDeleteVport(PVOID usrParamsContext,
             if (hvDelete && vport->isAbsentOnHv == FALSE) {
                 switchContext->internalPortId = 0;
                 switchContext->internalVport = NULL;
-                OvsInternalAdapterDown();
+                OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId);
             }
             hvSwitchPort = TRUE;
         }