datapath-windows: Fix various Geneve bugs
[cascardo/ovs.git] / datapath-windows / ovsext / Vport.c
index ef21fca..22741db 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"
+#include "Geneve.h"
 
 #ifdef OVS_DBG_MOD
 #undef OVS_DBG_MOD
@@ -289,7 +292,15 @@ HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
      * delete will delete the vport.
     */
     if (vport) {
+        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, TRUE, FALSE);
+        OvsPostEvent(&event);
     } else {
         OVS_LOG_WARN("Vport not present.");
     }
@@ -327,9 +338,8 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
         goto done;
     }
 
-    if (nicParam->NicType == NdisSwitchNicTypeInternal ||
-        (nicParam->NicType == NdisSwitchNicTypeExternal &&
-         nicParam->NicIndex != 0)) {
+    if (OvsIsInternalNIC(nicParam->NicType) ||
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
         GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
     }
 
@@ -339,44 +349,22 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
      * 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;
         }
     }
 
@@ -390,9 +378,8 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
         goto add_nic_done;
     }
     OvsInitVportWithNicParam(switchContext, vport, nicParam);
-    if (nicParam->NicType == NdisSwitchNicTypeInternal ||
-        (nicParam->NicType == NdisSwitchNicTypeExternal &&
-         nicParam->NicIndex != 0)) {
+    if (OvsIsInternalNIC(nicParam->NicType) ||
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
         RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
                       sizeof portFriendlyName);
     }
@@ -418,7 +405,6 @@ HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
 {
     LOCK_STATE_EX lockState;
     POVS_VPORT_ENTRY vport;
-    UINT32 portNo;
 
     VPORT_NIC_ENTER(nicParam);
 
@@ -444,7 +430,6 @@ HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
 
     vport->ovsState = OVS_STATE_CONNECTED;
     vport->nicState = NdisSwitchNicStateConnected;
-    portNo = vport->portNo;
 
     NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
@@ -470,6 +455,8 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     LOCK_STATE_EX lockState;
     UINT32 event = 0;
     IF_COUNTED_STRING portFriendlyName = {0};
+    BOOLEAN nameChanged = FALSE;
+    BOOLEAN aliasLookup = FALSE;
 
     VPORT_NIC_ENTER(nicParam);
 
@@ -483,9 +470,9 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
 
     /* GetNICAlias() must be called outside of a lock. */
     if (nicParam->NicType == NdisSwitchNicTypeInternal ||
-        (nicParam->NicType == NdisSwitchNicTypeExternal &&
-         nicParam->NicIndex != 0)) {
+        OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
         GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
+        aliasLookup = TRUE;
     }
 
     NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
@@ -502,8 +489,15 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     case NdisSwitchNicTypeInternal:
         RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
                       sizeof (GUID));
-        RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
-                      sizeof portFriendlyName);
+        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:
@@ -536,6 +530,17 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
     }
     vport->numaNodeId = nicParam->NumaNodeId;
 
+    if (nameChanged) {
+        OVS_EVENT_ENTRY evt;
+        evt.portNo = vport->portNo;
+        evt.ovsType = vport->ovsType;
+        evt.upcallPid = vport->upcallPid;
+        RtlCopyMemory(&evt.ovsName, &vport->ovsName, sizeof evt.ovsName);
+        evt.type = OVS_EVENT_LINK_DOWN;
+        OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
+        OvsPostEvent(&evt);
+    }
+
     NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
 
     /*
@@ -598,14 +603,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();
@@ -650,8 +656,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);
     }
 
@@ -684,9 +690,9 @@ OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
 
 
 POVS_VPORT_ENTRY
-OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
-                            UINT16 dstPort,
-                            OVS_VPORT_TYPE ovsPortType)
+OvsFindTunnelVportByDstPortAndType(POVS_SWITCH_CONTEXT switchContext,
+                                   UINT16 dstPort,
+                                   OVS_VPORT_TYPE ovsPortType)
 {
     POVS_VPORT_ENTRY vport;
     PLIST_ENTRY head, link;
@@ -703,6 +709,60 @@ OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
     return NULL;
 }
 
+POVS_VPORT_ENTRY
+OvsFindTunnelVportByDstPortAndNWProto(POVS_SWITCH_CONTEXT switchContext,
+                                      UINT16 dstPort,
+                                      UINT8 nwProto)
+{
+    POVS_VPORT_ENTRY vport;
+    PLIST_ENTRY head, link;
+    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 (GetPortFromPriv(vport) == dstPort) {
+            switch (nwProto) {
+            case IPPROTO_UDP:
+                if (vport->ovsType != OVS_VPORT_TYPE_GENEVE &&
+                    vport->ovsType != OVS_VPORT_TYPE_VXLAN) {
+                    continue;
+                }
+                break;
+            case IPPROTO_TCP:
+                if (vport->ovsType != OVS_VPORT_TYPE_STT) {
+                    continue;
+                }
+                break;
+            case IPPROTO_GRE:
+                break;
+            default:
+                continue;
+            }
+            return vport;
+        }
+    }
+    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,
@@ -907,14 +967,14 @@ OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
     UNREFERENCED_PARAMETER(switchContext);
 
     RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
-                  sizeof (nicParam->PermanentMacAddress));
+                  sizeof (vport->permMacAddress));
     RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
-                  sizeof (nicParam->CurrentMacAddress));
+                  sizeof (vport->currMacAddress));
 
     if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
         nicParam->NicType == NdisSwitchNicTypeEmulated) {
         RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
-                      sizeof (nicParam->VMMacAddress));
+                      sizeof (vport->vmMacAddress));
         RtlCopyMemory(&vport->vmName, &nicParam->VmName,
                       sizeof (nicParam->VmName));
     } else {
@@ -926,6 +986,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) {
@@ -985,6 +1046,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:
     {
@@ -1015,6 +1077,9 @@ OvsInitTunnelVport(PVOID userContext,
     case OVS_VPORT_TYPE_STT:
         status = OvsInitSttTunnel(vport, dstPort);
         break;
+    case OVS_VPORT_TYPE_GENEVE:
+        status = OvsInitGeneveTunnel(vport, dstPort);
+        break;
     default:
         ASSERT(0);
     }
@@ -1048,10 +1113,10 @@ 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;
+    NTSTATUS status;
+    WCHAR interfaceName[IF_MAX_STRING_SIZE + 1];
+    NET_LUID interfaceLuid;
+    size_t len;
 
     status = ConvertInterfaceGuidToLuid(netCfgInstanceId,
                                         &interfaceLuid);
@@ -1155,8 +1220,10 @@ 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:
+    case OVS_VPORT_TYPE_GENEVE:
     {
         UINT16 dstPort = GetPortFromPriv(vport);
         hash = OvsJhashBytes(&dstPort,
@@ -1240,10 +1307,14 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
             return status;
         }
     }
+    case OVS_VPORT_TYPE_GENEVE:
+        OvsCleanupGeneveTunnel(vport);
+        break;
     case OVS_VPORT_TYPE_STT:
         OvsCleanupSttTunnel(vport);
         break;
     case OVS_VPORT_TYPE_GRE:
+        OvsCleanupGreTunnel(vport);
         break;
     case OVS_VPORT_TYPE_NETDEV:
         if (vport->isExternal) {
@@ -1300,8 +1371,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
         InitializeListHead(&vport->ovsNameLink);
         RemoveEntryList(&vport->portNoLink);
         InitializeListHead(&vport->portNoLink);
-        if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
-            OVS_VPORT_TYPE_STT == vport->ovsType) {
+        if (OvsIsTunnelVportType(vport->ovsType)) {
             RemoveEntryList(&vport->tunnelVportLink);
             InitializeListHead(&vport->tunnelVportLink);
         }
@@ -1611,7 +1681,7 @@ OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
                                                  OVS_MAX_PORT_NAME_LENGTH);
         if (status != STATUS_SUCCESS) {
             OVS_LOG_INFO("Fail to convert NIC name.");
-            extInfo->vmUUID[0] = 0;
+            extInfo->name[0] = 0;
         }
 
         status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
@@ -1700,8 +1770,9 @@ cleanup:
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
             usrParamsCtx->outputBuffer;
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 
     return STATUS_SUCCESS;
@@ -2059,8 +2130,9 @@ Cleanup:
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
             usrParamsCtx->outputBuffer;
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 
     return STATUS_SUCCESS;
@@ -2190,13 +2262,23 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
         if (OvsIsTunnelVportType(portType)) {
             UINT16 transportPortDest = 0;
+            UINT8 nwProto = IPPROTO_NONE;
+            POVS_VPORT_ENTRY dupVport;
 
             switch (portType) {
+            case OVS_VPORT_TYPE_GRE:
+                nwProto = IPPROTO_GRE;
+                break;
             case OVS_VPORT_TYPE_VXLAN:
                 transportPortDest = VXLAN_UDP_PORT;
+                nwProto = IPPROTO_UDP;
+                break;
+            case OVS_VPORT_TYPE_GENEVE:
+                transportPortDest = GENEVE_UDP_PORT;
                 break;
             case OVS_VPORT_TYPE_STT:
                 transportPortDest = STT_TCP_PORT;
+                nwProto = IPPROTO_TCP;
                 break;
             default:
                 nlError = NL_ERROR_INVAL;
@@ -2211,6 +2293,22 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                 }
             }
 
+            /*
+             * We don't allow two tunnel ports on identical N/W protocol and
+             * L4 port number. This is applicable even if the two ports are of
+             * different tunneling types.
+             */
+            dupVport =
+                OvsFindTunnelVportByDstPortAndNWProto(gOvsSwitchContext,
+                                                      transportPortDest,
+                                                      nwProto);
+            if (dupVport) {
+                OVS_LOG_ERROR("Vport for N/W proto and port already exists,"
+                    " type: %u, dst port: %u, name: %s", dupVport->ovsType,
+                    transportPortDest, dupVport->ovsName);
+                goto Cleanup;
+            }
+
             status = OvsInitTunnelVport(usrParamsCtx,
                                         vport,
                                         portType,
@@ -2285,6 +2383,8 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                                    gOvsSwitchContext->dpNo);
 
     *replyLen = msgOut->nlMsg.nlmsgLen;
+    OVS_LOG_INFO("Created new vport, name: %s, type: %u", vport->ovsName,
+                 vport->ovsType);
 
 Cleanup:
     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
@@ -2303,6 +2403,9 @@ Cleanup:
                     case OVS_VPORT_TYPE_STT:
                         OvsCleanupSttTunnel(vport);
                         break;
+                    case OVS_VPORT_TYPE_GENEVE:
+                        OvsCleanupGeneveTunnel(vport);
+                        break;
                     default:
                         ASSERT(!"Invalid tunnel port type");
                     }
@@ -2311,8 +2414,9 @@ Cleanup:
             OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
         }
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 
     return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
@@ -2421,8 +2525,9 @@ Cleanup:
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
             usrParamsCtx->outputBuffer;
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 
     return STATUS_SUCCESS;
@@ -2513,8 +2618,9 @@ Cleanup:
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
             usrParamsCtx->outputBuffer;
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 
     return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
@@ -2548,9 +2654,9 @@ OvsTunnelVportPendingRemove(PVOID context,
             *replyLen = msgOut->nlMsg.nlmsgLen;
         } else {
             POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
-
-            NlBuildErrorMsg(msgIn, msgError, nlError);
-            *replyLen = msgError->nlMsg.nlmsgLen;
+            ASSERT(msgError);
+            NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+            ASSERT(*replyLen != 0);
         }
     }
 
@@ -2689,12 +2795,13 @@ OvsTunnelVportPendingInit(PVOID context,
     } while (error);
 
     if (error) {
-        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) msgOut;
+        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
 
         OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
         OvsFreeMemory(vport);
 
-        NlBuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
+        ASSERT(msgError);
+        NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
+        ASSERT(*replyLen != 0);
     }
 }