Index: /trunk/include/VBox/log.h
===================================================================
--- /trunk/include/VBox/log.h	(revision 84617)
+++ /trunk/include/VBox/log.h	(revision 84618)
@@ -371,4 +371,6 @@
     /** Main group, ICloudNetworkGatewayInfo */
     LOG_GROUP_MAIN_CLOUDNETWORKGATEWAYINFO,
+    /** Main group, ICloudNetworkEnvironmentInfo */
+    LOG_GROUP_MAIN_CLOUDNETWORKENVIRONMENTINFO,
     /** Main group, ICloudProfile. */
     LOG_GROUP_MAIN_CLOUDPROFILE,
@@ -922,4 +924,5 @@
     "MAIN_CLOUDNETWORK", \
     "MAIN_CLOUDNETWORKGATEWAYINFO", \
+    "MAIN_CLOUDNETWORKENVIRONMENTINFO", \
     "MAIN_CLOUDPROFILE", \
     "MAIN_CLOUDPROVIDER", \
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageCloud.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageCloud.cpp	(revision 84617)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageCloud.cpp	(revision 84618)
@@ -2084,4 +2084,95 @@
 
 
+static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
+{
+    RT_NOREF(pCommonOpts);
+    HRESULT hrc = S_OK;
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--gateway-os-name",      'n', RTGETOPT_REQ_STRING },
+        { "--gateway-os-version",   'v', RTGETOPT_REQ_STRING },
+        { "--gateway-shape",        's', RTGETOPT_REQ_STRING },
+        { "--tunnel-network-name",  't', RTGETOPT_REQ_STRING },
+        { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING },
+    };
+    RTGETOPTSTATE GetState;
+    RTGETOPTUNION ValueUnion;
+    int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
+    AssertRCReturn(vrc, RTEXITCODE_FAILURE);
+
+    Bstr strGatewayOsName;
+    Bstr strGatewayOsVersion;
+    Bstr strGatewayShape;
+    Bstr strTunnelNetworkName;
+    Bstr strTunnelNetworkRange;
+
+    int c;
+    while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
+    {
+        switch (c)
+        {
+            case 'n':
+                strGatewayOsName=ValueUnion.psz;
+                break;
+            case 'v':
+                strGatewayOsVersion=ValueUnion.psz;
+                break;
+            case 's':
+                strGatewayShape=ValueUnion.psz;
+                break;
+            case 't':
+                strTunnelNetworkName=ValueUnion.psz;
+                break;
+            case 'r':
+                strTunnelNetworkRange=ValueUnion.psz;
+                break;
+            case VINF_GETOPT_NOT_OPTION:
+                return errorUnknownSubcommand(ValueUnion.psz);
+            default:
+                return errorGetOpt(c, &ValueUnion);
+        }
+    }
+
+    /* Delayed check. It allows us to print help information.*/
+    hrc = checkAndSetCommonOptions(a, pCommonOpts);
+    if (FAILED(hrc))
+        return RTEXITCODE_FAILURE;
+
+    // if (strGatewayOsName.isEmpty())
+    //     return errorArgument("Missing --gateway-os-name parameter");
+    // if (strGatewayOsVersion.isEmpty())
+    //     return errorArgument("Missing --gateway-os-version parameter");
+    // if (strGatewayShape.isEmpty())
+    //     return errorArgument("Missing --gateway-shape parameter");
+    // if (strTunnelNetworkName.isEmpty())
+    //     strTunnelNetworkName = "VirtualBox Tunneling Network";
+
+    ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
+
+    ComObjPtr<ICloudClient> oCloudClient;
+    CHECK_ERROR2_RET(hrc, pCloudProfile,
+                     CreateCloudClient(oCloudClient.asOutParam()),
+                     RTEXITCODE_FAILURE);
+
+    ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
+    ComPtr<ICloudNetworkEnvironmentInfo> cloudNetworkEnv;
+    ComPtr<IProgress> progress;
+    CHECK_ERROR2_RET(hrc, oCloudClient,
+                     SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(),
+                                                  strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(),
+                                                  cloudNetworkEnv.asOutParam(), progress.asOutParam()),
+                     RTEXITCODE_FAILURE);
+
+    hrc = showProgress(progress);
+    CHECK_PROGRESS_ERROR_RET(progress, ("Setting up cloud network environment failed"), RTEXITCODE_FAILURE);
+
+    Bstr tunnelNetworkId;
+    hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam());
+    RTPrintf("Cloud network environment was set up successfully. Tunnel network id is: %ls\n", tunnelNetworkId.raw());
+
+    return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+
 static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
 {
@@ -2094,5 +2185,6 @@
         { "info",           1001, RTGETOPT_REQ_NOTHING },
         { "update",         1002, RTGETOPT_REQ_NOTHING },
-        { "delete",         1003, RTGETOPT_REQ_NOTHING }
+        { "delete",         1003, RTGETOPT_REQ_NOTHING },
+        { "setup",          1004, RTGETOPT_REQ_NOTHING }
     };
 
@@ -2116,4 +2208,6 @@
             case 1003:
                 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
+            case 1004:
+                return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts);
             case VINF_GETOPT_NOT_OPTION:
                 return errorUnknownSubcommand(ValueUnion.psz);
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 84617)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 84618)
@@ -571,5 +571,4 @@
 	src-server/NATNetworkImpl.cpp \
 	$(if $(VBOX_WITH_CLOUD_NET), \
-	src-server/CloudGateway.cpp \
 	src-server/CloudNetworkImpl.cpp \
 	,) \
@@ -1017,4 +1016,10 @@
 	$(VBOX_XML_SCHEMADEFS_CPP)
 
+# Experimental cloud support
+ifdef VBOX_WITH_CLOUD_NET
+ VBoxC_DEFS += VBOX_WITH_CLOUD_NET
+ VBoxC_SOURCES += src-client/CloudGateway.cpp
+endif
+
 # Audio bits.
 VBoxC_SOURCES += \
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 84617)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 84618)
@@ -26733,4 +26733,12 @@
 
 
+  <interface name="ICloudNetworkEnvironmentInfo" extends="$unknown"
+             uuid="181dfb55-394d-44d3-9edb-af2c4472c40a"
+             wsmap="managed"
+             reservedAttributes="7">
+    <attribute name="tunnelNetworkId" type="wstring" readonly="yes"/>
+  </interface>
+
+
   <interface name="ICloudMachine" extends="$unknown"
              uuid="d8497a14-8fbf-11ea-aa85-2b4d110b053e"
@@ -26925,5 +26933,5 @@
   <interface
     name="ICloudClient" extends="$unknown"
-    uuid="5b047402-9648-11ea-9aa2-2f60bdea83dd"
+    uuid="5fa3a8db-1c4f-4cda-b8d4-7982ef60fefb"
     wsmap="managed" reservedMethods="16" reservedAttributes="8"
     >
@@ -27344,4 +27352,32 @@
       <param name="gatewayInfo" type="ICloudNetworkGatewayInfo" dir="out">
         <desc>Information about the started gateway.</desc>
+      </param>
+      <param name="progress" type="IProgress" dir="return">
+        <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="setupCloudNetworkEnvironment">
+      <param name="tunnelNetworkName" type="wstring" dir="in">
+        <desc>The name of tunnelling network to be created in the Cloud. If this parameter
+          is empty the default value "VirtualBox Tunneling Network" is assumed.</desc>
+      </param>
+      <param name="tunnelNetworkRange" type="wstring" dir="in">
+        <desc>The IP address range of tunnelling network to be created in the Cloud. If this
+          parameter is empty the default value "10.0.0.0/16" is assumed.</desc>
+      </param>
+      <param name="gatewayOsName" type="wstring" dir="in">
+        <desc>The name of the operating system to be used for cloud gateway instances.
+          The default value is "Oracle Linux".</desc>
+      </param>
+      <param name="gatewayOsVersion" type="wstring" dir="in">
+        <desc>The version of the operating system to be used for cloud gateway instances.
+          The default value is "7.8".</desc>
+      </param>
+      <param name="gatewayShape" type="wstring" dir="in">
+        <desc>The shape of cloud gateway instance. The default value is "VM.Standard2.1".</desc>
+      </param>
+      <param name="networkEnvironmentInfo" type="ICloudNetworkEnvironmentInfo" dir="out">
+        <desc>Information about the created network environment.</desc>
       </param>
       <param name="progress" type="IProgress" dir="return">
Index: /trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 84617)
+++ /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 84618)
@@ -30,4 +30,7 @@
 # include "Recording.h"
 #endif
+#ifdef VBOX_WITH_CLOUD_NET
+#include "CloudGateway.h"
+#endif /* VBOX_WITH_CLOUD_NET */
 
 class Guest;
@@ -1092,4 +1095,8 @@
 #endif /* VBOX_WITH_RECORDING */
 
+#ifdef VBOX_WITH_CLOUD_NET
+    GatewayInfo mGateways;
+#endif /* VBOX_WITH_CLOUD_NET */
+
     friend class VMTask;
     friend class ConsoleVRDPServer;
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 84617)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 84618)
@@ -46,8 +46,4 @@
 # include "ThreadTask.h"
 #endif
-#ifdef VBOX_WITH_CLOUD_NET
-# include "CloudNetworkImpl.h"
-# include "CloudGateway.h"
-#endif /* VBOX_WITH_CLOUD_NET */
 
 // generated header
@@ -204,8 +200,4 @@
         // list of files to delete in Delete(); this list is filled by Unregister()
         std::list<Utf8Str>  llFilesToDelete;
-
-#ifdef VBOX_WITH_CLOUD_NET
-        GatewayInfo         mGatewayInfo;
-#endif /* VBOX_WITH_CLOUD_NET */
 };
 
@@ -764,10 +756,4 @@
     pm::CollectorGuest     *mCollectorGuest;
 #endif /* VBOX_WITH_RESOURCE_USAGE_API */
-
-#ifdef VBOX_WITH_CLOUD_NET
-HRESULT i_connectToCloudNetwork(ProgressProxy *aProgress);
-HRESULT i_disconnectFromCloudNetwork();
-HRESULT i_setMacAddress(int slot, const Utf8Str& strMac);
-#endif /* VBOX_WITH_CLOUD_NET */
 
     Machine * const         mPeer;
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 84617)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 84618)
@@ -649,4 +649,13 @@
     }
 
+#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)
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 84617)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 84618)
@@ -2630,4 +2630,15 @@
             Assert(!macAddr.isEmpty());
             Utf8Str macAddrUtf8 = macAddr;
+#ifdef VBOX_WITH_CLOUD_NET
+            NetworkAttachmentType_T eAttachmentType;
+            hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType);                 H();
+            if (eAttachmentType == NetworkAttachmentType_Cloud)
+            {
+                mGateways.setLocalMacAddress(macAddrUtf8);
+                /* We'll insert cloud MAC later, when it becomes known. */
+            }
+            else
+            {
+#endif
             char *macStr = (char*)macAddrUtf8.c_str();
             Assert(strlen(macStr) == 12);
@@ -2646,5 +2657,7 @@
             }
             InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
-
+#ifdef VBOX_WITH_CLOUD_NET
+            }
+#endif
             /*
              * Check if the cable is supposed to be unplugged
@@ -4985,4 +4998,9 @@
         Bstr bstr;
 
+#ifdef VBOX_WITH_CLOUD_NET
+        /* We'll need device's pCfg for cloud attachments */
+        PCFGMNODE pDevCfg = pCfg;
+#endif /* VBOX_WITH_CLOUD_NET */
+
 #define H()         AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
@@ -5823,5 +5841,10 @@
             case NetworkAttachmentType_Cloud:
             {
-                hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam());       H();
+                ComPtr<ICloudNetwork> network;
+                hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam());            H();
+                hrc = pMachine->COMGETTER(Name)(mGateways.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));
                 if (!bstr.isEmpty())
                 {
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 84617)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 84618)
@@ -50,8 +50,4 @@
 #include "ExtPackManagerImpl.h"
 #include "MachineLaunchVMCommonWorker.h"
-#ifdef VBOX_WITH_CLOUD_NET
-#include "ApplianceImpl.h"
-#include "CloudGateway.h"
-#endif /* VBOX_WITH_CLOUD_NET */
 
 // generated header
@@ -3335,8 +3331,4 @@
         if (SUCCEEDED(rc))
         {
-#ifdef VBOX_WITH_CLOUD_NET
-            i_connectToCloudNetwork(progress);
-#endif /* VBOX_WITH_CLOUD_NET */
-
             rc = i_launchVMProcess(control, strFrontend, aEnvironmentChanges, progress);
             if (SUCCEEDED(rc))
@@ -7308,164 +7300,4 @@
     return (mUSBControllers->size() > 0);
 }
-
-#ifdef VBOX_WITH_CLOUD_NET
-HRESULT Machine::i_setMacAddress(int slot, const Utf8Str& strMac)
-{
-    Bstr macAddress = strMac;
-    ComPtr<ISession> session;
-    HRESULT hrc = session.createInprocObject(CLSID_Session);
-    if (FAILED(hrc))
-        LogRel(("OCI-NET: Failed to create a session. hrc=%x\n", hrc));
-
-    hrc = lockMachine(session, LockType_Write);
-    if (FAILED(hrc))
-    {
-        LogRel(("OCI-NET: Failed to lock target VM for modifications. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    ComPtr<IMachine> sessionMachine;
-    hrc = session->COMGETTER(Machine)(sessionMachine.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("OCI-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    ComPtr<INetworkAdapter> networkAdapter;
-    hrc = sessionMachine->GetNetworkAdapter(slot, networkAdapter.asOutParam());
-    if (FAILED(hrc))
-    {
-        LogRel(("OCI-NET: Failed to locate the second network adapter. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    hrc = networkAdapter->COMSETTER(MACAddress)(macAddress.raw());
-    if (FAILED(hrc))
-    {
-        LogRel(("OCI-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc));
-        return hrc;
-    }
-
-    hrc = sessionMachine->SaveSettings();
-    if (FAILED(hrc))
-        LogRel(("OCI-NET: Failed to save 'lgw' settings. hrc=%x\n", hrc));
-
-    session->UnlockMachine();
-
-    return hrc;
-}
-
-
-HRESULT Machine::i_connectToCloudNetwork(ProgressProxy *aProgress)
-{
-    LogFlowThisFuncEnter();
-    AssertReturn(aProgress, E_FAIL);
-
-    HRESULT hrc = E_FAIL;
-    Bstr name;
-    int iSlot = -1;
-
-    LogFlowThisFunc(("Checking if cloud network needs to be connected\n"));
-    for (int slot = 0; (unsigned)slot < mNetworkAdapters.size(); ++slot)
-    {
-        BOOL enabled;
-        hrc = mNetworkAdapters[slot]->COMGETTER(Enabled)(&enabled);
-        if (   FAILED(hrc)
-            || !enabled)
-            continue;
-
-        NetworkAttachmentType_T type;
-        hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type);
-        if (   SUCCEEDED(hrc)
-            && type == NetworkAttachmentType_Cloud)
-        {
-            if (name.isNotEmpty())
-            {
-                LogRel(("OCI-NET: VM '%s' uses multiple cloud network attachments. '%ls' will be ignored.\n",
-                        mUserData->s.strName.c_str(), name.raw()));
-                continue;
-            }
-            hrc = mNetworkAdapters[slot]->COMGETTER(CloudNetwork)(name.asOutParam());
-            if (SUCCEEDED(hrc))
-            {
-                LogRel(("OCI-NET: VM '%s' uses cloud network '%ls'\n",
-                        mUserData->s.strName.c_str(), name.raw()));
-                iSlot = slot;
-            }
-        }
-    }
-    if (name.isNotEmpty())
-    {
-        LogFlowThisFunc(("Connecting to cloud network '%ls'...\n", name.raw()));
-        ComObjPtr<CloudNetwork> network;
-        hrc = mParent->i_findCloudNetworkByName(name, &network);
-        if (FAILED(hrc))
-        {
-            LogRel(("OCI-NET: Could not find cloud network '%ls'.\n", name.raw()));
-            return hrc;
-        }
-        Bstr MacAddress;
-        Utf8Str strMacAddress;
-        GatewayInfo gateways;
-        gateways.mTargetVM = mUserData->s.strName;
-        gateways.mAdapterSlot = iSlot;
-        hrc = mNetworkAdapters[iSlot]->COMGETTER(MACAddress)(MacAddress.asOutParam());
-        if (FAILED(hrc))
-        {
-            Host::i_generateMACAddress(strMacAddress);
-            LogRel(("OCI-NET: Failed to get MAC address of adapter connected to cloud network '%ls'.\n"
-                    "OCI-NET: Will use auto-generated '%s'.\n", name.raw(), strMacAddress.c_str()));
-        }
-        else
-            strMacAddress = MacAddress;
-        hrc = gateways.setLocalMacAddress(strMacAddress);
-        if (FAILED(hrc))
-        {
-            LogRel(("OCI-NET: Failed to obtain valid MAC address (%s) from cloud gateway '%ls'.\n",
-                    strMacAddress.c_str(), name.raw()));
-            return hrc;
-        }
-        hrc = startGateways(mParent, network, gateways);
-        /* We copy gateways structure unconditionally in order to be able to undo partially failed gateway setup. */
-        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-        mData->mGatewayInfo = gateways;
-        alock.release();
-        if (SUCCEEDED(hrc))
-        {
-            if (iSlot == -1)
-                LogRel(("OCI-NET: No slot information available for cloud network attachment!\n"));
-            else
-            {
-                hrc = i_setMacAddress(iSlot, gateways.getCloudMacAddressWithoutColons());
-                if (SUCCEEDED(hrc))
-                    LogRel(("OCI-NET: Updated MAC address for '%s' to %RTmac\n",
-                            mUserData->s.strName.c_str(), &gateways.mCloudMacAddress));
-                else
-                    LogRel(("OCI-NET: Failed to update MAC address for '%s' to %RTmac\n",
-                            mUserData->s.strName.c_str(), &gateways.mCloudMacAddress));
-            }
-        }
-    }
-    else
-        LogFlowThisFunc(("VM '%s' has no cloud network attachments.\n", mUserData->s.strName.c_str()));
-
-    LogFlowThisFuncLeave();
-    return hrc;
-}
-
-HRESULT Machine::i_disconnectFromCloudNetwork()
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-    GatewayInfo gateways(mData->mGatewayInfo);
-    mData->mGatewayInfo.setNull();
-    alock.release();
-
-    HRESULT hrc = stopGateways(mParent, gateways);
-    /// @todo Restore original MAC address. I'd hate to wait here for Machine to power off though.
-    // i_setMacAddress(gateways.mAdapterSlot, gateways.getLocalMacAddressWithoutColons());
-    return hrc;
-}
-#endif /* VBOX_WITH_CLOUD_NET */
 
 
@@ -13264,8 +13096,4 @@
     LogFlowThisFuncEnter();
 
-#ifdef VBOX_WITH_CLOUD_NET
-    mPeer->i_disconnectFromCloudNetwork();
-#endif /* VBOX_WITH_CLOUD_NET */
-
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
