Index: trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- trunk/src/VBox/Main/Makefile.kmk	(revision 93311)
+++ trunk/src/VBox/Main/Makefile.kmk	(revision 93312)
@@ -1096,6 +1096,9 @@
 
 # Experimental cloud support
-ifdef VBOX_WITH_CLOUD_NET
- VBoxC_DEFS += VBOX_WITH_CLOUD_NET
+if defined(VBOX_WITH_CLOUD_NET)
+ if defined(VBOX_WITH_LIBSSH)
+  VBoxC_SDKS += VBOX_SSH VBOX_OPENSSL
+  VBoxC_DEFS += LIBSSH_STATIC VBOX_WITH_LIBSSH
+ endif
  VBoxC_SOURCES += src-client/CloudGateway.cpp
 endif
Index: trunk/src/VBox/Main/include/CloudGateway.h
===================================================================
--- trunk/src/VBox/Main/include/CloudGateway.h	(revision 93311)
+++ trunk/src/VBox/Main/include/CloudGateway.h	(revision 93312)
@@ -25,7 +25,7 @@
 {
     Bstr    mTargetVM;
-    Utf8Str mGatewayVM;
     Utf8Str mGatewayInstanceId;
     Utf8Str mPublicSshKey;
+    Utf8Str mPrivateSshKey;
     Bstr    mCloudProvider;
     Bstr    mCloudProfile;
@@ -39,14 +39,10 @@
     HRESULT setLocalMacAddress(const Utf8Str& mac);
 
-    Utf8Str getCloudMacAddressWithoutColons() const;
-    Utf8Str getLocalMacAddressWithoutColons() const;
-    Utf8Str getLocalMacAddressWithColons() const;
-
     GatewayInfo() {}
 
     GatewayInfo(const GatewayInfo& other)
-        : mGatewayVM(other.mGatewayVM),
-          mGatewayInstanceId(other.mGatewayInstanceId),
+        : mGatewayInstanceId(other.mGatewayInstanceId),
           mPublicSshKey(other.mPublicSshKey),
+          mPrivateSshKey(other.mPrivateSshKey),
           mCloudProvider(other.mCloudProvider),
           mCloudProfile(other.mCloudProfile),
@@ -60,7 +56,7 @@
     GatewayInfo& operator=(const GatewayInfo& other)
     {
-        mGatewayVM = other.mGatewayVM;
         mGatewayInstanceId = other.mGatewayInstanceId;
         mPublicSshKey = other.mPublicSshKey;
+        mPrivateSshKey = other.mPrivateSshKey;
         mCloudProvider = other.mCloudProvider;
         mCloudProfile = other.mCloudProfile;
@@ -75,7 +71,7 @@
     void setNull()
     {
-        mGatewayVM.setNull();
         mGatewayInstanceId.setNull();
         mPublicSshKey.setNull();
+        mPrivateSshKey.setNull();
         mCloudProvider.setNull();
         mCloudProfile.setNull();
@@ -90,6 +86,7 @@
 class CloudNetwork;
 
-HRESULT startGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& pGateways);
-HRESULT stopGateways(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways);
+HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& pGateways);
+HRESULT stopCloudGateway(ComPtr<IVirtualBox> virtualBox, GatewayInfo& gateways);
+HRESULT generateKeys(GatewayInfo& gateways);
 
 #endif /* !MAIN_INCLUDED_CloudGateway_h */
Index: trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 93311)
+++ trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 93312)
@@ -1086,5 +1086,5 @@
 
 #ifdef VBOX_WITH_CLOUD_NET
-    GatewayInfo mGateways;
+    GatewayInfo mGateway;
 #endif /* VBOX_WITH_CLOUD_NET */
 
Index: trunk/src/VBox/Main/src-client/CloudGateway.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/CloudGateway.cpp	(revision 93311)
+++ trunk/src/VBox/Main/src-client/CloudGateway.cpp	(revision 93312)
@@ -37,4 +37,15 @@
 #include <iprt/vfs.h>
 #include <iprt/uri.h>
+#ifdef DEBUG
+#include <iprt/file.h>
+#include <VBox/com/utils.h>
+#endif
+
+#ifdef VBOX_WITH_LIBSSH
+/* Prevent inclusion of Winsock2.h */
+#define _WINSOCK2API_
+#include <libssh/libssh.h>
+#endif /* VBOX_WITH_LIBSSH */
+
 
 static HRESULT setMacAddress(const Utf8Str& str, RTMAC& mac)
@@ -49,4 +60,5 @@
 }
 
+
 HRESULT GatewayInfo::setCloudMacAddress(const Utf8Str& mac)
 {
@@ -54,4 +66,5 @@
 }
 
+
 HRESULT GatewayInfo::setLocalMacAddress(const Utf8Str& mac)
 {
@@ -59,22 +72,4 @@
 }
 
-Utf8Str GatewayInfo::getCloudMacAddressWithoutColons() const
-{
-    return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",
-                      mCloudMacAddress.au8[0], mCloudMacAddress.au8[1], mCloudMacAddress.au8[2],
-                      mCloudMacAddress.au8[3], mCloudMacAddress.au8[4], mCloudMacAddress.au8[5]);
-}
-
-Utf8Str GatewayInfo::getLocalMacAddressWithoutColons() const
-{
-    return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",
-                      mLocalMacAddress.au8[0], mLocalMacAddress.au8[1], mLocalMacAddress.au8[2],
-                      mLocalMacAddress.au8[3], mLocalMacAddress.au8[4], mLocalMacAddress.au8[5]);
-}
-
-Utf8Str GatewayInfo::getLocalMacAddressWithColons() const
-{
-    return Utf8StrFmt("%RTmac", &mLocalMacAddress);
-}
 
 class CloudError
@@ -89,4 +84,5 @@
     Utf8Str mText;
 };
+
 
 static void handleErrors(HRESULT hrc, const char *pszFormat, ...)
@@ -104,4 +100,5 @@
 }
 
+
 class CloudClient
 {
@@ -110,6 +107,6 @@
     ~CloudClient() {};
 
-    void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateways);
-    void stopCloudGateway(const GatewayInfo& gateways);
+    void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway);
+    void stopCloudGateway(const GatewayInfo& gateway);
 
 private:
@@ -119,4 +116,5 @@
     ComPtr<ICloudClient>          mClient;
 };
+
 
 CloudClient::CloudClient(ComPtr<IVirtualBox> virtualBox, const Bstr& strProvider, const Bstr& strProfile)
@@ -132,9 +130,10 @@
 }
 
-void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateways)
+
+void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway)
 {
     ComPtr<IProgress> progress;
     ComPtr<ICloudNetworkGatewayInfo> gatewayInfo;
-    HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateways.mPublicSshKey).raw(),
+    HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateway.mPublicSshKey).raw(),
                                                     gatewayInfo.asOutParam(), progress.asOutParam());
     handleErrors(hrc, "Failed to launch compute instance");
@@ -145,26 +144,27 @@
     hrc = gatewayInfo->COMGETTER(InstanceId)(instanceId.asOutParam());
     handleErrors(hrc, "Failed to get launched compute instance id");
-    gateways.mGatewayInstanceId = instanceId;
+    gateway.mGatewayInstanceId = instanceId;
 
     Bstr publicIP;
     hrc = gatewayInfo->COMGETTER(PublicIP)(publicIP.asOutParam());
     handleErrors(hrc, "Failed to get cloud gateway public IP address");
-    gateways.mCloudPublicIp = publicIP;
+    gateway.mCloudPublicIp = publicIP;
 
     Bstr secondaryPublicIP;
     hrc = gatewayInfo->COMGETTER(SecondaryPublicIP)(secondaryPublicIP.asOutParam());
     handleErrors(hrc, "Failed to get cloud gateway secondary public IP address");
-    gateways.mCloudSecondaryPublicIp = secondaryPublicIP;
+    gateway.mCloudSecondaryPublicIp = secondaryPublicIP;
 
     Bstr macAddress;
     hrc = gatewayInfo->COMGETTER(MacAddress)(macAddress.asOutParam());
     handleErrors(hrc, "Failed to get cloud gateway public IP address");
-    gateways.setCloudMacAddress(macAddress);
-}
-
-void CloudClient::stopCloudGateway(const GatewayInfo& gateways)
+    gateway.setCloudMacAddress(macAddress);
+}
+
+
+void CloudClient::stopCloudGateway(const GatewayInfo& gateway)
 {
     ComPtr<IProgress> progress;
-    HRESULT hrc = mClient->TerminateInstance(Bstr(gateways.mGatewayInstanceId).raw(), progress.asOutParam());
+    HRESULT hrc = mClient->TerminateInstance(Bstr(gateway.mGatewayInstanceId).raw(), progress.asOutParam());
     handleErrors(hrc, "Failed to terminate compute instance");
 #if 0
@@ -176,13 +176,13 @@
 
 
-static HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways)
+HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateway)
 {
     HRESULT hrc = S_OK;
 
     try {
-        hrc = network->COMGETTER(Provider)(gateways.mCloudProvider.asOutParam());
-        hrc = network->COMGETTER(Profile)(gateways.mCloudProfile.asOutParam());
-        CloudClient client(virtualBox, gateways.mCloudProvider, gateways.mCloudProfile);
-        client.startCloudGateway(network, gateways);
+        hrc = network->COMGETTER(Provider)(gateway.mCloudProvider.asOutParam());
+        hrc = network->COMGETTER(Profile)(gateway.mCloudProfile.asOutParam());
+        CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile);
+        client.startCloudGateway(network, gateway);
     }
     catch (CloudError e)
@@ -195,278 +195,5 @@
 
 
-static HRESULT attachToLocalNetwork(ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork)
-{
-    ComPtr<IMachine> sessionMachine;
-    HRESULT hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    ComPtr<INetworkAdapter> networkAdapter;
-    hrc = sessionMachine->GetNetworkAdapter(1, networkAdapter.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    BstrFmt network("cloud-%s", aCloudNetwork.c_str());
-    hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    hrc = sessionMachine->SaveSettings();
-    if (FAILED(hrc))
-        LogRel(("CLOUD-NET: Failed to save 'lgw' settings. hrc=%x\n", hrc));
-    return hrc;
-}
-
-static HRESULT startLocalGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork, GatewayInfo& gateways)
-{
-    /*
-     * It would be really beneficial if we do not create a local gateway VM each time a target starts.
-     * We probably just need to make sure its configuration matches the one required by the cloud network
-     * attachment and update configuration if necessary.
-     */
-    Bstr strGatewayVM = BstrFmt("lgw-%ls", gateways.mTargetVM.raw());
-    ComPtr<IMachine> machine;
-    HRESULT hrc = virtualBox->FindMachine(strGatewayVM.raw(), machine.asOutParam());
-    if (SUCCEEDED(hrc))
-    {
-        hrc = machine->LockMachine(aSession, LockType_Write);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        hrc = attachToLocalNetwork(aSession, aCloudNetwork);
-    }
-    else
-    {
-        SafeArray<IN_BSTR> groups;
-        groups.push_back(Bstr("/gateways").mutableRaw());
-        hrc = virtualBox->CreateMachine(NULL, Bstr(strGatewayVM).raw(), ComSafeArrayAsInParam(groups), Bstr("Ubuntu_64").raw(), Bstr("").raw(), machine.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to create '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-        /* Initial configuration */
-        hrc = machine->ApplyDefaults(NULL);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to apply defaults to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        /* Add second network adapter */
-        ComPtr<INetworkAdapter> networkAdapter;
-        hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = networkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_Internal);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        BstrFmt network("cloud-%s", aCloudNetwork.c_str());
-        hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = networkAdapter->COMSETTER(PromiscModePolicy)(NetworkAdapterPromiscModePolicy_AllowAll);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to set promiscuous mode policy for the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = networkAdapter->COMSETTER(Enabled)(TRUE);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to enable the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        /* No need for audio -- disable it. */
-        ComPtr<IAudioAdapter> audioAdapter;
-        hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = audioAdapter->COMSETTER(Enabled)(FALSE);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to disable the audio adapter. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        /** @todo Disable USB? */
-
-        /* Register the local gateway VM */
-        hrc = virtualBox->RegisterMachine(machine);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to register '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        /*
-        * Storage can only be attached to registered VMs which means we need to use session
-        * to lock VM in order to make it mutable again.
-        */
-        ComPtr<ISystemProperties> systemProperties;
-        ComPtr<IMedium> hd;
-        Bstr defaultMachineFolder;
-        hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc));
-            return hrc;
-        }
-        hrc = systemProperties->COMGETTER(DefaultMachineFolder)(defaultMachineFolder.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc));
-            return hrc;
-        }
-        hrc = virtualBox->OpenMedium(BstrFmt("%ls\\gateways\\lgw.vdi", defaultMachineFolder.raw()).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE, hd.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to open medium for '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        hrc = machine->LockMachine(aSession, LockType_Write);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        ComPtr<IMachine> sessionMachine;
-        hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = sessionMachine->AttachDevice(Bstr("SATA").raw(), 0, 0, DeviceType_HardDisk, hd);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to attach HD to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-
-        /* Save settings */
-        hrc = sessionMachine->SaveSettings();
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to save '%ls' settings. hrc=%x\n", strGatewayVM.raw(), hrc));
-            return hrc;
-        }
-    }
-    /* Unlock the machine before start, it will be re-locked by LaunchVMProcess */
-    aSession->UnlockMachine();
-
-#ifdef DEBUG
- #define LGW_FRONTEND "gui"
-#else
- #define LGW_FRONTEND "headless"
-#endif
-    ComPtr<IProgress> progress;
-    hrc = machine->LaunchVMProcess(aSession, Bstr(LGW_FRONTEND).raw(), ComSafeArrayNullInParam(), progress.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-        return hrc;
-    }
-
-    hrc = progress->WaitForCompletion(-1);
-    if (FAILED(hrc))
-        LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc));
-
-    gateways.mGatewayVM = strGatewayVM;
-
-    ComPtr<IEventSource> es;
-    hrc = virtualBox->COMGETTER(EventSource)(es.asOutParam());
-    ComPtr<IEventListener> listener;
-    hrc = es->CreateListener(listener.asOutParam());
-    com::SafeArray <VBoxEventType_T> eventTypes(1);
-    eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
-    hrc = es->RegisterListener(listener, ComSafeArrayAsInParam(eventTypes), false);
-
-    Bstr publicKey;
-    Bstr aMachStrGuid;
-    machine->COMGETTER(Id)(aMachStrGuid.asOutParam());
-    Guid aMachGuid(aMachStrGuid);
-
-    uint64_t u64Started = RTTimeMilliTS();
-    do
-    {
-        ComPtr<IEvent> ev;
-        hrc = es->GetEvent(listener, 1000 /* seconds */, ev.asOutParam());
-        if (ev)
-        {
-            VBoxEventType_T aType;
-            hrc = ev->COMGETTER(Type)(&aType);
-            if (aType == VBoxEventType_OnGuestPropertyChanged)
-            {
-                ComPtr<IGuestPropertyChangedEvent> gpcev = ev;
-                Assert(gpcev);
-                Bstr aNextStrGuid;
-                gpcev->COMGETTER(MachineId)(aNextStrGuid.asOutParam());
-                if (aMachGuid != Guid(aNextStrGuid))
-                    continue;
-                Bstr aNextName;
-                gpcev->COMGETTER(Name)(aNextName.asOutParam());
-                if (aNextName == "/VirtualBox/Gateway/PublicKey")
-                {
-                    gpcev->COMGETTER(Value)(publicKey.asOutParam());
-                    LogRel(("CLOUD-NET: Got public key from local gateway '%ls'\n", publicKey.raw()));
-                    break;
-                }
-            }
-
-        }
-    } while (RTTimeMilliTS() - u64Started < 300 * 1000); /** @todo reasonable timeout */
-
-    if (publicKey.isEmpty())
-    {
-        LogRel(("CLOUD-NET: Failed to get ssh public key from '%ls'\n", strGatewayVM.raw()));
-        return E_FAIL;
-    }
-
-    gateways.mPublicSshKey = publicKey;
-
-    return hrc;
-}
-
+#if 0 /* Disabled until proxy support is implemented */
 static bool getProxyForIpAddr(ComPtr<IVirtualBox> virtualBox, const com::Utf8Str &strIpAddr, Bstr &strProxyType, Bstr &strProxyHost, Bstr &strProxyPort)
 {
@@ -598,318 +325,34 @@
 #endif /* VBOX_WITH_PROXY_INFO */
 }
-
-
-static HRESULT exchangeInfoBetweenGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, GatewayInfo& gateways)
-{
-    RT_NOREF(virtualBox);
-    HRESULT hrc = S_OK;
-    do
-    {
-        ComPtr<IConsole> console;
-        hrc = aSession->COMGETTER(Console)(console.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain console for 'lgw'. hrc=%x\n", hrc));
-            break;
-        }
-
-        ComPtr<IGuest> guest;
-        hrc = console->COMGETTER(Guest)(guest.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain guest for 'lgw'. hrc=%x\n", hrc));
-            break;
-        }
-
-        ComPtr<IGuestSession> guestSession;
-
-        GuestSessionWaitResult_T enmWaitResult = GuestSessionWaitResult_None;
-        for (int cTriesLeft = 6; cTriesLeft > 0; cTriesLeft--)
-        {
-            RTThreadSleep(5000 /* ms */);
-            hrc = guest->CreateSession(Bstr("vbox").raw(), Bstr("vbox").raw(), NULL, Bstr("Cloud Gateway Impersonation").raw(), guestSession.asOutParam());
-            if (FAILED(hrc))
-            {
-                LogRel(("CLOUD-NET: Failed to create guest session for 'lgw'%s. hrc=%x\n", cTriesLeft > 1 ? ", will re-try" : "", hrc));
-                continue;
-            }
-            hrc = guestSession->WaitFor(GuestSessionWaitForFlag_Start, 30 * 1000, &enmWaitResult);
-            if (FAILED(hrc))
-            {
-                LogRel(("CLOUD-NET: WARNING! Failed to wait in guest session for 'lgw'%s. waitResult=%x hrc=%x\n",
-                        cTriesLeft > 1 ? ", will re-try" : "", enmWaitResult, hrc));
-                guestSession->Close();
-                guestSession.setNull();
-                continue;
-            }
-            if (enmWaitResult == GuestSessionWaitResult_Start)
-                break;
-            LogRel(("CLOUD-NET: WARNING! 'lgw' guest session waitResult=%x%s\n",
-                    enmWaitResult, cTriesLeft > 1 ? ", will re-try" : ""));
-            guestSession->Close();
-            guestSession.setNull();
-        }
-
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to start guest session for 'lgw'. waitResult=%x hrc=%x\n", enmWaitResult, hrc));
-            break;
-        }
-
-        GuestSessionStatus_T enmSessionStatus;
-        hrc = guestSession->COMGETTER(Status)(&enmSessionStatus);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to get guest session status for 'lgw'. hrc=%x\n", hrc));
-            break;
-        }
-        LogRel(("CLOUD-NET: Session status: %d\n", enmSessionStatus));
-
-        Bstr strPrimaryProxyType;
-        Bstr strPrimaryProxyHost;
-        Bstr strPrimaryProxyPort;
-        Bstr strSecondaryProxyType;
-        Bstr strSecondaryProxyHost;
-        Bstr strSecondaryProxyPort;
-
-        ComPtr<IGuestProcess> guestProcess;
-        com::SafeArray<IN_BSTR> aArgs;
-        com::SafeArray<IN_BSTR> aEnv;
-        com::SafeArray<ProcessCreateFlag_T> aCreateFlags;
-        com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
-        aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
-        aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
-#define GUEST_CMD "/bin/sh"
-        aArgs.push_back(Bstr(GUEST_CMD).mutableRaw());
-        aArgs.push_back(Bstr("-x").mutableRaw());
-        aArgs.push_back(Bstr("/home/vbox/local-bridge.sh").mutableRaw());
-        aArgs.push_back(Bstr(gateways.mCloudPublicIp).mutableRaw());
-        aArgs.push_back(Bstr(gateways.mCloudSecondaryPublicIp).mutableRaw());
-        aArgs.push_back(Bstr(gateways.getLocalMacAddressWithColons()).mutableRaw());
-        if (getProxyForIpAddr(virtualBox, gateways.mCloudPublicIp, strPrimaryProxyType, strPrimaryProxyHost, strPrimaryProxyPort))
-        {
-            aArgs.push_back(strPrimaryProxyType.mutableRaw());
-            aArgs.push_back(strPrimaryProxyHost.mutableRaw());
-            aArgs.push_back(strPrimaryProxyPort.mutableRaw());
-            if (getProxyForIpAddr(virtualBox, gateways.mCloudSecondaryPublicIp, strSecondaryProxyType, strSecondaryProxyHost, strSecondaryProxyPort))
-            {
-                aArgs.push_back(strSecondaryProxyType.mutableRaw());
-                aArgs.push_back(strSecondaryProxyHost.mutableRaw());
-                aArgs.push_back(strSecondaryProxyPort.mutableRaw());
-            }
-        }
-        hrc = guestSession->ProcessCreate(Bstr(GUEST_CMD).raw(),
-                                        ComSafeArrayAsInParam(aArgs),
-                                        ComSafeArrayAsInParam(aEnv),
-                                        ComSafeArrayAsInParam(aCreateFlags),
-                                        180 * 1000 /* ms */,
-                                        guestProcess.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to create guest process '/bin/sh' for 'lgw'. hrc=%x\n", hrc));
-            break;
-        }
-
-        ProcessWaitResult_T waitResult;
-        hrc = guestProcess->WaitFor(ProcessWaitForFlag_Start, 10 * 1000 /* ms */, &waitResult);
-        if (FAILED(hrc) || (waitResult != ProcessWaitResult_Start))
-        {
-            LogRel(("CLOUD-NET: Failed to wait for guest process to start for 'lgw'. waitResult=%x hrc=%x\n",
-                    waitResult, hrc));
-            break;
-        }
-        LogRel(("CLOUD-NET: waitResult=%x\n", waitResult));
-
-        uint32_t cNotSupported = 0;
-        bool fRead, fDone = false;
-        uint64_t u64Start = RTTimeMilliTS();
-        do
-        {
-            /** @todo wait for stdout when it becomes supported! */
-            hrc = guestProcess->WaitFor(ProcessWaitForFlag_Terminate | ProcessWaitForFlag_StdOut, 1000 /* ms */, &waitResult);
-            if (FAILED(hrc))
-            {
-                LogRel(("CLOUD-NET: Failed to get output from guest process for 'lgw'. waitResult=%x hrc=%x\n",
-                        waitResult, hrc));
-                break;
-            }
-            if (waitResult == ProcessWaitResult_WaitFlagNotSupported)
-                ++cNotSupported;
-            else
-            {
-                if (cNotSupported)
-                {
-                    LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported));
-                    cNotSupported = 0;
-                }
-                LogRel(("CLOUD-NET: waitResult=%x\n", waitResult));
-            }
-
-            fRead = false;
-            switch (waitResult)
-            {
-                case ProcessWaitResult_WaitFlagNotSupported:
-                    RTThreadYield();
-                    /* Fall through */
-                case ProcessWaitResult_StdOut:
-                    fRead = true;
-                    break;
-                case ProcessWaitResult_Terminate:
-                    fDone = true;
-                    break;
-                case ProcessWaitResult_Timeout:
-                {
-                    ProcessStatus_T enmProcStatus;
-                    hrc = guestProcess->COMGETTER(Status)(&enmProcStatus);
-                    if (FAILED(hrc))
-                    {
-                        LogRel(("CLOUD-NET: Failed to query guest process status for 'lgw'. hrc=%x\n", hrc));
-                        fDone = true;
-                    }
-                    else
-                    {
-                        LogRel(("CLOUD-NET: Guest process timeout for 'lgw'. status=%d\n", enmProcStatus));
-                        if (   enmProcStatus == ProcessStatus_TimedOutKilled
-                            || enmProcStatus == ProcessStatus_TimedOutAbnormally)
-                        fDone = true;
-                    }
-                    fRead = true;
-                    break;
-                }
-                default:
-                    LogRel(("CLOUD-NET: Unexpected waitResult=%x\n", waitResult));
-                    break;
-            }
-
-            if (fRead)
-            {
-                SafeArray<BYTE> aStdOutData, aStdErrData;
-                hrc = guestProcess->Read(1 /* StdOut */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdOutData));
-                if (FAILED(hrc))
-                {
-                    LogRel(("CLOUD-NET: Failed to read stdout from guest process for 'lgw'. hrc=%x\n", hrc));
-                    break;
-                }
-                hrc = guestProcess->Read(2 /* StdErr */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdErrData));
-                if (FAILED(hrc))
-                {
-                    LogRel(("CLOUD-NET: Failed to read stderr from guest process for 'lgw'. hrc=%x\n", hrc));
-                    break;
-                }
-
-                size_t cbStdOutData = aStdOutData.size();
-                size_t cbStdErrData = aStdErrData.size();
-                if (cbStdOutData == 0 && cbStdErrData == 0)
-                {
-                    //LogRel(("CLOUD-NET: Empty output from guest process for 'lgw'. hrc=%x\n", hrc));
-                    continue;
-                }
-
-                if (cNotSupported)
-                {
-                    LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported));
-                    cNotSupported = 0;
-                }
-                if (cbStdOutData)
-                    LogRel(("CLOUD-NET: Got stdout from 'lgw':\n%.*s", aStdOutData.size(), aStdOutData.raw()));
-                if (cbStdErrData)
-                    LogRel(("CLOUD-NET: Got stderr from 'lgw':\n%.*s", aStdErrData.size(), aStdErrData.raw()));
-            }
-        }
-        while (!fDone && RTTimeMilliTS() - u64Start < 180 * 1000 /* ms */);
-
-    } while (false);
-
-    return hrc;
-}
-
-
-HRESULT destroyLocalGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
-{
-    if (gateways.mGatewayVM.isEmpty())
+#endif
+
+HRESULT stopCloudGateway(ComPtr<IVirtualBox> virtualBox, GatewayInfo& gateway)
+{
+    if (gateway.mGatewayInstanceId.isEmpty())
         return S_OK;
 
-    LogRel(("CLOUD-NET: Shutting down local gateway '%s'...\n", gateways.mGatewayVM.c_str()));
-
-    ComPtr<IMachine> localGateway;
-    HRESULT hrc = virtualBox->FindMachine(Bstr(gateways.mGatewayVM).raw(), localGateway.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to locate '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-        return hrc;
-    }
-
-    MachineState_T tmp;
-    hrc = localGateway->COMGETTER(State)(&tmp);
-    if (tmp == MachineState_Running)
-    {
-        /* If the gateway VM is running we need to stop it */
-        ComPtr<ISession> session;
-        hrc = session.createInprocObject(CLSID_Session);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc));
-            return hrc;
-        }
-
-        hrc = localGateway->LockMachine(session, LockType_Shared);
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to lock '%s' for control. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-            return hrc;
-        }
-
-        ComPtr<IConsole> console;
-        hrc = session->COMGETTER(Console)(console.asOutParam());
-        if (FAILED(hrc))
-        {
-            LogRel(("CLOUD-NET: Failed to obtain console for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-            return hrc;
-        }
-
-        ComPtr<IProgress> progress;
-        console->PowerDown(progress.asOutParam()); /* We assume the gateway disk to be immutable! */
-
-#if 0
-        hrc = progress->WaitForCompletion(-1);
-        if (FAILED(hrc))
-            LogRel(("CLOUD-NET: Failed to stop '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-#endif
-        session->UnlockMachine();
-    }
-#if 0
-    /*
-     * Unfortunately we cannot unregister a machine we've just powered down and unlocked.
-     * It takes some time for the machine to unlock completely.
-     */
-    /** @todo Removal of VM should probably be optional in the future. */
-    SafeIfaceArray<IMedium> media;
-    hrc = pLocalGateway->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(media));
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to unregister '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-        return hrc;
-    }
-    ComPtr<IProgress> removalProgress;
-    hrc = pLocalGateway->DeleteConfig(ComSafeArrayAsInParam(media), removalProgress.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("CLOUD-NET: Failed to delete machine files for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc));
-    }
-#endif
-    return hrc;
-}
-
-static HRESULT terminateCloudGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
-{
-    if (gateways.mGatewayInstanceId.isEmpty())
-        return S_OK;
-
-    LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateways.mGatewayInstanceId.c_str()));
+    LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateway.mGatewayInstanceId.c_str()));
 
     HRESULT hrc = S_OK;
     try {
-        CloudClient client(virtualBox, gateways.mCloudProvider, gateways.mCloudProfile);
-        client.stopCloudGateway(gateways);
+        CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile);
+        client.stopCloudGateway(gateway);
+#if 0
+# ifdef DEBUG
+        char szKeyPath[RTPATH_MAX];
+
+        int rc = GetVBoxUserHomeDirectory(szKeyPath, sizeof(szKeyPath), false /* fCreateDir */);
+        if (RT_SUCCESS(rc))
+        {
+            rc = RTPathAppend(szKeyPath, sizeof(szKeyPath), "gateway-key.pem");
+            AssertRCReturn(rc, rc);
+            rc = RTFileDelete(szKeyPath);
+            if (RT_FAILURE(rc))
+                LogRel(("WARNING! Failed to delete private key %s with rc=%d\n", szKeyPath, rc));
+        }
+        else
+            LogRel(("WARNING! Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
+# endif /* DEBUG */
+#endif
     }
     catch (CloudError e)
@@ -918,36 +361,71 @@
         LogRel(("CLOUD-NET: Failed to terminate cloud gateway instance (rc=%x).\n", hrc));
     }
+    gateway.mGatewayInstanceId.setNull();
     return hrc;
 }
 
-HRESULT startGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways)
-{
-    /* Session used to launch and control the local gateway VM */
-    ComPtr<ISession> session;
-    Bstr strNetwork;
-    HRESULT hrc = session.createInprocObject(CLSID_Session);
-    if (FAILED(hrc))
-        LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc));
+
+HRESULT generateKeys(GatewayInfo& gateway)
+{
+#ifndef VBOX_WITH_LIBSSH
+    RT_NOREF(gateway);
+    return E_NOTIMPL;
+#else /* VBOX_WITH_LIBSSH */
+    ssh_key single_use_key;
+    int rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &single_use_key);
+    if (rc != SSH_OK)
+    {
+        LogRel(("Failed to generate a key pair. rc = %d\n", rc));
+        return E_FAIL;
+    }
+
+    char *pstrKey = NULL;
+    rc = ssh_pki_export_privkey_base64(single_use_key, NULL, NULL, NULL, &pstrKey);
+    if (rc != SSH_OK)
+    {
+        LogRel(("Failed to export private key. rc = %d\n", rc));
+        return E_FAIL;
+    }
+    gateway.mPrivateSshKey = pstrKey;
+#if 0
+# ifdef DEBUG
+    char szConfigPath[RTPATH_MAX];
+
+    rc = GetVBoxUserHomeDirectory(szConfigPath, sizeof(szConfigPath), false /* fCreateDir */);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTPathAppend(szConfigPath, sizeof(szConfigPath), "gateway-key.pem");
+        AssertRCReturn(rc, rc);
+        rc = ssh_pki_export_privkey_file(single_use_key, NULL, NULL, NULL, szConfigPath);
+        if (rc != SSH_OK)
+        {
+            LogRel(("Failed to export private key to %s with rc=%d\n", szConfigPath, rc));
+            return E_FAIL;
+        }
+#  ifndef RT_OS_WINDOWS
+        rc = RTPathSetMode(szConfigPath, RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); /* Satisfy ssh client */
+        AssertRCReturn(rc, rc);
+#  endif
+    }
     else
-        hrc = network->COMGETTER(NetworkName)(strNetwork.asOutParam());
-    if (SUCCEEDED(hrc))
-        hrc = startLocalGateway(virtualBox, session, strNetwork, gateways);
-    if (SUCCEEDED(hrc))
-        hrc = startCloudGateway(virtualBox, network, gateways);
-    if (SUCCEEDED(hrc))
-        hrc = exchangeInfoBetweenGateways(virtualBox, session, gateways);
-
-    session->UnlockMachine();
-    /** @todo Destroy gateways if unsuccessful (cleanup) */
-
-    return hrc;
-}
-
-HRESULT stopGateways(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways)
-{
-    HRESULT hrc = destroyLocalGateway(virtualBox, gateways);
-    AssertComRC(hrc);
-    hrc = terminateCloudGateway(virtualBox, gateways);
-    AssertComRC(hrc);
-    return hrc;
-}
+    {
+        LogRel(("Failed to get VirtualBox user home directory with '%Rrc'\n", rc));
+        return E_FAIL;
+    }
+# endif /* DEBUG */
+#endif
+    ssh_string_free_char(pstrKey);
+    pstrKey = NULL;
+    rc = ssh_pki_export_pubkey_base64(single_use_key, &pstrKey);
+    if (rc != SSH_OK)
+    {
+        LogRel(("Failed to export public key. rc = %d\n", rc));
+        return E_FAIL;
+    }
+    gateway.mPublicSshKey = Utf8StrFmt("ssh-rsa %s single-use-key", pstrKey);
+    ssh_string_free_char(pstrKey);
+    ssh_key_free(single_use_key);
+
+    return S_OK;
+#endif /* VBOX_WITH_LIBSSH */
+}
Index: trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 93311)
+++ trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 93312)
@@ -657,13 +657,4 @@
     }
 
-#ifdef VBOX_WITH_CLOUD_NET
-    {
-        ComPtr<IVirtualBox> pVirtualBox;
-        HRESULT rc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
-        AssertComRC(rc);
-        if (SUCCEEDED(rc) && !pVirtualBox.isNull())
-            stopGateways(pVirtualBox, mGateways);
-    }
-#endif /* VBOX_WITH_CLOUD_NET */
     LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
     if (mVmListener)
@@ -8946,4 +8937,18 @@
                 break;
 
+#ifdef VBOX_WITH_CLOUD_NET
+            /*
+             * We stop cloud gateway here because we may have failed to connect to it,
+             * configure it, or establish a tunnel. We definitely do not want an orphaned
+             * instance running in the cloud.
+             */
+            {
+                ComPtr<IVirtualBox> pVirtualBox;
+                HRESULT rc = that->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
+                AssertComRC(rc);
+                if (SUCCEEDED(rc) && !pVirtualBox.isNull())
+                    stopCloudGateway(pVirtualBox, that->mGateway);
+            }
+#endif /* VBOX_WITH_CLOUD_NET */
             /* Terminate host interface networking. If pUVM is NULL, we've been
              * manually called from powerUpThread() either before calling
Index: trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 93311)
+++ trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 93312)
@@ -335,4 +335,23 @@
 {
     InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
+}
+
+/**
+ * Helper that calls CFGMR3InsertPassword and throws an RTCError if that
+ * fails (Utf8Str variant).
+ * @param   pNode           See CFGMR3InsertPasswordN.
+ * @param   pcszName        See CFGMR3InsertPasswordN.
+ * @param   rStrValue       The string value.
+ */
+static void InsertConfigPassword(PCFGMNODE pNode,
+                               const char *pcszName,
+                               const Utf8Str &rStrValue)
+{
+    int vrc = CFGMR3InsertPasswordN(pNode,
+                                    pcszName,
+                                    rStrValue.c_str(),
+                                    rStrValue.length());
+    if (RT_FAILURE(vrc))
+        throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);
 }
 
@@ -2758,5 +2777,5 @@
             if (eAttachmentType == NetworkAttachmentType_Cloud)
             {
-                mGateways.setLocalMacAddress(macAddrUtf8);
+                mGateway.setLocalMacAddress(macAddrUtf8);
                 /* We'll insert cloud MAC later, when it becomes known. */
             }
@@ -6381,15 +6400,29 @@
                 ComPtr<ICloudNetwork> network;
                 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam());            H();
-                hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam());            H();
+                hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam());            H();
                 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam());   H();
-                hrc = startGateways(virtualBox, network, mGateways);                          H();
-                InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
+                hrc = generateKeys(mGateway);
+                if (FAILED(hrc))
+                {
+                    if (hrc == E_NOTIMPL)
+                        return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
+                                N_("Failed to generate a key pair due to missing libssh\n"
+                                    "To fix this problem, either build VirtualBox with libssh "
+                                    "support or switch to another network attachment type in "
+                                    "the VM settings.\n"));
+                    else
+                        return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
+                                N_("Failed to generate a key pair due to libssh error!\n"));
+                }
+                hrc = startCloudGateway(virtualBox, network, mGateway);                      H();
+                InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
                 if (!bstr.isEmpty())
                 {
-                    InsertConfigString(pLunL0, "Driver", "IntNet");
+                    InsertConfigString(pLunL0, "Driver", "CloudTunnel");
                     InsertConfigNode(pLunL0, "Config", &pCfg);
-                    InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
-                    InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
-                    InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
+                    InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
+                    InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
+                    InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
+                    InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
                     networkName = bstr;
                     trunkType = Bstr(TRUNKTYPE_WHATEVER);
Index: trunk/src/VBox/Main/xml/Settings.cpp
===================================================================
--- trunk/src/VBox/Main/xml/Settings.cpp	(revision 93311)
+++ trunk/src/VBox/Main/xml/Settings.cpp	(revision 93312)
@@ -8012,4 +8012,21 @@
             }
         }
+
+#ifdef VBOX_WITH_CLOUD_NET
+        NetworkAdaptersList::const_iterator netit;
+        for (netit = hardwareMachine.llNetworkAdapters.begin();
+             netit != hardwareMachine.llNetworkAdapters.end();
+             ++netit)
+        {
+            // VirtualBox 6.1 adds support for cloud networks.
+            if (   netit->fEnabled
+                && netit->mode == NetworkAttachmentType_Cloud)
+            {
+                m->sv = SettingsVersion_v1_18;
+                break;
+            }
+
+        }
+#endif /* VBOX_WITH_CLOUD_NET */
     }
 
