datapath-windows: Add GRE TEB support for windows datapath
[cascardo/ovs.git] / datapath-windows / ovsext / Vport.c
index 48845da..7b0103d 100644 (file)
  */
 
 #include "precomp.h"
+
+#include "Datapath.h"
+#include "Event.h"
+#include "Gre.h"
+#include "IpHelper.h"
 #include "Jhash.h"
+#include "Oid.h"
+#include "Stt.h"
 #include "Switch.h"
-#include "Vport.h"
-#include "Event.h"
 #include "User.h"
+#include "Vport.h"
 #include "Vxlan.h"
-#include "Stt.h"
-#include "IpHelper.h"
-#include "Oid.h"
-#include "Datapath.h"
 
 #ifdef OVS_DBG_MOD
 #undef OVS_DBG_MOD
@@ -94,7 +96,8 @@ static VOID OvsTunnelVportPendingInit(PVOID context,
 static VOID OvsTunnelVportPendingRemove(PVOID context,
                                         NTSTATUS status,
                                         UINT32 *replyLen);
-static VOID AssignNicNameSpecial(POVS_VPORT_ENTRY vport);
+static NTSTATUS GetNICAlias(GUID *netCfgInstanceId,
+                            IF_COUNTED_STRING *portFriendlyName);
 
 /*
  * --------------------------------------------------------------------------
@@ -311,7 +314,7 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
 {
     POVS_VPORT_ENTRY vport;
     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
-
+    IF_COUNTED_STRING portFriendlyName = {0};
     LOCK_STATE_EX lockState;
 
     VPORT_NIC_ENTER(nicParam);
@@ -326,50 +329,33 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
         goto done;
     }
 
+    if (OvsIsInternalNIC(nicParam->NicType) ||
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
+        GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
+    }
+
     NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
     /*
      * There can be one or more NICs for the external port. We create a vport
      * structure for each such NIC, and each NIC inherits a lot of properties
      * from the parent external port.
      */
-    if (nicParam->NicType == NdisSwitchNicTypeExternal &&
-        nicParam->NicIndex != 0) {
+    if (OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
+        NDIS_SWITCH_PORT_PARAMETERS portParam;
         POVS_VPORT_ENTRY virtExtVport =
             (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
 
-        vport = OvsFindVportByPortIdAndNicIndex(switchContext,
-                                                nicParam->PortId,
-                                                nicParam->NicIndex);
-        if (vport == NULL) {
-            NDIS_SWITCH_PORT_PARAMETERS portParam;
-            /* Find by interface name */
-            WCHAR interfaceName[IF_MAX_STRING_SIZE] = { 0 };
-            NET_LUID interfaceLuid = { 0 };
-            size_t len = 0;
-            status = ConvertInterfaceGuidToLuid(&nicParam->NetCfgInstanceId,
-                                                &interfaceLuid);
-            if (status == STATUS_SUCCESS) {
-                status = ConvertInterfaceLuidToAlias(&interfaceLuid,
-                                                     interfaceName,
-                                                     IF_MAX_STRING_SIZE + 1);
-                if (status == STATUS_SUCCESS) {
-                    RtlStringCbLengthW(interfaceName,
-                                       IF_MAX_STRING_SIZE,
-                                       &len);
-                    vport = OvsFindVportByHvNameW(switchContext,
-                                                  interfaceName,
-                                                  len);
-                }
-            }
-
-            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;
-            }
+        ASSERT(virtExtVport);
+        ASSERT(OvsFindVportByPortIdAndNicIndex(switchContext,
+                                               nicParam->PortId,
+                                               nicParam->NicIndex) == NULL);
+        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;
         }
     }
 
@@ -383,20 +369,14 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
         goto add_nic_done;
     }
     OvsInitVportWithNicParam(switchContext, vport, nicParam);
-    if (nicParam->NicType == NdisSwitchNicTypeInternal ||
-        (nicParam->NicType == NdisSwitchNicTypeExternal &&
-         nicParam->NicIndex != 0)) {
-        AssignNicNameSpecial(vport);
+    if (OvsIsInternalNIC(nicParam->NicType) ||
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
+        RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
+                      sizeof portFriendlyName);
     }
 
 add_nic_done:
     NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
-    if (status == STATUS_SUCCESS &&
-        (vport->portType == NdisSwitchPortTypeInternal ||
-         (vport->portType == NdisSwitchPortTypeExternal &&
-          nicParam->NicIndex != 0))) {
-        AssignNicNameSpecial(vport);
-    }
 
 done:
     VPORT_NIC_EXIT(nicParam);
@@ -447,7 +427,7 @@ HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
     NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
     if (nicParam->NicType == NdisSwitchNicTypeInternal) {
-        OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
+        OvsInternalAdapterUp(&nicParam->NetCfgInstanceId);
     }
 
 done:
@@ -467,6 +447,9 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     POVS_VPORT_ENTRY vport;
     LOCK_STATE_EX lockState;
     UINT32 event = 0;
+    IF_COUNTED_STRING portFriendlyName = {0};
+    BOOLEAN nameChanged = FALSE;
+    BOOLEAN aliasLookup = FALSE;
 
     VPORT_NIC_ENTER(nicParam);
 
@@ -478,6 +461,13 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
         goto update_nic_done;
     }
 
+    /* GetNICAlias() must be called outside of a lock. */
+    if (nicParam->NicType == NdisSwitchNicTypeInternal ||
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
+        GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
+        aliasLookup = TRUE;
+    }
+
     NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
     vport = OvsFindVportByPortIdAndNicIndex(switchContext,
                                             nicParam->PortId,
@@ -492,7 +482,15 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     case NdisSwitchNicTypeInternal:
         RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
                       sizeof (GUID));
-        AssignNicNameSpecial(vport);
+        if (aliasLookup) {
+            if (RtlCompareMemory(&vport->portFriendlyName,
+                    &portFriendlyName, vport->portFriendlyName.Length) !=
+                    vport->portFriendlyName.Length) {
+                RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
+                    sizeof portFriendlyName);
+                nameChanged = TRUE;
+            }
+        }
         break;
     case NdisSwitchNicTypeSynthetic:
     case NdisSwitchNicTypeEmulated:
@@ -525,6 +523,17 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     }
     vport->numaNodeId = nicParam->NumaNodeId;
 
+    if (nameChanged) {
+        OVS_EVENT_ENTRY event;
+        event.portNo = vport->portNo;
+        event.ovsType = vport->ovsType;
+        event.upcallPid = vport->upcallPid;
+        RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
+        event.type = OVS_EVENT_LINK_DOWN;
+        OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
+        OvsPostEvent(&event);
+    }
+
     NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
     /*
@@ -587,14 +596,15 @@ HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
     RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
     event.type = OVS_EVENT_LINK_DOWN;
 
-    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
-
     /*
      * Delete the port from the hash tables accessible to userspace. After this
      * point, userspace should not be able to access this port.
      */
-    OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
-    OvsPostEvent(&event);
+    if (OvsIsRealExternalVport(vport)) {
+        OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
+        OvsPostEvent(&event);
+    }
+    NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
     if (isInternalPort) {
         OvsInternalAdapterDown();
@@ -639,8 +649,8 @@ HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
     vport->nicState = NdisSwitchNicStateUnknown;
     vport->ovsState = OVS_STATE_PORT_CREATED;
 
-    if (vport->portType == NdisSwitchPortTypeExternal &&
-        vport->nicIndex != 0) {
+    if (OvsIsRealExternalVport(vport)) {
+        /* This vport was created in HvCreateNic(). */
         OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
     }
 
@@ -692,6 +702,24 @@ OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
     return NULL;
 }
 
+POVS_VPORT_ENTRY
+OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT switchContext,
+                             OVS_VPORT_TYPE ovsPortType)
+{
+    POVS_VPORT_ENTRY vport;
+    PLIST_ENTRY head, link;
+    UINT16 dstPort = 0;
+    UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
+                                OVS_HASH_BASIS);
+    head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
+    LIST_FORALL(head, link) {
+        vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
+        if (vport->ovsType == ovsPortType) {
+            return vport;
+        }
+    }
+    return NULL;
+}
 
 POVS_VPORT_ENTRY
 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
@@ -915,6 +943,7 @@ OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
     vport->mtu = nicParam->MTU;
     vport->nicState = nicParam->NicState;
     vport->nicIndex = nicParam->NicIndex;
+    vport->nicType = nicParam->NicType;
     vport->numaNodeId = nicParam->NumaNodeId;
 
     switch (vport->nicState) {
@@ -974,6 +1003,7 @@ OvsInitTunnelVport(PVOID userContext,
     vport->ovsState = OVS_STATE_PORT_CREATED;
     switch (ovsType) {
     case OVS_VPORT_TYPE_GRE:
+        status = OvsInitGreTunnel(vport);
         break;
     case OVS_VPORT_TYPE_VXLAN:
     {
@@ -1033,18 +1063,16 @@ OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
  * Hyper-V, is overwritten with the interface alias name.
  * --------------------------------------------------------------------------
  */
-static VOID
-AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
+static NTSTATUS
+GetNICAlias(GUID *netCfgInstanceId,
+            IF_COUNTED_STRING *portFriendlyName)
 {
     NTSTATUS status = STATUS_SUCCESS;
     WCHAR interfaceName[IF_MAX_STRING_SIZE] = { 0 };
     NET_LUID interfaceLuid = { 0 };
     size_t len = 0;
 
-    ASSERT(vport->portType == NdisSwitchPortTypeExternal ||
-           vport->portType == NdisSwitchPortTypeInternal);
-
-    status = ConvertInterfaceGuidToLuid(&vport->netCfgInstanceId,
+    status = ConvertInterfaceGuidToLuid(netCfgInstanceId,
                                         &interfaceLuid);
     if (status == STATUS_SUCCESS) {
         /*
@@ -1054,26 +1082,21 @@ AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
         status = ConvertInterfaceLuidToAlias(&interfaceLuid, interfaceName,
                                              IF_MAX_STRING_SIZE + 1);
         if (status == STATUS_SUCCESS) {
-            if (vport->portType == NdisSwitchPortTypeExternal &&
-                vport->nicIndex == 0) {
-                RtlStringCbPrintfW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
-                                   L"%s.virtualAdapter", interfaceName);
-            } else {
-                RtlStringCbPrintfW(vport->portFriendlyName.String,
-                                   IF_MAX_STRING_SIZE, L"%s", interfaceName);
-            }
-
-            RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
+            RtlStringCbPrintfW(portFriendlyName->String,
+                               IF_MAX_STRING_SIZE, L"%s", interfaceName);
+            RtlStringCbLengthW(portFriendlyName->String, IF_MAX_STRING_SIZE,
                                &len);
-            vport->portFriendlyName.Length = (USHORT)len;
+            portFriendlyName->Length = (USHORT)len;
         } else {
-            OVS_LOG_INFO("Fail to convert interface LUID to alias, status: %x",
+            OVS_LOG_ERROR("Fail to convert interface LUID to alias, status: %x",
                 status);
         }
     } else {
-        OVS_LOG_INFO("Fail to convert interface GUID to LUID, status: %x",
+        OVS_LOG_ERROR("Fail to convert interface GUID to LUID, status: %x",
                       status);
     }
+
+    return status;
 }
 
 
@@ -1151,6 +1174,7 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
     UINT32 hash;
 
     switch(vport->ovsType) {
+    case OVS_VPORT_TYPE_GRE:
     case OVS_VPORT_TYPE_VXLAN:
     case OVS_VPORT_TYPE_STT:
     {
@@ -1240,6 +1264,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
         OvsCleanupSttTunnel(vport);
         break;
     case OVS_VPORT_TYPE_GRE:
+        OvsCleanupGreTunnel(vport);
         break;
     case OVS_VPORT_TYPE_NETDEV:
         if (vport->isExternal) {
@@ -1297,7 +1322,8 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
         RemoveEntryList(&vport->portNoLink);
         InitializeListHead(&vport->portNoLink);
         if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
-            OVS_VPORT_TYPE_STT == vport->ovsType) {
+            OVS_VPORT_TYPE_STT == vport->ovsType   ||
+            OVS_VPORT_TYPE_GRE == vport->ovsType) {
             RemoveEntryList(&vport->tunnelVportLink);
             InitializeListHead(&vport->tunnelVportLink);
         }
@@ -2188,6 +2214,8 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
             UINT16 transportPortDest = 0;
 
             switch (portType) {
+            case OVS_VPORT_TYPE_GRE:
+                break;
             case OVS_VPORT_TYPE_VXLAN:
                 transportPortDest = VXLAN_UDP_PORT;
                 break;