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