You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by fm...@apache.org on 2017/12/21 10:25:24 UTC

[cloudstack] branch master updated: CLOUDSTACK-10024: Network migration support

This is an automated email from the ASF dual-hosted git repository.

fmaximus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new d497656  CLOUDSTACK-10024: Network migration support
d497656 is described below

commit d49765619dae5551e41192c4e00c324e74fa33db
Author: Sigert Goeminne <si...@nuagenetworks.net>
AuthorDate: Wed Apr 26 15:32:31 2017 +0200

    CLOUDSTACK-10024: Network migration support
    
    Co-Authored-By: Frank Maximus frank.maximus@nuagenetworks.net
    Co-Authored-By: Raf Smeets raf.smeets@nuagenetworks.net
    
    New API’s:
    
    * migrateNetwork
    * migrateVpc
---
 api/src/com/cloud/event/EventTypes.java            |    1 +
 api/src/com/cloud/network/NetworkService.java      |   19 +
 api/src/com/cloud/network/Networks.java            |    1 +
 api/src/com/cloud/offering/NetworkOffering.java    |    2 +-
 api/src/com/cloud/server/ResourceTag.java          |    4 +-
 api/src/com/cloud/vm/NicSecondaryIp.java           |    2 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    2 +
 .../command/admin/network/MigrateNetworkCmd.java   |  155 ++
 .../api/command/admin/network/MigrateVPCCmd.java   |  144 ++
 .../admin/network/UpdateNetworkOfferingCmd.java    |    7 +
 .../src/com/cloud/agent/api/ReplugNicAnswer.java   |   14 +-
 core/src/com/cloud/agent/api/ReplugNicCommand.java |   70 +
 .../src/com/cloud/vm/VirtualMachineManager.java    |    3 +
 .../service/NetworkOrchestrationService.java       |    7 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   43 +-
 .../engine/orchestration/NetworkOrchestrator.java  |    8 +-
 .../src/com/cloud/network/dao/NetworkVO.java       |    4 +
 .../src/com/cloud/network/dao/RouterNetworkVO.java |    4 +
 .../src/com/cloud/network/vpc/NetworkACLVO.java    |    4 +
 .../src/com/cloud/network/vpc/VpcGatewayVO.java    |    4 +
 .../com/cloud/network/vpc/dao/NetworkACLDao.java   |    6 +
 .../cloud/network/vpc/dao/NetworkACLDaoImpl.java   |   14 +
 .../com/cloud/network/vpc/dao/VpcGatewayDao.java   |    2 +
 .../cloud/network/vpc/dao/VpcGatewayDaoImpl.java   |    7 +
 .../vpc/dao/VpcOfferingServiceMapDaoImpl.java      |    1 -
 .../cloud/offerings/NetworkOfferingDetailsVO.java  |   35 +-
 .../src/com/cloud/offerings/NetworkOfferingVO.java |    4 +
 .../offerings/dao/NetworkOfferingDetailsDao.java   |    4 +-
 .../dao/NetworkOfferingDetailsDaoImpl.java         |   19 +-
 .../src/com/cloud/tags/dao/ResourceTagDao.java     |   26 +-
 .../com/cloud/tags/dao/ResourceTagsDaoImpl.java    |   27 +
 .../schema/src/com/cloud/vm/dao/NicIpAliasDao.java |    1 +
 .../src/com/cloud/vm/dao/NicIpAliasDaoImpl.java    |   10 +
 .../src/com/cloud/vm/dao/NicSecondaryIpDao.java    |    2 +
 .../com/cloud/vm/dao/NicSecondaryIpDaoImpl.java    |   11 +
 .../src/com/cloud/vm/dao/NicSecondaryIpVO.java     |    5 +
 .../hypervisor/kvm/resource/BridgeVifDriver.java   |  158 +-
 .../hypervisor/kvm/resource/DirectVifDriver.java   |   14 +
 .../hypervisor/kvm/resource/IvsVifDriver.java      |   16 +-
 .../kvm/resource/LibvirtComputingResource.java     |   78 +-
 .../kvm/resource/LibvirtDomainXMLParser.java       |   12 +-
 .../hypervisor/kvm/resource/LibvirtVMDef.java      |   39 +-
 .../hypervisor/kvm/resource/OvsVifDriver.java      |   44 +-
 .../cloud/hypervisor/kvm/resource/VifDriver.java   |    8 +
 .../hypervisor/kvm/resource/VifDriverBase.java     |    4 +
 .../wrapper/LibvirtCheckNetworkCommandWrapper.java |    7 +-
 .../wrapper/LibvirtPlugNicCommandWrapper.java      |   15 +-
 .../LibvirtPrepareForMigrationCommandWrapper.java  |   13 +-
 .../wrapper/LibvirtReplugNicCommandWrapper.java    |  133 ++
 .../kvm/resource/LibvirtComputingResourceTest.java |   82 +-
 .../kvm/resource/LibvirtDomainXMLParserTest.java   |    9 +-
 .../hypervisor/kvm/resource/LibvirtVMDefTest.java  |   55 +-
 .../LibvirtReplugNicCommandWrapperTest.java        |  274 +++
 .../cloud/agent/manager/MockNetworkManager.java    |    4 +
 .../agent/manager/MockNetworkManagerImpl.java      |   17 +-
 .../cloud/agent/manager/SimulatorManagerImpl.java  |   13 +-
 .../hypervisor/vmware/resource/VmwareResource.java |   87 +-
 plugins/network-elements/nuage-vsp/pom.xml         |    2 +-
 .../com/cloud/network/element/NuageVspElement.java |  106 +-
 .../network/guru/NuageVspGuestNetworkGuru.java     |   39 +-
 .../src/com/cloud/util/NuageVspEntityBuilder.java  |   63 +-
 .../nuage-vsp/test/com/cloud/NuageTest.java        |   11 +-
 .../cloud/network/element/NuageVspElementTest.java |    2 +
 .../core/spring-server-core-managers-context.xml   |    2 +
 .../configuration/ConfigurationManagerImpl.java    |   20 +
 .../metadata/ResourceMetaDataManagerImpl.java      |   14 +-
 .../com/cloud/network/NetworkMigrationManager.java |   85 +
 .../cloud/network/NetworkMigrationManagerImpl.java |  693 +++++++
 server/src/com/cloud/network/NetworkModelImpl.java |   13 +-
 .../src/com/cloud/network/NetworkServiceImpl.java  |  568 ++++--
 .../src/com/cloud/network/vpc/VpcManagerImpl.java  |    1 +
 .../src/com/cloud/server/ManagementServerImpl.java |    4 +
 .../com/cloud/tags/TaggedResourceManagerImpl.java  |    5 +-
 .../test/com/cloud/vpc/MockNetworkManagerImpl.java |   23 +-
 test/integration/plugins/nuagevsp/nuageTestCase.py |   50 +-
 .../plugins/nuagevsp/nuage_test_data.py            |    2 +-
 .../plugins/nuagevsp/test_nuage_extra_dhcp.py      |    3 +-
 .../plugins/nuagevsp/test_nuage_internal_dns.py    |    2 +
 .../nuagevsp/test_nuage_network_migration.py       | 2002 ++++++++++++++++++++
 .../plugins/nuagevsp/test_nuage_vpc_internal_lb.py |    3 +
 tools/apidoc/gen_toc.py                            |    1 +
 tools/marvin/marvin/config/test_data.py            |  122 +-
 tools/marvin/marvin/deployDataCenter.py            |    3 +
 tools/marvin/marvin/lib/base.py                    |   49 +
 .../cloud/hypervisor/vmware/util/VmwareHelper.java |  133 +-
 85 files changed, 5269 insertions(+), 506 deletions(-)

diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index d5d11e8..ce410a6 100644
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -130,6 +130,7 @@ public class EventTypes {
     public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE";
     public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE";
     public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE";
+    public static final String EVENT_NETWORK_MIGRATE = "NETWORK.MIGRATE";
     public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN";
     public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE";
     public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE";
diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java
index 0ad42b5..2559cfa 100644
--- a/api/src/com/cloud/network/NetworkService.java
+++ b/api/src/com/cloud/network/NetworkService.java
@@ -36,6 +36,7 @@ import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.Network.Service;
 import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.vpc.Vpc;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.user.Account;
 import com.cloud.user.User;
@@ -82,6 +83,24 @@ public interface NetworkService {
     Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long networkOfferingId,
         Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID, boolean updateInSequence, boolean forced);
 
+    /**
+     * Migrate a network from one physical network to another physical network
+     * @param networkId of the network that needs to be migrated
+     * @param networkOfferingId new network offering id for the network
+     * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
+     * @return the migrated network
+     */
+    Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume);
+
+    /**
+     * Migrate a vpc from on physical network to another physical network
+     * @param vpcId the id of the vpc that needs to be migrated
+     * @param vpcNetworkofferingId the new vpc offering id
+     * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
+     * @return the migrated vpc
+     */
+    Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map<String, String> networkToOffering, Account account, User callerUser, boolean resume);
+
     PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List<String> isolationMethods, String broadcastDomainRange, Long domainId,
         List<String> tags, String name);
 
diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java
index 37746f0..06f4236 100644
--- a/api/src/com/cloud/network/Networks.java
+++ b/api/src/com/cloud/network/Networks.java
@@ -246,6 +246,7 @@ public class Networks {
          * encode a string into a BroadcastUri
          * @param candidate the input string
          * @return an URI containing an appropriate (possibly given) scheme and the value
+         *
          */
         public static URI fromString(String candidate) {
             try {
diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java
index 3532010..0c83789 100644
--- a/api/src/com/cloud/offering/NetworkOffering.java
+++ b/api/src/com/cloud/offering/NetworkOffering.java
@@ -38,7 +38,7 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity,
     }
 
     public enum Detail {
-        InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits
+        InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering
     }
 
     public final static String SystemPublicNetwork = "System-Public-Network";
diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java
index 3bed77d..067cb97 100644
--- a/api/src/com/cloud/server/ResourceTag.java
+++ b/api/src/com/cloud/server/ResourceTag.java
@@ -58,7 +58,9 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
         LBStickinessPolicy(false, true),
         LBHealthCheckPolicy(false, true),
         SnapshotPolicy(false, true),
-        GuestOs(false, true);
+        GuestOs(false, true),
+        NetworkOffering(false, true),
+        VpcOffering(true, false);
 
 
         ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {
diff --git a/api/src/com/cloud/vm/NicSecondaryIp.java b/api/src/com/cloud/vm/NicSecondaryIp.java
index b7d3668..2856e0a 100644
--- a/api/src/com/cloud/vm/NicSecondaryIp.java
+++ b/api/src/com/cloud/vm/NicSecondaryIp.java
@@ -32,6 +32,8 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden
 
     long getNicId();
 
+    void setNicId(long nicId);
+
     String getIp4Address();
 
     String getIp6Address();
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index a5bd95f..64cdb23 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -332,6 +332,7 @@ public class ApiConstants {
     public static final String COUNT = "count";
     public static final String TRAFFIC_TYPE = "traffictype";
     public static final String NETWORK_OFFERING_ID = "networkofferingid";
+    public static final String TIER_NETWORK_OFFERINGS = "tiernetworkofferings";
     public static final String NETWORK_IDS = "networkids";
     public static final String NETWORK_ID = "networkid";
     public static final String NIC_ID = "nicid";
@@ -375,6 +376,7 @@ public class ApiConstants {
     public static final String ZONE_TOKEN = "zonetoken";
     public static final String DHCP_PROVIDER = "dhcpprovider";
     public static final String RESULT = "success";
+    public static final String RESUME = "resume";
     public static final String LUN_ID = "lunId";
     public static final String IQN = "iqn";
     public static final String AGGREGATE_NAME = "aggregatename";
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java
new file mode 100644
index 0000000..651fce8
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java
@@ -0,0 +1,155 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.NetworkOfferingResponse;
+import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.Network;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+
+@APICommand(name = "migrateNetwork", description = "moves a network to another physical network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class MigrateNetworkCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName());
+
+    private static final String s_name = "migratenetworkresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+    @ACL(accessType = AccessType.OperateEntry)
+    @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class,
+            required=true, description="the ID of the network")
+    protected Long id;
+
+    @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, description = "network offering ID")
+    private Long networkOfferingId;
+
+    @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
+    private Boolean resume;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public Long getNetworkOfferingId() {
+        return networkOfferingId;
+    }
+
+    public Boolean getResume() {
+        return resume != null ? resume : false;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        Network network = _networkService.getNetwork(id);
+        if (network == null) {
+            throw new InvalidParameterValueException("Networkd id=" + id + " doesn't exist");
+        } else {
+            return _networkService.getNetwork(id).getAccountId();
+        }
+    }
+
+    @Override
+    public void execute() {
+        User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
+        Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
+        Network network = _networkService.getNetwork(id);
+        if (network == null) {
+            throw new InvalidParameterValueException("Couldn't find network by id");
+        }
+
+        Network result =
+            _networkService.migrateGuestNetwork(getId(), getNetworkOfferingId(), callerAccount, callerUser, getResume());
+
+        if (result != null) {
+            NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network");
+        }
+    }
+
+    @Override
+    public String getEventDescription() {
+        StringBuilder eventMsg = new StringBuilder("Migrating network: " + getId());
+        if (getNetworkOfferingId() != null) {
+            Network network = _networkService.getNetwork(getId());
+            if (network == null) {
+                throw new InvalidParameterValueException("Network id=" + id + " doesn't exist");
+            }
+            if (network.getNetworkOfferingId() != getNetworkOfferingId()) {
+                NetworkOffering oldOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
+                NetworkOffering newOff = _entityMgr.findById(NetworkOffering.class, getNetworkOfferingId());
+                if (newOff == null) {
+                    throw new InvalidParameterValueException("Network offering id supplied is invalid");
+                }
+
+                eventMsg.append(". Original network offering id: " + oldOff.getUuid() + ", new network offering id: " + newOff.getUuid());
+            }
+        }
+
+        return eventMsg.toString();
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NETWORK_MIGRATE;
+    }
+
+    @Override
+    public String getSyncObjType() {
+        return BaseAsyncCmd.networkSyncObject;
+    }
+
+    @Override
+    public Long getSyncObjId() {
+        return id;
+    }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java
new file mode 100644
index 0000000..6cf1157
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java
@@ -0,0 +1,144 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.network;
+
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.VpcOfferingResponse;
+import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.cloud.event.EventTypes;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+
+@APICommand(name = "migrateVPC", description = "moves a vpc to another physical network", responseObject = VpcResponse.class, responseView = ResponseObject.ResponseView.Restricted, entityType = {Vpc.class},
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class MigrateVPCCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName());
+
+    private static final String s_name = "migratevpcresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+    @ACL(accessType = SecurityChecker.AccessType.OperateEntry)
+    @Parameter(name= ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class,
+            required=true, description = "the ID of the vpc")
+    protected Long id;
+
+    @Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, required=true, description = "vpc offering ID")
+    private Long vpcOfferingId;
+
+    @Parameter(name = ApiConstants.TIER_NETWORK_OFFERINGS, type = CommandType.MAP, description = "network offering ids for each network in the vpc. Example: tierNetworkOfferings[0].networkId=networkId1&tierNetworkOfferings[0].networkOfferingId=newNetworkofferingId1&tierNetworkOfferings[1].networkId=networkId2&tierNetworkOfferings[1].networkOfferingId=newNetworkofferingId2")
+    private Map<Integer, HashMap<String, String>> tierNetworkOfferings;
+
+    @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
+    private Boolean resume;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public Long getVpcOfferingId() {
+        return vpcOfferingId;
+    }
+
+    public Boolean getResume() {
+        return resume == null ? false : resume;
+    }
+
+    public Map<String, String> getTierNetworkOfferings() {
+        HashMap<String, String> flatMap = new HashMap<>();
+
+        if (tierNetworkOfferings == null) {
+            return flatMap;
+        }
+
+        for (HashMap<String, String> map : tierNetworkOfferings.values()) {
+             flatMap.put(map.get("networkid"), map.get("networkofferingid"));
+        }
+
+        return flatMap;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public void execute() {
+        User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
+        Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
+
+        Vpc result =
+                _networkService.migrateVpcNetwork(getId(), getVpcOfferingId(), getTierNetworkOfferings(), callerAccount, callerUser, getResume());
+
+        if (result != null) {
+            VpcResponse response = _responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, result);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vpc");
+        }
+    }
+
+    @Override
+    public String getEventDescription() { return "Migrating vpc: " + getId() + " to new vpc offering (" + vpcOfferingId + ")";  }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NETWORK_MIGRATE;
+    }
+
+    @Override
+    public String getSyncObjType() {
+        return BaseAsyncCmd.networkSyncObject;
+    }
+
+    @Override
+    public Long getSyncObjId() {
+        return id;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+
+}
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
index 411da4f..5c58530 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java
@@ -69,6 +69,9 @@ public class UpdateNetworkOfferingCmd extends BaseCmd {
                description = "maximum number of concurrent connections supported by the network offering")
     private Integer maxConnections;
 
+    @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096)
+    private String tags;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -105,6 +108,10 @@ public class UpdateNetworkOfferingCmd extends BaseCmd {
         return keepAliveEnabled;
     }
 
+    public String getTags() {
+        return tags;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java b/core/src/com/cloud/agent/api/ReplugNicAnswer.java
similarity index 76%
copy from engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java
copy to core/src/com/cloud/agent/api/ReplugNicAnswer.java
index 5e2a6f5..7de39c3 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java
+++ b/core/src/com/cloud/agent/api/ReplugNicAnswer.java
@@ -1,3 +1,4 @@
+//
 // Licensed to the Apache Software Foundation (ASF) under one
 // or more contributor license agreements.  See the NOTICE file
 // distributed with this work for additional information
@@ -14,10 +15,15 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-package com.cloud.network.vpc.dao;
+//
+
+package com.cloud.agent.api;
 
-import com.cloud.network.vpc.NetworkACLVO;
-import com.cloud.utils.db.GenericDao;
+public class ReplugNicAnswer extends Answer {
+    public ReplugNicAnswer() {
+    }
 
-public interface NetworkACLDao extends GenericDao<NetworkACLVO, Long> {
+    public ReplugNicAnswer(ReplugNicCommand cmd, boolean success, String result) {
+        super(cmd, success, result);
+    }
 }
diff --git a/core/src/com/cloud/agent/api/ReplugNicCommand.java b/core/src/com/cloud/agent/api/ReplugNicCommand.java
new file mode 100644
index 0000000..1c61f0a
--- /dev/null
+++ b/core/src/com/cloud/agent/api/ReplugNicCommand.java
@@ -0,0 +1,70 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.agent.api;
+
+import java.util.Map;
+
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.vm.VirtualMachine;
+
+public class ReplugNicCommand extends Command {
+
+    NicTO nic;
+    String instanceName;
+    VirtualMachine.Type vmType;
+    Map<String, String> details;
+
+    public NicTO getNic() {
+        return nic;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return true;
+    }
+
+    protected ReplugNicCommand() {
+    }
+
+    public ReplugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype) {
+        this.nic = nic;
+        this.instanceName = instanceName;
+        this.vmType = vmtype;
+    }
+
+    public ReplugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype, Map<String, String> details) {
+        this.nic = nic;
+        this.instanceName = instanceName;
+        this.vmType = vmtype;
+        this.details = details;
+    }
+
+    public String getVmName() {
+        return instanceName;
+    }
+
+    public VirtualMachine.Type getVMType() {
+        return vmType;
+    }
+
+    public Map<String, String> getDetails() {
+        return this.details;
+    }
+}
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index 14fead7..a20fc7b 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -193,6 +193,9 @@ public interface VirtualMachineManager extends Manager {
      */
     VirtualMachineTO toVmTO(VirtualMachineProfile profile);
 
+    boolean replugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException,
+            ResourceUnavailableException, InsufficientCapacityException;
+
     VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException,
             InsufficientServerCapacityException;
 
diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
index e2a471f..86a8fe9 100644
--- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
@@ -130,6 +130,11 @@ public interface NetworkOrchestrationService {
     Map<Integer, String> getExtraDhcpOptions(long nicId);
 
     /**
+     * Returns all extra dhcp options which are set on the provided nic
+     * @param nicId
+     * @return map which maps the dhcp value on it's option code
+     */
+    /**
      * prepares vm nic change for migration
      *
      * This method will be called in migration transaction before the vm migration.
@@ -275,4 +280,6 @@ public interface NetworkOrchestrationService {
     int getResourceCount(Network network);
 
     void finalizeUpdateInSequence(Network network, boolean success);
+
+    List<NetworkGuru> getNetworkGurus();
 }
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 74927b9..da13b7a 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -38,8 +38,8 @@ import java.util.concurrent.TimeUnit;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
-import com.cloud.agent.api.AttachOrDettachConfigDriveCommand;
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.ca.CAManager;
 import org.apache.cloudstack.context.CallContext;
@@ -59,6 +59,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager;
 import org.apache.cloudstack.framework.jobs.Outcome;
 import org.apache.cloudstack.framework.jobs.dao.VmWorkJobDao;
 import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
 import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl;
 import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
@@ -70,13 +71,13 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
-import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
 import com.cloud.agent.api.AgentControlAnswer;
 import com.cloud.agent.api.AgentControlCommand;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachOrDettachConfigDriveCommand;
 import com.cloud.agent.api.CheckVirtualMachineAnswer;
 import com.cloud.agent.api.CheckVirtualMachineCommand;
 import com.cloud.agent.api.ClusterVMMetaDataSyncAnswer;
@@ -89,6 +90,8 @@ import com.cloud.agent.api.PlugNicCommand;
 import com.cloud.agent.api.PrepareForMigrationCommand;
 import com.cloud.agent.api.RebootAnswer;
 import com.cloud.agent.api.RebootCommand;
+import com.cloud.agent.api.ReplugNicAnswer;
+import com.cloud.agent.api.ReplugNicCommand;
 import com.cloud.agent.api.RestoreVMSnapshotAnswer;
 import com.cloud.agent.api.RestoreVMSnapshotCommand;
 import com.cloud.agent.api.ScaleVmCommand;
@@ -3635,6 +3638,36 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         }
     }
 
+    @Override
+    public boolean replugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final ReservationContext context, final DeployDestination dest) throws ConcurrentOperationException,
+            ResourceUnavailableException, InsufficientCapacityException {
+        boolean result = true;
+
+        final VMInstanceVO router = _vmDao.findById(vm.getId());
+        if (router.getState() == State.Running) {
+            try {
+                final ReplugNicCommand replugNicCmd = new ReplugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails());
+                final Commands cmds = new Commands(Command.OnError.Stop);
+                cmds.addCommand("replugnic", replugNicCmd);
+                _agentMgr.send(dest.getHost().getId(), cmds);
+                final ReplugNicAnswer replugNicAnswer = cmds.getAnswer(ReplugNicAnswer.class);
+                if (replugNicAnswer == null || !replugNicAnswer.getResult()) {
+                    s_logger.warn("Unable to replug nic for vm " + vm.getName());
+                    result = false;
+                }
+            } catch (final OperationTimedoutException e) {
+                throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, dest.getHost().getId(), e);
+            }
+        } else {
+            s_logger.warn("Unable to apply ReplugNic, vm " + router + " is not in the right state " + router.getState());
+
+            throw new ResourceUnavailableException("Unable to apply ReplugNic on the backend," + " vm " + vm + " is not in the right state", DataCenter.class,
+                                                   router.getDataCenterId());
+        }
+
+        return result;
+    }
+
     public boolean plugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final ReservationContext context, final DeployDestination dest) throws ConcurrentOperationException,
     ResourceUnavailableException, InsufficientCapacityException {
         boolean result = true;
@@ -3647,7 +3680,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                 cmds.addCommand("plugnic", plugNicCmd);
                 _agentMgr.send(dest.getHost().getId(), cmds);
                 final PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class);
-                if (!(plugNicAnswer != null && plugNicAnswer.getResult())) {
+                if (plugNicAnswer == null || !plugNicAnswer.getResult()) {
                     s_logger.warn("Unable to plug nic for vm " + vm.getName());
                     result = false;
                 }
@@ -3683,7 +3716,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                 _agentMgr.send(dest.getHost().getId(), cmds);
 
                 final UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class);
-                if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) {
+                if (unplugNicAnswer == null || !unplugNicAnswer.getResult()) {
                     s_logger.warn("Unable to unplug nic from router " + router);
                     result = false;
                 }
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 2d30ced..d5b0244 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -292,7 +292,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
 
     List<NetworkGuru> networkGurus;
 
-
+    @Override
     public List<NetworkGuru> getNetworkGurus() {
         return networkGurus;
     }
@@ -1156,7 +1156,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                 }
 
                 if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Asking " + element.getName() + " to implemenet " + network);
+                    s_logger.debug("Asking " + element.getName() + " to implement " + network);
                 }
 
                 if (!element.implement(network, offering, dest, context)) {
@@ -2644,7 +2644,9 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                     public void doInTransactionWithoutResult(final TransactionStatus status) {
                         final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, networkFinal.getGuruName());
 
-                        guru.trash(networkFinal, _networkOfferingDao.findById(networkFinal.getNetworkOfferingId()));
+                        if (!guru.trash(networkFinal, _networkOfferingDao.findById(networkFinal.getNetworkOfferingId()))) {
+                            throw new CloudRuntimeException("Failed to trash network.");
+                        }
 
                         if (!deleteVlansInNetwork(networkFinal.getId(), context.getCaller().getId(), callerAccount)) {
                             s_logger.warn("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges");
diff --git a/engine/schema/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java
index 08a326a..f871788 100644
--- a/engine/schema/src/com/cloud/network/dao/NetworkVO.java
+++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java
@@ -318,6 +318,10 @@ public class NetworkVO implements Network {
         return related;
     }
 
+    public void setRelated(long related) {
+        this.related = related;
+    }
+
     @Override
     public long getId() {
         return id;
diff --git a/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java b/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java
index db86cfa..5808af3 100644
--- a/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java
+++ b/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java
@@ -68,6 +68,10 @@ public class RouterNetworkVO implements InternalIdentity {
         return guestType;
     }
 
+    public void setNetworkId(long networkId) {
+        this.networkId = networkId;
+    }
+
     @Override
     public long getId() {
         return id;
diff --git a/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java b/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java
index b6ed5cb..fb6a239 100644
--- a/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java
+++ b/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java
@@ -93,6 +93,10 @@ public class NetworkACLVO implements NetworkACL {
         this.display = display;
     }
 
+    public void setVpcId(long vpcId) {
+        this.vpcId = vpcId;
+    }
+
     @Override
     public boolean isDisplay() {
         return display;
diff --git a/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java b/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java
index 23568b4..9919ba3 100644
--- a/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java
+++ b/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java
@@ -220,4 +220,8 @@ public class VpcGatewayVO implements VpcGateway {
     public Class<?> getEntityType() {
         return VpcGateway.class;
     }
+
+    public void setVpcId(Long vpcId) {
+        this.vpcId = vpcId;
+    }
 }
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java
index 5e2a6f5..37ba347 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java
+++ b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java
@@ -16,8 +16,14 @@
 // under the License.
 package com.cloud.network.vpc.dao;
 
+import java.util.List;
+
 import com.cloud.network.vpc.NetworkACLVO;
+import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GenericDao;
 
 public interface NetworkACLDao extends GenericDao<NetworkACLVO, Long> {
+
+    @DB
+    List<NetworkACLVO> listByVpcId(long vpcId);
 }
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java
index 00bb1d8..d21df12 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java
+++ b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java
@@ -19,15 +19,29 @@ package com.cloud.network.vpc.dao;
 
 import org.springframework.stereotype.Component;
 
+import java.util.List;
+
 import com.cloud.network.vpc.NetworkACLVO;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
 
 @Component
 @DB()
 public class NetworkACLDaoImpl extends GenericDaoBase<NetworkACLVO, Long> implements NetworkACLDao {
+    protected final SearchBuilder<NetworkACLVO> AllFieldsSearch;
 
     protected NetworkACLDaoImpl() {
+        AllFieldsSearch = createSearchBuilder();
+        AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), SearchCriteria.Op.EQ);
+        AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), SearchCriteria.Op.EQ);
+        AllFieldsSearch.done();
     }
 
+    @Override public List<NetworkACLVO> listByVpcId(long vpcId) {
+        SearchCriteria<NetworkACLVO> sc = AllFieldsSearch.create();
+        sc.setParameters("vpcId", vpcId);
+        return listBy(sc);
+    }
 }
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java
index a2a449b..e6a72c8 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java
+++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java
@@ -30,4 +30,6 @@ public interface VpcGatewayDao extends GenericDao<VpcGatewayVO, Long> {
     List<VpcGatewayVO> listByVpcIdAndType(long vpcId, VpcGateway.Type type);
 
     List<VpcGatewayVO> listByAclIdAndType(long aclId, VpcGateway.Type type);
+
+    List<VpcGatewayVO> listByVpcId(long vpcId);
 }
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java
index 284fd88..39d3319 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java
+++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java
@@ -82,4 +82,11 @@ public class VpcGatewayDaoImpl extends GenericDaoBase<VpcGatewayVO, Long> implem
         sc.setParameters("type", type);
         return listBy(sc);
     }
+
+    @Override
+    public List<VpcGatewayVO> listByVpcId(long vpcId) {
+        SearchCriteria<VpcGatewayVO> sc = AllFieldsSearch.create();
+        sc.setParameters("vpcId", vpcId);
+        return listBy(sc);
+    }
 }
diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
index 9679c3a..9e14bb5 100644
--- a/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
+++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
@@ -97,7 +97,6 @@ public class VpcOfferingServiceMapDaoImpl extends GenericDaoBase<VpcOfferingServ
     @Override
     public List<String> listServicesForVpcOffering(long offId) {
         SearchCriteria<String> sc = ServicesSearch.create();
-        ;
         sc.setParameters("offeringId", offId);
         return customSearch(sc, null);
     }
diff --git a/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java b/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java
index c16c5ac..d28e150 100644
--- a/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java
+++ b/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java
@@ -25,21 +25,20 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
-import org.apache.cloudstack.api.InternalIdentity;
-
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Detail;
+import org.apache.cloudstack.api.ResourceDetail;
 
 @Entity
 @Table(name = "network_offering_details")
-public class NetworkOfferingDetailsVO implements InternalIdentity {
+public class NetworkOfferingDetailsVO implements ResourceDetail {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Column(name = "id")
     private long id;
 
     @Column(name = "network_offering_id")
-    private long offeringId;
+    private long resourceId;
 
     @Enumerated(value = EnumType.STRING)
     @Column(name = "name")
@@ -51,8 +50,8 @@ public class NetworkOfferingDetailsVO implements InternalIdentity {
     public NetworkOfferingDetailsVO() {
     }
 
-    public NetworkOfferingDetailsVO(long offeringId, Detail detailName, String value) {
-        this.offeringId = offeringId;
+    public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value) {
+        this.resourceId = resourceId;
         this.name = detailName;
         this.value = value;
     }
@@ -62,11 +61,20 @@ public class NetworkOfferingDetailsVO implements InternalIdentity {
         return id;
     }
 
-    public long getOfferingId() {
-        return offeringId;
+    @Override
+    public long getResourceId() {
+        return resourceId;
+    }
+
+    public void setResourceId(long resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    public String getName() {
+        return name.name();
     }
 
-    public NetworkOffering.Detail getName() {
+    public NetworkOffering.Detail getDetailName() {
         return name;
     }
 
@@ -74,12 +82,13 @@ public class NetworkOfferingDetailsVO implements InternalIdentity {
         return value;
     }
 
-    public void setId(long id) {
-        this.id = id;
+    @Override
+    public boolean isDisplay() {
+        return false;
     }
 
-    public void setOfferingId(long offeringId) {
-        this.offeringId = offeringId;
+    public void setId(long id) {
+        this.id = id;
     }
 
     public void setName(NetworkOffering.Detail name) {
diff --git a/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java
index f6451fb..e317143 100644
--- a/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java
+++ b/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java
@@ -223,6 +223,10 @@ public class NetworkOfferingVO implements NetworkOffering {
         return tags;
     }
 
+    public void setTags(String tags) {
+        this.tags = tags;
+    }
+
     public void setName(String name) {
         this.name = name;
     }
diff --git a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java
index 6af9c91..94e5006 100644
--- a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java
+++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java
@@ -21,9 +21,9 @@ import java.util.Map;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Detail;
 import com.cloud.offerings.NetworkOfferingDetailsVO;
-import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
 
-public interface NetworkOfferingDetailsDao extends GenericDao<NetworkOfferingDetailsVO, Long> {
+public interface NetworkOfferingDetailsDao extends ResourceDetailsDao<NetworkOfferingDetailsVO> {
 
     Map<NetworkOffering.Detail, String> getNtwkOffDetails(long offeringId);
 
diff --git a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java
index ea47670..786b71c 100644
--- a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java
+++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java
@@ -16,6 +16,8 @@
 // under the License.
 package com.cloud.offerings.dao;
 
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -23,27 +25,27 @@ import java.util.Map;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Detail;
 import com.cloud.offerings.NetworkOfferingDetailsVO;
-import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.GenericSearchBuilder;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Func;
 import com.cloud.utils.db.SearchCriteria.Op;
 
-public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase<NetworkOfferingDetailsVO, Long> implements NetworkOfferingDetailsDao {
+public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<NetworkOfferingDetailsVO> implements NetworkOfferingDetailsDao {
     protected final SearchBuilder<NetworkOfferingDetailsVO> DetailSearch;
     private final GenericSearchBuilder<NetworkOfferingDetailsVO, String> ValueSearch;
 
     public NetworkOfferingDetailsDaoImpl() {
 
         DetailSearch = createSearchBuilder();
-        DetailSearch.and("offeringId", DetailSearch.entity().getOfferingId(), SearchCriteria.Op.EQ);
+        DetailSearch.and("resourceId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
         DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
+        DetailSearch.and("value", DetailSearch.entity().getValue(), SearchCriteria.Op.EQ);
         DetailSearch.done();
 
         ValueSearch = createSearchBuilder(String.class);
         ValueSearch.select(null, Func.DISTINCT, ValueSearch.entity().getValue());
-        ValueSearch.and("offeringId", ValueSearch.entity().getOfferingId(), SearchCriteria.Op.EQ);
+        ValueSearch.and("resourceId", ValueSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
         ValueSearch.and("name", ValueSearch.entity().getName(), Op.EQ);
         ValueSearch.done();
     }
@@ -51,12 +53,12 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase<NetworkOfferin
     @Override
     public Map<NetworkOffering.Detail, String> getNtwkOffDetails(long offeringId) {
         SearchCriteria<NetworkOfferingDetailsVO> sc = DetailSearch.create();
-        sc.setParameters("offeringId", offeringId);
+        sc.setParameters("resourceId", offeringId);
 
         List<NetworkOfferingDetailsVO> results = search(sc, null);
         Map<NetworkOffering.Detail, String> details = new HashMap<NetworkOffering.Detail, String>(results.size());
         for (NetworkOfferingDetailsVO result : results) {
-            details.put(result.getName(), result.getValue());
+            details.put(result.getDetailName(), result.getValue());
         }
 
         return details;
@@ -66,7 +68,7 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase<NetworkOfferin
     public String getDetail(long offeringId, Detail detailName) {
         SearchCriteria<String> sc = ValueSearch.create();
         sc.setParameters("name", detailName);
-        sc.setParameters("offeringId", offeringId);
+        sc.setParameters("resourceId", offeringId);
         List<String> results = customSearch(sc, null);
         if (results.isEmpty()) {
             return null;
@@ -75,4 +77,7 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase<NetworkOfferin
         }
     }
 
+    @Override public void addDetail(long resourceId, String key, String value, boolean display) {
+        persist(new NetworkOfferingDetailsVO(resourceId, Detail.valueOf(key), value));
+    }
 }
diff --git a/engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java b/engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java
index b788434..bacb09b 100644
--- a/engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java
+++ b/engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java
@@ -29,15 +29,35 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
 public interface ResourceTagDao extends GenericDao<ResourceTagVO, Long> {
 
     /**
-     * @param resourceId
-     * @param resourceType
-     * @return
+     * Remove a resourceTag based on the resourceId and type
+     * @param resourceId the id of the resource you want to remove
+     * @param resourceType the resource type
+     * @return true if successful
      */
     boolean removeByIdAndType(long resourceId, ResourceObjectType resourceType);
 
     List<? extends ResourceTag> listBy(long resourceId, ResourceObjectType resourceType);
 
+    /**
+     * Find a resource tag based on the resource id, resource type and key
+     * @param resourceId the id of the resource you want to find
+     * @param resourceType the resource type (e.g. VPC)
+     * @param key the key value
+     * @return the ResourceTag matching the search criteria
+     */
+    ResourceTag findByKey(long resourceId, ResourceObjectType resourceType, String key);
+
     void updateResourceId(long srcId, long destId, ResourceObjectType resourceType);
 
     Map<String, Set<ResourceTagResponse>> listTags();
+
+    /**
+     * remove a resource tag based on the resource id, resource type and key
+     * @param resourceId the id of the resource you want to remove
+     * @param resourceType the resource type (e.g. VPC)
+     * @param key the key value
+     */
+    void removeByResourceIdAndKey(long resourceId, ResourceObjectType resourceType, String key);
+
+    List<? extends ResourceTag> listByResourceUuid(String resourceUuid);
 }
diff --git a/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java
index d5578a8..cc9d99e 100644
--- a/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java
+++ b/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java
@@ -42,6 +42,8 @@ public class ResourceTagsDaoImpl extends GenericDaoBase<ResourceTagVO, Long> imp
         AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), Op.EQ);
         AllFieldsSearch.and("uuid", AllFieldsSearch.entity().getResourceUuid(), Op.EQ);
         AllFieldsSearch.and("resourceType", AllFieldsSearch.entity().getResourceType(), Op.EQ);
+        AllFieldsSearch.and("key", AllFieldsSearch.entity().getKey(), Op.EQ);
+        AllFieldsSearch.and("resourceUuid", AllFieldsSearch.entity().getResourceUuid(), Op.EQ);
         AllFieldsSearch.done();
     }
 
@@ -62,6 +64,15 @@ public class ResourceTagsDaoImpl extends GenericDaoBase<ResourceTagVO, Long> imp
         return listBy(sc);
     }
 
+    @Override
+    public ResourceTag findByKey(long resourceId, ResourceObjectType resourceType, String key) {
+        SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
+        sc.setParameters("resourceId", resourceId);
+        sc.setParameters("resourceType", resourceType);
+        sc.setParameters("key", key);
+        return findOneBy(sc);
+    }
+
     @Override public void updateResourceId(long srcId, long destId, ResourceObjectType resourceType) {
         SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
         sc.setParameters("resourceId", srcId);
@@ -93,4 +104,20 @@ public class ResourceTagsDaoImpl extends GenericDaoBase<ResourceTagVO, Long> imp
         }
         return resourceTagMap;
     }
+
+    @Override
+    public void removeByResourceIdAndKey(long resourceId, ResourceObjectType resourceType, String key) {
+        SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
+        sc.setParameters("resourceId", resourceId);
+        sc.setParameters("resourceType", resourceType);
+        sc.setParameters("key", key);
+        remove(sc);
+    }
+
+    @Override
+    public List<? extends ResourceTag> listByResourceUuid(String resourceUuid) {
+        SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
+        sc.setParameters("resourceUuid", resourceUuid);
+        return listBy(sc);
+    }
 }
diff --git a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java
index b79c101..40e7e40 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java
@@ -58,4 +58,5 @@ public interface NicIpAliasDao extends GenericDao<NicIpAliasVO, Long> {
 
     List<NicIpAliasVO> listByNetworkIdAndState(long networkId, NicIpAlias.State state);
 
+    int moveIpAliases(long fromNicId, long toNicId);
 }
\ No newline at end of file
diff --git a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java
index 48cc662..d1453aa 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java
@@ -172,4 +172,14 @@ public class NicIpAliasDaoImpl extends GenericDaoBase<NicIpAliasVO, Long> implem
         List<NicIpAliasVO> list = listBy(sc);
         return list.size();
     }
+
+    @Override
+    public int moveIpAliases(long fromNicId, long toNicId) {
+        SearchCriteria<NicIpAliasVO> sc = AllFieldsSearch.create();
+        sc.setParameters("nicId", fromNicId);
+
+        NicIpAliasVO update = createForUpdate();
+        update.setNicId(toNicId);
+        return update(update, sc);
+    }
 }
diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java
index ef8df51..96b80b8 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java
@@ -57,4 +57,6 @@ public interface NicSecondaryIpDao extends GenericDao<NicSecondaryIpVO, Long> {
     Long countByNicId(long nicId);
 
     List<NicSecondaryIpVO> listSecondaryIpUsingKeyword(long nicId, String keyword);
+
+    int moveSecondaryIps(long fromNicId, long toNicId);
 }
diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
index 50733de..01f53bc 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
@@ -172,4 +172,15 @@ public class NicSecondaryIpDaoImpl extends GenericDaoBase<NicSecondaryIpVO, Long
         sc.setParameters("address", "%" + keyword + "%");
         return listBy(sc);
     }
+
+    @Override
+    public int moveSecondaryIps(long fromNicId, long toNicId) {
+        NicSecondaryIpVO update = createForUpdate();
+        update.setNicId(toNicId);
+
+        SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
+        sc.setParameters("nicId", fromNicId);
+
+        return update(update, sc);
+    }
 }
diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java
index 23e45e8..d60ac92 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java
@@ -98,6 +98,11 @@ public class NicSecondaryIpVO implements NicSecondaryIp {
     }
 
     @Override
+    public void setNicId(long nicId) {
+        this.nicId = nicId;
+    }
+
+    @Override
     public long getDomainId() {
         return domainId;
     }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java
index 2fab9a8..11b22c4 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java
@@ -20,16 +20,19 @@
 package com.cloud.hypervisor.kvm.resource;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.naming.ConfigurationException;
 
-import com.google.common.base.Strings;
 import org.apache.log4j.Logger;
 import org.libvirt.LibvirtException;
 
+import com.google.common.base.Strings;
+
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.exception.InternalErrorException;
 import com.cloud.network.Networks;
@@ -54,6 +57,8 @@ public class BridgeVifDriver extends VifDriverBase {
 
         super.configure(params);
 
+        getPifs();
+
         // Set the domr scripts directory
         params.put("domr.scripts.dir", "scripts/network/domr/kvm");
 
@@ -80,12 +85,125 @@ public class BridgeVifDriver extends VifDriverBase {
         if (libvirtVersion == null) {
             libvirtVersion = 0L;
         }
+    }
 
-        try {
-            createControlNetwork();
-        } catch (LibvirtException e) {
-            throw new ConfigurationException(e.getMessage());
+    public void getPifs() {
+        final File dir = new File("/sys/devices/virtual/net");
+        final File[] netdevs = dir.listFiles();
+        final List<String> bridges = new ArrayList<String>();
+        for (File netdev : netdevs) {
+            final File isbridge = new File(netdev.getAbsolutePath() + "/bridge");
+            final String netdevName = netdev.getName();
+            s_logger.debug("looking in file " + netdev.getAbsolutePath() + "/bridge");
+            if (isbridge.exists()) {
+                s_logger.debug("Found bridge " + netdevName);
+                bridges.add(netdevName);
+            }
+        }
+
+        String guestBridgeName = _libvirtComputingResource.getGuestBridgeName();
+        String publicBridgeName = _libvirtComputingResource.getPublicBridgeName();
+
+        for (final String bridge : bridges) {
+            s_logger.debug("looking for pif for bridge " + bridge);
+            final String pif = getPif(bridge);
+            if (_libvirtComputingResource.isPublicBridge(bridge)) {
+                _pifs.put("public", pif);
+            }
+            if (guestBridgeName != null && bridge.equals(guestBridgeName)) {
+                _pifs.put("private", pif);
+            }
+            _pifs.put(bridge, pif);
+        }
+
+        // guest(private) creates bridges on a pif, if private bridge not found try pif direct
+        // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label
+        if (_pifs.get("private") == null) {
+            s_logger.debug("guest(private) traffic label '" + guestBridgeName + "' not found as bridge, looking for physical interface");
+            final File dev = new File("/sys/class/net/" + guestBridgeName);
+            if (dev.exists()) {
+                s_logger.debug("guest(private) traffic label '" + guestBridgeName + "' found as a physical device");
+                _pifs.put("private", guestBridgeName);
+            }
+        }
+
+        // public creates bridges on a pif, if private bridge not found try pif direct
+        // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label
+        if (_pifs.get("public") == null) {
+            s_logger.debug("public traffic label '" + publicBridgeName+ "' not found as bridge, looking for physical interface");
+            final File dev = new File("/sys/class/net/" + publicBridgeName);
+            if (dev.exists()) {
+                s_logger.debug("public traffic label '" + publicBridgeName + "' found as a physical device");
+                _pifs.put("public", publicBridgeName);
+            }
+        }
+
+        s_logger.debug("done looking for pifs, no more bridges");
+    }
+
+    private String getPif(final String bridge) {
+        String pif = matchPifFileInDirectory(bridge);
+        final File vlanfile = new File("/proc/net/vlan/" + pif);
+
+        if (vlanfile.isFile()) {
+            pif = Script.runSimpleBashScript("grep ^Device\\: /proc/net/vlan/" + pif + " | awk {'print $2'}");
         }
+
+        return pif;
+    }
+
+    private String matchPifFileInDirectory(final String bridgeName) {
+        final File brif = new File("/sys/devices/virtual/net/" + bridgeName + "/brif");
+
+        if (!brif.isDirectory()) {
+            final File pif = new File("/sys/class/net/" + bridgeName);
+            if (pif.isDirectory()) {
+                // if bridgeName already refers to a pif, return it as-is
+                return bridgeName;
+            }
+            s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", does " + brif.getAbsolutePath() + "exist?");
+            return "";
+        }
+
+        final File[] interfaces = brif.listFiles();
+
+        for (File anInterface : interfaces) {
+            final String fname = anInterface.getName();
+            s_logger.debug("matchPifFileInDirectory: file name '" + fname + "'");
+            if (isInterface(fname)) {
+                return fname;
+            }
+        }
+
+        s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", did not find an eth*, bond*, team*, vlan*, em*, p*p*, ens*, eno*, enp*, or enx* in " + brif.getAbsolutePath());
+        return "";
+    }
+
+    private static final String [] IF_NAME_PATTERNS = {
+            "^eth",
+            "^bond",
+            "^vlan",
+            "^vx",
+            "^em",
+            "^ens",
+            "^eno",
+            "^enp",
+            "^team",
+            "^enx",
+            "^p\\d+p\\d+"
+    };
+
+    /**
+     * @param fname
+     * @return
+     */
+    private static boolean isInterface(final String fname) {
+        StringBuilder commonPattern = new StringBuilder();
+        for (final String ifNamePattern : IF_NAME_PATTERNS) {
+            commonPattern.append("|(").append(ifNamePattern).append(".*)");
+        }
+
+        return fname.matches(commonPattern.toString());
     }
 
     @Override
@@ -161,6 +279,7 @@ public class BridgeVifDriver extends VifDriverBase {
         if (nic.getPxeDisable() == true) {
             intf.setPxeDisable(true);
         }
+
         return intf;
     }
 
@@ -169,6 +288,16 @@ public class BridgeVifDriver extends VifDriverBase {
         deleteVnetBr(iface.getBrName());
     }
 
+    @Override
+    public void attach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("brctl addif " + iface.getBrName() + " " + iface.getDevName());
+    }
+
+    @Override
+    public void detach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("test -d /sys/class/net/" + iface.getBrName() + "/brif/" + iface.getDevName() + " && brctl delif " + iface.getBrName() + " " + iface.getDevName());
+    }
+
     private String setVnetBrName(String pifName, String vnetId) {
         return "br" + pifName + "-" + vnetId;
     }
@@ -272,10 +401,6 @@ public class BridgeVifDriver extends VifDriverBase {
         }
     }
 
-    private void createControlNetwork() throws LibvirtException {
-        createControlNetwork(_bridges.get("linklocal"));
-    }
-
     private void deleteExistingLinkLocalRouteTable(String linkLocalBr) {
         Script command = new Script("/bin/bash", _timeout);
         command.add("-c");
@@ -304,16 +429,21 @@ public class BridgeVifDriver extends VifDriverBase {
         }
     }
 
-    private void createControlNetwork(String privBrName) {
+    private void createControlNetwork() {
+        createControlNetwork(_bridges.get("linklocal"));
+    }
+
+    @Override
+    public void createControlNetwork(String privBrName)  {
         deleteExistingLinkLocalRouteTable(privBrName);
-        if (!isBridgeExists(privBrName)) {
+        if (!isExistingBridge(privBrName)) {
             Script.runSimpleBashScript("brctl addbr " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout);
         }
-
     }
 
-    private boolean isBridgeExists(String bridgeName) {
-        File f = new File("/sys/devices/virtual/net/" + bridgeName);
+    @Override
+    public boolean isExistingBridge(String bridgeName) {
+        File f = new File("/sys/devices/virtual/net/" + bridgeName + "/bridge");
         if (f.exists()) {
             return true;
         } else {
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java
index 3cc8839..b8763fa 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java
@@ -63,4 +63,18 @@ public class DirectVifDriver extends VifDriverBase {
         // not needed, libvirt will cleanup
     }
 
+    @Override
+    public void attach(LibvirtVMDef.InterfaceDef iface) {
+
+    }
+
+    @Override
+    public void detach(LibvirtVMDef.InterfaceDef iface) {
+
+    }
+
+    @Override
+    public void createControlNetwork(String privBrName) {
+    }
+
 }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java
index 1aae2b5..8e73d85 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java
@@ -74,8 +74,6 @@ public class IvsVifDriver extends VifDriverBase {
         if (libvirtVersion == null) {
             libvirtVersion = 0L;
         }
-
-        createControlNetwork(_bridges.get("linklocal"));
     }
 
     @Override
@@ -145,6 +143,17 @@ public class IvsVifDriver extends VifDriverBase {
     public void unplug(InterfaceDef iface) {
     }
 
+    @Override
+    public void attach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("/usr/sbin/ivs-ctl add-port " + iface.getDevName());
+    }
+
+    @Override
+    public void detach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("/usr/sbin/ivs-ctl del-port " + iface.getDevName());
+    }
+
+
     private void createControlNetwork() throws LibvirtException {
         createControlNetwork(_bridges.get("linklocal"));
     }
@@ -268,7 +277,8 @@ public class IvsVifDriver extends VifDriverBase {
         }
     }
 
-    private void createControlNetwork(String privBrName) {
+    @Override
+    public void createControlNetwork(String privBrName) {
         deleteExitingLinkLocalRouteTable(privBrName);
         if (!isBridgeExists(privBrName)) {
             Script.runSimpleBashScript("brctl addbr " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout);
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 51b9737..9c97b3e 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -47,12 +47,6 @@ import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
-import org.apache.cloudstack.storage.to.VolumeObjectTO;
-import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
-import org.apache.cloudstack.utils.linux.CPUStat;
-import org.apache.cloudstack.utils.linux.MemStat;
-import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.ArrayUtils;
@@ -76,6 +70,15 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
+import com.google.common.base.Strings;
+
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
+import org.apache.cloudstack.utils.linux.CPUStat;
+import org.apache.cloudstack.utils.linux.MemStat;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.HostVmStateReportEntry;
@@ -167,7 +170,6 @@ import com.cloud.utils.ssh.SshHelper;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VmDetailConstants;
-import com.google.common.base.Strings;
 
 /**
  * LibvirtComputingResource execute requests on the computing/routing host using
@@ -968,6 +970,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
             }
         }
 
+        final Map<String, String> bridges = new HashMap<String, String>();
+
+        params.put("libvirt.host.bridges", bridges);
+        params.put("libvirt.host.pifs", _pifs);
+
+        params.put("libvirt.computing.resource", this);
+        params.put("libvirtVersion", _hypervisorLibvirtVersion);
+
+
+        configureVifDrivers(params);
+
+        /*
         switch (_bridgeType) {
         case OPENVSWITCH:
             getOvsPifs();
@@ -977,6 +991,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
             getPifs();
             break;
         }
+        */
 
         if (_pifs.get("private") == null) {
             s_logger.debug("Failed to get private nic name");
@@ -1027,19 +1042,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
             params.put("vm.migrate.speed", String.valueOf(_migrateSpeed));
         }
 
-        final Map<String, String> bridges = new HashMap<String, String>();
         bridges.put("linklocal", _linkLocalBridgeName);
         bridges.put("public", _publicBridgeName);
         bridges.put("private", _privBridgeName);
         bridges.put("guest", _guestBridgeName);
 
-        params.put("libvirt.host.bridges", bridges);
-        params.put("libvirt.host.pifs", _pifs);
-
-        params.put("libvirt.computing.resource", this);
-        params.put("libvirtVersion", _hypervisorLibvirtVersion);
+        getVifDriver(TrafficType.Control).createControlNetwork(_linkLocalBridgeName);
 
-        configureVifDrivers(params);
         configureDiskActivityChecks(params);
 
         final KVMStorageProcessor storageProcessor = new KVMStorageProcessor(_storagePoolMgr, this);
@@ -1132,6 +1141,23 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
         return vifDriver;
     }
 
+    public VifDriver getVifDriver(final TrafficType trafficType, final String bridgeName) {
+        VifDriver vifDriver = null;
+
+        for (VifDriver driver : getAllVifDrivers()) {
+            if (driver.isExistingBridge(bridgeName)) {
+                vifDriver = driver;
+                break;
+            }
+        }
+
+        if (vifDriver == null) {
+            vifDriver = getVifDriver(trafficType);
+        }
+
+        return vifDriver;
+    }
+
     public List<VifDriver> getAllVifDrivers() {
         final Set<VifDriver> vifDrivers = new HashSet<VifDriver>();
 
@@ -1160,10 +1186,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
         for (final String bridge : bridges) {
             s_logger.debug("looking for pif for bridge " + bridge);
             final String pif = getPif(bridge);
-            if (_publicBridgeName != null && bridge.equals(_publicBridgeName)) {
+            if (isPublicBridge(bridge)) {
                 _pifs.put("public", pif);
             }
-            if (_guestBridgeName != null && bridge.equals(_guestBridgeName)) {
+            if (isGuestBridge(bridge)) {
                 _pifs.put("private", pif);
             }
             _pifs.put(bridge, pif);
@@ -1194,6 +1220,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
         s_logger.debug("done looking for pifs, no more bridges");
     }
 
+    boolean isGuestBridge(String bridge) {
+        return _guestBridgeName != null && bridge.equals(_guestBridgeName);
+    }
+
     private void getOvsPifs() {
         final String cmdout = Script.runSimpleBashScript("ovs-vsctl list-br | sed '{:q;N;s/\\n/%/g;t q}'");
         s_logger.debug("cmdout was " + cmdout);
@@ -1204,10 +1234,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
             // Not really interested in the pif name at this point for ovs
             // bridges
             final String pif = bridge;
-            if (_publicBridgeName != null && bridge.equals(_publicBridgeName)) {
+            if (isPublicBridge(bridge)) {
                 _pifs.put("public", pif);
             }
-            if (_guestBridgeName != null && bridge.equals(_guestBridgeName)) {
+            if (isGuestBridge(bridge)) {
                 _pifs.put("private", pif);
             }
             _pifs.put(bridge, pif);
@@ -1215,6 +1245,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
         s_logger.debug("done looking for pifs, no more bridges");
     }
 
+    public boolean isPublicBridge(String bridge) {
+        return _publicBridgeName != null && bridge.equals(_publicBridgeName);
+    }
+
     private String getPif(final String bridge) {
         String pif = matchPifFileInDirectory(bridge);
         final File vlanfile = new File("/proc/net/vlan/" + pif);
@@ -1281,12 +1315,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
         return false;
     }
 
-    public boolean checkNetwork(final String networkName) {
+    public boolean checkNetwork(final TrafficType trafficType, final String networkName) {
         if (networkName == null) {
             return true;
         }
 
-        if (_bridgeType == BridgeType.OPENVSWITCH) {
+        if (getVifDriver(trafficType, networkName) instanceof OvsVifDriver) {
             return checkOvsNetwork(networkName);
         } else {
             return checkBridgeNetwork(networkName);
@@ -1421,7 +1455,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
 
     public synchronized boolean findOrCreateTunnelNetwork(final String nwName) {
         try {
-            if (checkNetwork(nwName)) {
+            if (checkNetwork(TrafficType.Guest, nwName)) {
                 return true;
             }
             // if not found, create a new one
@@ -2324,7 +2358,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
             }
         }
 
-        vm.getDevices().addDevice(getVifDriver(nic.getType()).plug(nic, vm.getPlatformEmulator().toString(), nicAdapter).toString());
+        vm.getDevices().addDevice(getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter));
     }
 
     public boolean cleanupDisk(final DiskDef disk) {
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index 847d775..d979d55 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -27,7 +27,7 @@ import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
-import com.google.common.base.Strings;
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -36,7 +36,8 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
-import com.cloud.utils.StringUtils;
+import com.google.common.base.Strings;
+
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
@@ -161,6 +162,8 @@ public class LibvirtDomainXMLParser {
                 String mac = getAttrValue("mac", "address", nic);
                 String dev = getAttrValue("target", "dev", nic);
                 String model = getAttrValue("model", "type", nic);
+                String slot = StringUtils.removeStart(getAttrValue("address", "slot", nic), "0x");
+
                 InterfaceDef def = new InterfaceDef();
                 NodeList bandwidth = nic.getElementsByTagName("bandwidth");
                 Integer networkRateKBps = 0;
@@ -181,6 +184,11 @@ public class LibvirtDomainXMLParser {
                     String scriptPath = getAttrValue("script", "path", nic);
                     def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps);
                 }
+
+                if (StringUtils.isNotBlank(slot)) {
+                    def.setSlot(Integer.parseInt(slot, 16));
+                }
+
                 interfaces.add(def);
             }
 
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 0f34a92..0196c85 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -16,16 +16,17 @@
 // under the License.
 package com.cloud.hypervisor.kvm.resource;
 
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.log4j.Logger;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.log4j.Logger;
+
+import com.google.common.collect.Maps;
+
 public class LibvirtVMDef {
     private static final Logger s_logger = Logger.getLogger(LibvirtVMDef.class);
 
@@ -890,7 +891,7 @@ public class LibvirtVMDef {
             }
         }
 
-        enum NicModel {
+        public enum NicModel {
             E1000("e1000"), VIRTIO("virtio"), RTL8139("rtl8139"), NE2KPCI("ne2k_pci"), VMXNET3("vmxnet3");
             String _model;
 
@@ -925,6 +926,8 @@ public class LibvirtVMDef {
         private String _virtualPortInterfaceId;
         private int _vlanTag = -1;
         private boolean _pxeDisable = false;
+        private boolean _linkStateUp = true;
+        private Integer _slot;
 
         public void defBridgeNet(String brName, String targetBrName, String macAddr, NicModel model) {
             defBridgeNet(brName, targetBrName, macAddr, model, 0);
@@ -1012,6 +1015,10 @@ public class LibvirtVMDef {
             return _networkName;
         }
 
+        public void setDevName(String networkName) {
+            _networkName = networkName;
+        }
+
         public String getMacAddress() {
             return _macAddr;
         }
@@ -1044,6 +1051,22 @@ public class LibvirtVMDef {
             return _vlanTag;
         }
 
+        public void setSlot(Integer slot) {
+            _slot = slot;
+        }
+
+        public Integer getSlot() {
+            return _slot;
+        }
+
+        public void setLinkStateUp(boolean linkStateUp) {
+            _linkStateUp = linkStateUp;
+        }
+
+        public boolean isLinkStateUp() {
+            return _linkStateUp;
+        }
+
         @Override
         public String toString() {
             StringBuilder netBuilder = new StringBuilder();
@@ -1086,6 +1109,12 @@ public class LibvirtVMDef {
             if (_vlanTag > 0 && _vlanTag < 4095) {
                 netBuilder.append("<vlan trunk='no'>\n<tag id='" + _vlanTag + "'/>\n</vlan>");
             }
+
+            netBuilder.append("<link state='" + (_linkStateUp ? "up" : "down") +"'/>\n");
+
+            if (_slot  != null) {
+                netBuilder.append(String.format("<address type='pci' domain='0x0000' bus='0x00' slot='0x%02x' function='0x0'/>\n", _slot));
+            }
             netBuilder.append("</interface>\n");
             return netBuilder.toString();
         }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
index 6462df7..06cd161 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
@@ -18,6 +18,8 @@
  */
 package com.cloud.hypervisor.kvm.resource;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.ConfigurationException;
@@ -42,6 +44,8 @@ public class OvsVifDriver extends VifDriverBase {
     public void configure(Map<String, Object> params) throws ConfigurationException {
         super.configure(params);
 
+        getPifs();
+
         String networkScriptsDir = (String)params.get("network.scripts.dir");
         if (networkScriptsDir == null) {
             networkScriptsDir = "scripts/vm/network/vnet";
@@ -49,8 +53,27 @@ public class OvsVifDriver extends VifDriverBase {
 
         String value = (String)params.get("scripts.timeout");
         _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000;
+    }
 
-        createControlNetwork(_bridges.get("linklocal"));
+    public void getPifs() {
+        final String cmdout = Script.runSimpleBashScript("ovs-vsctl list-br | sed '{:q;N;s/\\n/%/g;t q}'");
+        s_logger.debug("cmdout was " + cmdout);
+        final List<String> bridges = Arrays.asList(cmdout.split("%"));
+        for (final String bridge : bridges) {
+            s_logger.debug("looking for pif for bridge " + bridge);
+            // String pif = getOvsPif(bridge);
+            // Not really interested in the pif name at this point for ovs
+            // bridges
+            final String pif = bridge;
+            if (_libvirtComputingResource.isPublicBridge(bridge)) {
+                _pifs.put("public", pif);
+            }
+            if (_libvirtComputingResource.isGuestBridge(bridge)) {
+                _pifs.put("private", pif);
+            }
+            _pifs.put(bridge, pif);
+        }
+        s_logger.debug("done looking for pifs, no more bridges");
     }
 
     @Override
@@ -132,6 +155,17 @@ public class OvsVifDriver extends VifDriverBase {
         // Libvirt apparently takes care of this, see BridgeVifDriver unplug
     }
 
+
+    @Override
+    public void attach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("ovs-vsctl add-port " + iface.getBrName() + " " + iface.getDevName());
+    }
+
+    @Override
+    public void detach(LibvirtVMDef.InterfaceDef iface) {
+        Script.runSimpleBashScript("ovs-vsctl port-to-br " + iface.getDevName() + " && ovs-vsctl del-port " + iface.getBrName() + " " + iface.getDevName());
+    }
+
     private void deleteExitingLinkLocalRouteTable(String linkLocalBr) {
         Script command = new Script("/bin/bash", _timeout);
         command.add("-c");
@@ -156,14 +190,16 @@ public class OvsVifDriver extends VifDriverBase {
         }
     }
 
-    private void createControlNetwork(String privBrName) {
+    @Override
+    public void createControlNetwork(String privBrName) {
         deleteExitingLinkLocalRouteTable(privBrName);
-        if (!isBridgeExists(privBrName)) {
+        if (!isExistingBridge(privBrName)) {
             Script.runSimpleBashScript("ovs-vsctl add-br " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout);
         }
     }
 
-    private boolean isBridgeExists(String bridgeName) {
+    @Override
+    public boolean isExistingBridge(String bridgeName) {
         Script command = new Script("/bin/sh", _timeout);
         command.add("-c");
         command.add("ovs-vsctl br-exists " + bridgeName);
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java
index 5cd2d61..387a552 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java
@@ -36,4 +36,12 @@ public interface VifDriver {
 
     public void unplug(LibvirtVMDef.InterfaceDef iface);
 
+    void attach(LibvirtVMDef.InterfaceDef iface);
+
+    void detach(LibvirtVMDef.InterfaceDef iface);
+
+    void createControlNetwork(String privBrName);
+
+    boolean isExistingBridge(String bridgeName);
+
 }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java
index 2baec27..dad73f2 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java
@@ -63,4 +63,8 @@ public abstract class VifDriverBase implements VifDriver {
             return LibvirtVMDef.InterfaceDef.NicModel.E1000;
         }
     }
+
+    public boolean isExistingBridge(String bridgeName) {
+        return false;
+    }
 }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java
index 0d3df1f..1ce491c 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java
@@ -25,6 +25,7 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkAnswer;
 import com.cloud.agent.api.CheckNetworkCommand;
 import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.network.Networks;
 import com.cloud.network.PhysicalNetworkSetupInfo;
 import com.cloud.resource.CommandWrapper;
 import com.cloud.resource.ResourceWrapper;
@@ -38,13 +39,13 @@ public final class LibvirtCheckNetworkCommandWrapper extends CommandWrapper<Chec
         String errMsg = null;
 
         for (final PhysicalNetworkSetupInfo nic : phyNics) {
-            if (!libvirtComputingResource.checkNetwork(nic.getGuestNetworkName())) {
+            if (!libvirtComputingResource.checkNetwork(Networks.TrafficType.Guest, nic.getGuestNetworkName())) {
                 errMsg = "Can not find network: " + nic.getGuestNetworkName();
                 break;
-            } else if (!libvirtComputingResource.checkNetwork(nic.getPrivateNetworkName())) {
+            } else if (!libvirtComputingResource.checkNetwork(Networks.TrafficType.Management, nic.getPrivateNetworkName())) {
                 errMsg = "Can not find network: " + nic.getPrivateNetworkName();
                 break;
-            } else if (!libvirtComputingResource.checkNetwork(nic.getPublicNetworkName())) {
+            } else if (!libvirtComputingResource.checkNetwork(Networks.TrafficType.Public, nic.getPublicNetworkName())) {
                 errMsg = "Can not find network: " + nic.getPublicNetworkName();
                 break;
             }
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
index 018d6a7..2ee9b95 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
@@ -19,13 +19,6 @@
 
 package com.cloud.hypervisor.kvm.resource.wrapper;
 
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.libvirt.Connect;
-import org.libvirt.Domain;
-import org.libvirt.LibvirtException;
-
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.PlugNicAnswer;
 import com.cloud.agent.api.PlugNicCommand;
@@ -36,6 +29,12 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
 import com.cloud.hypervisor.kvm.resource.VifDriver;
 import com.cloud.resource.CommandWrapper;
 import com.cloud.resource.ResourceWrapper;
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.LibvirtException;
+
+import java.util.List;
 
 @ResourceWrapper(handles =  PlugNicCommand.class)
 public final class LibvirtPlugNicCommandWrapper extends CommandWrapper<PlugNicCommand, Answer, LibvirtComputingResource> {
@@ -61,7 +60,7 @@ public final class LibvirtPlugNicCommandWrapper extends CommandWrapper<PlugNicCo
                 }
                 nicnum++;
             }
-            final VifDriver vifDriver = libvirtComputingResource.getVifDriver(nic.getType());
+            final VifDriver vifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName());
             final InterfaceDef interfaceDef = vifDriver.plug(nic, "Other PV", "");
             vm.attachDevice(interfaceDef.toString());
 
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
index 2dfca5d..940a0a7 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
@@ -19,12 +19,6 @@
 
 package com.cloud.hypervisor.kvm.resource.wrapper;
 
-import java.net.URISyntaxException;
-
-import org.apache.log4j.Logger;
-import org.libvirt.Connect;
-import org.libvirt.LibvirtException;
-
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.PrepareForMigrationAnswer;
 import com.cloud.agent.api.PrepareForMigrationCommand;
@@ -37,6 +31,11 @@ import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
 import com.cloud.resource.CommandWrapper;
 import com.cloud.resource.ResourceWrapper;
 import com.cloud.storage.Volume;
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.LibvirtException;
+
+import java.net.URISyntaxException;
 
 @ResourceWrapper(handles =  PrepareForMigrationCommand.class)
 public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapper<PrepareForMigrationCommand, Answer, LibvirtComputingResource> {
@@ -60,7 +59,7 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp
 
             final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vm.getName());
             for (final NicTO nic : nics) {
-                libvirtComputingResource.getVifDriver(nic.getType()).plug(nic, null, "");
+                libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "");
             }
 
             /* setup disks, e.g for iso */
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java
new file mode 100644
index 0000000..8c20a33
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java
@@ -0,0 +1,133 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.hypervisor.kvm.resource.wrapper;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.LibvirtException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.ReplugNicAnswer;
+import com.cloud.agent.api.ReplugNicCommand;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.exception.InternalErrorException;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
+import com.cloud.hypervisor.kvm.resource.VifDriver;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+
+@ResourceWrapper(handles =  ReplugNicCommand.class)
+public final class LibvirtReplugNicCommandWrapper extends CommandWrapper<ReplugNicCommand, Answer, LibvirtComputingResource> {
+
+    private static final Logger s_logger = Logger.getLogger(LibvirtReplugNicCommandWrapper.class);
+    public enum DomainAffect {
+        CURRENT(0), LIVE(1), CONFIG(2), BOTH(3);
+
+        private int value;
+        DomainAffect(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    @Override
+    public Answer execute(final ReplugNicCommand command, final LibvirtComputingResource libvirtComputingResource) {
+        final NicTO nic = command.getNic();
+        final String vmName = command.getVmName();
+        Domain vm = null;
+        try {
+            final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
+            final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
+            vm = libvirtComputingResource.getDomain(conn, vmName);
+
+            InterfaceDef oldPluggedNic = findPluggedNic(libvirtComputingResource, nic, vmName, conn);
+
+            final VifDriver newVifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName());
+            final InterfaceDef interfaceDef = newVifDriver.plug(nic, "Other PV", oldPluggedNic.getModel().toString());
+
+            interfaceDef.setSlot(oldPluggedNic.getSlot());
+            interfaceDef.setDevName(oldPluggedNic.getDevName());
+            interfaceDef.setLinkStateUp(false);
+
+            oldPluggedNic.setSlot(null);
+
+            int i = 0;
+            do {
+                i++;
+                s_logger.debug("ReplugNic: Detaching interface" + oldPluggedNic + " (Attempt: " + i + ")");
+                vm.detachDevice(oldPluggedNic.toString());
+            } while (findPluggedNic(libvirtComputingResource, nic, vmName, conn) != null && i <= 10);
+
+            s_logger.debug("ReplugNic: Attaching interface" + interfaceDef);
+            vm.attachDevice(interfaceDef.toString());
+
+            interfaceDef.setLinkStateUp(true);
+            s_logger.debug("ReplugNic: Updating interface" + interfaceDef);
+            vm.updateDeviceFlags(interfaceDef.toString(), DomainAffect.LIVE.getValue());
+
+            /*
+            // Manual replug
+            for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) {
+                vifDriver.detach(oldPluggedNic);
+            }
+            newVifDriver.attach(interfaceDef);
+            */
+
+            // We don't know which "traffic type" is associated with
+            // each interface at this point, so inform all vif drivers
+            for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) {
+                vifDriver.unplug(oldPluggedNic);
+            }
+
+            return new ReplugNicAnswer(command, true, "success");
+        } catch (final LibvirtException | InternalErrorException e) {
+            final String msg = " Plug Nic failed due to " + e.toString();
+            s_logger.warn(msg, e);
+            return new ReplugNicAnswer(command, false, msg);
+        } finally {
+            if (vm != null) {
+                try {
+                    vm.free();
+                } catch (final LibvirtException l) {
+                    s_logger.trace("Ignoring libvirt error.", l);
+                }
+            }
+        }
+    }
+
+    private InterfaceDef findPluggedNic(LibvirtComputingResource libvirtComputingResource, NicTO nic, String vmName, Connect conn) {
+        InterfaceDef oldPluggedNic = null;
+
+        final List<InterfaceDef> pluggedNics = libvirtComputingResource.getInterfaces(conn, vmName);
+
+        for (final InterfaceDef pluggedNic : pluggedNics) {
+            if (pluggedNic.getMacAddress().equalsIgnoreCase(nic.getMac())) {
+                oldPluggedNic = pluggedNic;
+            }
+        }
+
+        return oldPluggedNic;
+    }
+}
\ No newline at end of file
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
index b3f8530..2fd7692 100644
--- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
@@ -19,16 +19,6 @@
 
 package com.cloud.hypervisor.kvm.resource;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -48,11 +38,6 @@ import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
-import org.apache.cloudstack.storage.command.AttachAnswer;
-import org.apache.cloudstack.storage.command.AttachCommand;
-import org.apache.cloudstack.utils.linux.CPUStat;
-import org.apache.cloudstack.utils.linux.MemStat;
-import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 import org.apache.commons.lang.SystemUtils;
 import org.joda.time.Duration;
 import org.junit.Assert;
@@ -78,6 +63,12 @@ import org.mockito.runners.MockitoJUnitRunner;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
 
+import org.apache.cloudstack.storage.command.AttachAnswer;
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.utils.linux.CPUStat;
+import org.apache.cloudstack.utils.linux.MemStat;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachIsoCommand;
 import com.cloud.agent.api.BackupSnapshotCommand;
@@ -178,6 +169,16 @@ import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.Type;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 @RunWith(MockitoJUnitRunner.class)
 public class LibvirtComputingResourceTest {
 
@@ -1021,7 +1022,7 @@ public class LibvirtComputingResourceTest {
         when(nicTO.getType()).thenReturn(TrafficType.Guest);
         when(diskTO.getType()).thenReturn(Volume.Type.ISO);
 
-        when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver);
+        when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver);
         when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager);
 
         final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
@@ -1069,7 +1070,7 @@ public class LibvirtComputingResourceTest {
         when(nicTO.getType()).thenReturn(TrafficType.Guest);
         when(diskTO.getType()).thenReturn(Volume.Type.ISO);
 
-        when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver);
+        when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver);
         when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager);
         when(storagePoolManager.connectPhysicalDisksViaVmSpec(vm)).thenReturn(true);
 
@@ -1161,7 +1162,7 @@ public class LibvirtComputingResourceTest {
         when(nicTO.getType()).thenReturn(TrafficType.Guest);
         when(volume.getType()).thenReturn(Volume.Type.ISO);
 
-        when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver);
+        when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver);
         when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager);
         try {
             when(libvirtComputingResource.getVolumePath(conn, volume)).thenThrow(URISyntaxException.class);
@@ -1213,7 +1214,7 @@ public class LibvirtComputingResourceTest {
         when(vm.getNics()).thenReturn(new NicTO[]{nicTO});
         when(nicTO.getType()).thenReturn(TrafficType.Guest);
 
-        when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenThrow(InternalErrorException.class);
+        when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenThrow(InternalErrorException.class);
         when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager);
         try {
             when(libvirtComputingResource.getVolumePath(conn, volume)).thenReturn("/path");
@@ -2550,9 +2551,9 @@ public class LibvirtComputingResourceTest {
 
         final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList);
 
-        when(libvirtComputingResource.checkNetwork(nic.getGuestNetworkName())).thenReturn(true);
-        when(libvirtComputingResource.checkNetwork(nic.getPrivateNetworkName())).thenReturn(true);
-        when(libvirtComputingResource.checkNetwork(nic.getPublicNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Guest, nic.getGuestNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Management, nic.getPrivateNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Public, nic.getPublicNetworkName())).thenReturn(true);
 
         final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
         assertNotNull(wrapper);
@@ -2560,9 +2561,9 @@ public class LibvirtComputingResourceTest {
         final Answer answer = wrapper.execute(command, libvirtComputingResource);
         assertTrue(answer.getResult());
 
-        verify(libvirtComputingResource, times(3)).checkNetwork(nic.getGuestNetworkName());
-        verify(libvirtComputingResource, times(3)).checkNetwork(nic.getPrivateNetworkName());
-        verify(libvirtComputingResource, times(3)).checkNetwork(nic.getPublicNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, nic.getGuestNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, nic.getPrivateNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Public, nic.getPublicNetworkName());
     }
 
     @Test
@@ -2574,7 +2575,7 @@ public class LibvirtComputingResourceTest {
 
         final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList);
 
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(false);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(false);
 
         final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
         assertNotNull(wrapper);
@@ -2582,7 +2583,7 @@ public class LibvirtComputingResourceTest {
         final Answer answer = wrapper.execute(command, libvirtComputingResource);
         assertFalse(answer.getResult());
 
-        verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName());
     }
 
     @Test
@@ -2594,8 +2595,8 @@ public class LibvirtComputingResourceTest {
 
         final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList);
 
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(true);
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPrivateNetworkName())).thenReturn(false);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName())).thenReturn(false);
 
         final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
         assertNotNull(wrapper);
@@ -2603,8 +2604,8 @@ public class LibvirtComputingResourceTest {
         final Answer answer = wrapper.execute(command, libvirtComputingResource);
         assertFalse(answer.getResult());
 
-        verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName());
-        verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getPrivateNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName());
     }
 
     @Test
@@ -2616,9 +2617,9 @@ public class LibvirtComputingResourceTest {
 
         final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList);
 
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(true);
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPrivateNetworkName())).thenReturn(true);
-        when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPublicNetworkName())).thenReturn(false);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName())).thenReturn(true);
+        when(libvirtComputingResource.checkNetwork(TrafficType.Public, networkSetupInfo.getPublicNetworkName())).thenReturn(false);
 
         final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
         assertNotNull(wrapper);
@@ -2626,8 +2627,8 @@ public class LibvirtComputingResourceTest {
         final Answer answer = wrapper.execute(command, libvirtComputingResource);
         assertFalse(answer.getResult());
 
-        verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName());
-        verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getPrivateNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName());
+        verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName());
     }
 
     @Test
@@ -3151,12 +3152,13 @@ public class LibvirtComputingResourceTest {
         when(intDef.getMacAddress()).thenReturn("00:00:00:00");
 
         when(nic.getMac()).thenReturn("00:00:00:01");
+        when(nic.getName()).thenReturn("br0");
 
         try {
             when(libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName())).thenReturn(conn);
             when(libvirtComputingResource.getDomain(conn, instanceName)).thenReturn(vm);
 
-            when(libvirtComputingResource.getVifDriver(nic.getType())).thenReturn(vifDriver);
+            when(libvirtComputingResource.getVifDriver(nic.getType(), nic.getName())).thenReturn(vifDriver);
 
             when(vifDriver.plug(nic, "Other PV", "")).thenReturn(interfaceDef);
             when(interfaceDef.toString()).thenReturn("Interface");
@@ -3180,7 +3182,7 @@ public class LibvirtComputingResourceTest {
         try {
             verify(libvirtUtilitiesHelper, times(1)).getConnectionByVmName(command.getVmName());
             verify(libvirtComputingResource, times(1)).getDomain(conn, instanceName);
-            verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType());
+            verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType(), nic.getName());
             verify(vifDriver, times(1)).plug(nic, "Other PV", "");
         } catch (final LibvirtException e) {
             fail(e.getMessage());
@@ -3253,7 +3255,7 @@ public class LibvirtComputingResourceTest {
             when(libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName())).thenReturn(conn);
             when(libvirtComputingResource.getDomain(conn, instanceName)).thenReturn(vm);
 
-            when(libvirtComputingResource.getVifDriver(nic.getType())).thenReturn(vifDriver);
+            when(libvirtComputingResource.getVifDriver(nic.getType(), nic.getName())).thenReturn(vifDriver);
 
             when(vifDriver.plug(nic, "Other PV", "")).thenThrow(InternalErrorException.class);
 
@@ -3273,7 +3275,7 @@ public class LibvirtComputingResourceTest {
         try {
             verify(libvirtUtilitiesHelper, times(1)).getConnectionByVmName(command.getVmName());
             verify(libvirtComputingResource, times(1)).getDomain(conn, instanceName);
-            verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType());
+            verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType(), nic.getName());
             verify(vifDriver, times(1)).plug(nic, "Other PV", "");
         } catch (final LibvirtException e) {
             fail(e.getMessage());
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
index 78c4e86..9197013 100644
--- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
@@ -19,14 +19,15 @@
 
 package com.cloud.hypervisor.kvm.resource;
 
-import junit.framework.TestCase;
-
 import java.io.File;
 import java.util.List;
+
+import junit.framework.TestCase;
+
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
-import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
 
 public class LibvirtDomainXMLParserTest extends TestCase {
@@ -227,6 +228,8 @@ public class LibvirtDomainXMLParserTest extends TestCase {
         for (int i = 0; i < ifs.size(); i++) {
             assertEquals(ifModel, ifs.get(i).getModel());
             assertEquals(ifType, ifs.get(i).getNetType());
+            assertEquals(Integer.valueOf(i + 3), ifs.get(i).getSlot());
+            assertEquals("vnet" + i, ifs.get(i).getDevName());
         }
 
         List<RngDef> rngs = parser.getRngs();
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
index e758dec..006562c 100644
--- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
@@ -19,14 +19,15 @@
 
 package com.cloud.hypervisor.kvm.resource;
 
+import java.io.File;
+
 import junit.framework.TestCase;
-import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
+
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
 import com.cloud.utils.Pair;
 
-import java.io.File;
-
 public class LibvirtVMDefTest extends TestCase {
 
     public void testInterfaceEtehrnet() {
@@ -34,8 +35,12 @@ public class LibvirtVMDefTest extends TestCase {
         ifDef.defEthernet("targetDeviceName", "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO);
 
         String expected =
-            "<interface type='ethernet'>\n" + "<target dev='targetDeviceName'/>\n" + "<mac address='00:11:22:aa:bb:dd'/>\n" + "<model type='virtio'/>\n"
-                + "</interface>\n";
+            "<interface type='ethernet'>\n"
+                    + "<target dev='targetDeviceName'/>\n"
+                    + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                    + "<model type='virtio'/>\n"
+                    + "<link state='up'/>\n"
+                    + "</interface>\n";
 
         assertEquals(expected, ifDef.toString());
     }
@@ -45,8 +50,44 @@ public class LibvirtVMDefTest extends TestCase {
         ifDef.defDirectNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO, "private");
 
         String expected =
-            "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.DIRECT + "'>\n" + "<source dev='targetDeviceName' mode='private'/>\n" +
-                "<mac address='00:11:22:aa:bb:dd'/>\n" + "<model type='virtio'/>\n" + "</interface>\n";
+            "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.DIRECT + "'>\n"
+                    + "<source dev='targetDeviceName' mode='private'/>\n"
+                    + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                    + "<model type='virtio'/>\n"
+                    + "<link state='up'/>\n"
+                    + "</interface>\n";
+
+        assertEquals(expected, ifDef.toString());
+    }
+
+    public void testInterfaceBridgeSlot() {
+        LibvirtVMDef.InterfaceDef ifDef = new LibvirtVMDef.InterfaceDef();
+        ifDef.defBridgeNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO);
+        ifDef.setSlot(16);
+
+        String expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<link state='up'/>\n"
+                        + "<address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/>\n"
+                        + "</interface>\n";
+
+        assertEquals(expected, ifDef.toString());
+
+        ifDef.setLinkStateUp(false);
+        ifDef.setDevName("vnet11");
+
+        expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<target dev='vnet11'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<link state='down'/>\n"
+                        + "<address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/>\n"
+                        + "</interface>\n";
 
         assertEquals(expected, ifDef.toString());
     }
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java
new file mode 100644
index 0000000..86e455b
--- /dev/null
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java
@@ -0,0 +1,274 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.hypervisor.kvm.resource.wrapper;
+
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.LibvirtException;
+import org.mockito.BDDMockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.ReplugNicCommand;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.hypervisor.kvm.resource.BridgeVifDriver;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.OvsVifDriver;
+import com.cloud.network.Networks;
+import com.cloud.utils.script.Script;
+import com.cloud.vm.VirtualMachine;
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(Script.class)
+public class LibvirtReplugNicCommandWrapperTest {
+    private static final String part_1 =
+            "<domain type='kvm' id='143'>\n"
+            + "  <name>i-85-285-VM</name>\n"
+            + "  <uuid>8825b180-468f-4227-beb7-6b06fd342116</uuid>\n"
+            + "  <description>CentOS 5.5 (64-bit)</description>\n"
+            + "  <memory unit='KiB'>262144</memory>\n"
+            + "  <currentMemory unit='KiB'>262144</currentMemory>\n"
+            + "  <vcpu placement='static'>1</vcpu>\n"
+            + "  <cputune>\n"
+            + "    <shares>256</shares>\n"
+            + "  </cputune>\n"
+            + "  <sysinfo type='smbios'>\n"
+            + "    <system>\n"
+            + "      <entry name='manufacturer'>Apache Software Foundation</entry>\n"
+            + "      <entry name='product'>CloudStack KVM Hypervisor</entry>\n"
+            + "      <entry name='uuid'>8825b180-468f-4227-beb7-6b06fd342116</entry>\n"
+            + "    </system>\n"
+            + "  </sysinfo>\n"
+            + "  <os>\n"
+            + "    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>\n"
+            + "    <boot dev='cdrom'/>\n"
+            + "    <boot dev='hd'/>\n"
+            + "    <smbios mode='sysinfo'/>\n"
+            + "  </os>\n"
+            + "  <features>\n"
+            + "    <acpi/>\n"
+            + "    <apic/>\n"
+            + "    <pae/>\n"
+            + "  </features>\n"
+            + "  <clock offset='utc'>\n"
+            + "    <timer name='kvmclock'/>\n"
+            + "  </clock>\n"
+            + "  <on_poweroff>destroy</on_poweroff>\n"
+            + "  <on_reboot>restart</on_reboot>\n"
+            + "  <on_crash>destroy</on_crash>\n"
+            + "  <devices>\n"
+            + "    <emulator>/usr/libexec/qemu-kvm</emulator>\n"
+            + "    <disk type='file' device='disk'>\n"
+            + "      <driver name='qemu' type='qcow2' cache='none'/>\n"
+            + "      <source file='/mnt/4436eeec-abec-3ef8-b733-c9541df20361/0c4aae69-2652-4a04-b460-1abb5a1a695c'/>\n"
+            + "      <backingStore type='file' index='1'>\n"
+            + "        <format type='raw'/>\n"
+            + "        <source file='/mnt/4436eeec-abec-3ef8-b733-c9541df20361/d9ce07e5-9e13-11e7-816b-faac09070700'/>\n"
+            + "        <backingStore/>\n"
+            + "      </backingStore>\n"
+            + "      <target dev='vda' bus='virtio'/>\n"
+            + "      <serial>0c4aae6926524a04b460</serial>\n"
+            + "      <alias name='virtio-disk0'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n"
+            + "    </disk>\n"
+            + "    <disk type='file' device='cdrom'>\n"
+            + "      <driver name='qemu' type='raw' cache='none'/>\n"
+            + "      <backingStore/>\n"
+            + "      <target dev='hdc' bus='ide'/>\n"
+            + "      <readonly/>\n"
+            + "      <alias name='ide0-1-0'/>\n"
+            + "      <address type='drive' controller='0' bus='1' target='0' unit='0'/>\n"
+            + "    </disk>\n"
+            + "    <controller type='usb' index='0'>\n"
+            + "      <alias name='usb'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>\n"
+            + "    </controller>\n"
+            + "    <controller type='pci' index='0' model='pci-root'>\n"
+            + "      <alias name='pci.0'/>\n"
+            + "    </controller>\n"
+            + "    <controller type='ide' index='0'>\n"
+            + "      <alias name='ide'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>\n"
+            + "    </controller>\n"
+            + "    <controller type='virtio-serial' index='0'>\n"
+            + "      <alias name='virtio-serial0'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n"
+            + "    </controller>\n";
+    private static final String part_2 =
+            "    <interface type='bridge'>\n"
+            + "      <mac address='02:00:7c:98:00:02'/>\n"
+            + "      <source bridge='breth2-234'/>\n"
+            + "      <bandwidth>\n"
+            + "        <inbound average='25600' peak='25600'/>\n"
+            + "        <outbound average='25600' peak='25600'/>\n"
+            + "      </bandwidth>\n"
+            + "      <target dev='vnet10'/>\n"
+            + "      <model type='virtio'/>\n"
+            + "      <link state='up'/>\n"
+            + "      <alias name='net0'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n"
+            + "    </interface>\n";
+    private static final String part_3 =
+            "    <serial type='pty'>\n"
+            + "      <source path='/dev/pts/4'/>\n"
+            + "      <target port='0'/>\n"
+            + "      <alias name='serial0'/>\n"
+            + "    </serial>\n"
+            + "    <console type='pty' tty='/dev/pts/4'>\n"
+            + "      <source path='/dev/pts/4'/>\n"
+            + "      <target type='serial' port='0'/>\n"
+            + "      <alias name='serial0'/>\n"
+            + "    </console>\n"
+            + "    <channel type='unix'>\n"
+            + "      <source mode='bind' path='/var/lib/libvirt/qemu/i-85-285-VM.org.qemu.guest_agent.0'/>\n"
+            + "      <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/>\n"
+            + "      <alias name='channel0'/>\n"
+            + "      <address type='virtio-serial' controller='0' bus='0' port='1'/>\n"
+            + "    </channel>\n"
+            + "    <input type='tablet' bus='usb'>\n"
+            + "      <alias name='input0'/>\n"
+            + "    </input>\n"
+            + "    <input type='mouse' bus='ps2'/>\n"
+            + "    <input type='keyboard' bus='ps2'/>\n"
+            + "    <graphics type='vnc' port='5903' autoport='yes' listen='10.100.100.11'>\n"
+            + "      <listen type='address' address='10.100.100.11'/>\n"
+            + "    </graphics>\n"
+            + "    <video>\n"
+            + "      <model type='cirrus' vram='16384' heads='1'/>\n"
+            + "      <alias name='video0'/>\n"
+            + "      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>\n"
+            + "    </video>\n"
+            + "    <memballoon model='none'>\n"
+            + "      <alias name='balloon0'/>\n"
+            + "    </memballoon>\n"
+            + "  </devices>\n"
+            + "</domain>\n";
+
+    private static final String fullfile = part_1 + part_2 + part_3;
+
+    private LibvirtComputingResource res;
+    private final Domain _domain = mock(Domain.class);
+
+    @Before
+    public void setUp() throws LibvirtException, ConfigurationException {
+        // Use a spy because we only want to override getVifDriverClass
+        LibvirtComputingResource resReal = new LibvirtComputingResource();
+        res = spy(resReal);
+
+        Connect conn = mock(Connect.class);
+        LibvirtUtilitiesHelper helper = mock(LibvirtUtilitiesHelper.class);
+
+        when(_domain.getXMLDesc(0))
+                .thenReturn(fullfile)
+                .thenReturn(part_1 + part_3);
+        when(conn.domainLookupByName(anyString())).thenReturn(_domain);
+        when(helper.getConnectionByVmName(anyString())).thenReturn(conn);
+        PowerMockito.mockStatic(Script.class);
+        BDDMockito.given(Script.findScript(anyString(), anyString())).willReturn("dummypath/tofile.sh");
+
+        Map<String, String> pifs = new HashMap<>();
+        pifs.put("alubr0", "alubr0");
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("libvirt.computing.resource", res);
+        params.put("libvirt.host.pifs", pifs);
+
+        BridgeVifDriver bridgeVifDriver = spy(new BridgeVifDriver());
+        OvsVifDriver ovsVifDriver = spy(new OvsVifDriver());
+
+        doNothing().when(bridgeVifDriver).getPifs();
+        doNothing().when(ovsVifDriver).getPifs();
+
+        doReturn(helper).when(res).getLibvirtUtilitiesHelper();
+        doReturn(bridgeVifDriver).when(res).getVifDriver(eq(Networks.TrafficType.Guest), anyString());
+        doReturn(ovsVifDriver).when(res).getVifDriver(Networks.TrafficType.Guest, "alubr0");
+        doReturn(bridgeVifDriver).when(res).getVifDriver(not(eq(Networks.TrafficType.Guest)));
+        doReturn(Arrays.asList(bridgeVifDriver, ovsVifDriver)).when(res).getAllVifDrivers();
+
+        bridgeVifDriver.configure(params);
+        ovsVifDriver.configure(params);
+    }
+
+    @Test
+    public void testReplugNic() throws LibvirtException {
+
+        final String expectedDetachXml =
+                "<interface type='bridge'>\n"
+                        + "<source bridge='breth2-234'/>\n"
+                        + "<target dev='vnet10'/>\n"
+                        + "<mac address='02:00:7c:98:00:02'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<link state='up'/>\n"
+                        + "</interface>\n";
+        final String expectedAttachXml =
+                "<interface type='bridge'>\n"
+                        + "<source bridge='alubr0'/>\n"
+                        + "<target dev='vnet10'/>\n"
+                        + "<mac address='02:00:7c:98:00:02'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<virtualport type='openvswitch'>\n"
+                        + "</virtualport>\n"
+                        + "<link state='down'/>\n"
+                        + "<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n"
+                        + "</interface>\n";
+        final String expectedUpdateXml =
+                "<interface type='bridge'>\n"
+                        + "<source bridge='alubr0'/>\n"
+                        + "<target dev='vnet10'/>\n"
+                        + "<mac address='02:00:7c:98:00:02'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<virtualport type='openvswitch'>\n"
+                        + "</virtualport>\n"
+                        + "<link state='up'/>\n"
+                        + "<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n"
+                        + "</interface>\n";
+
+        final LibvirtReplugNicCommandWrapper wrapper = new LibvirtReplugNicCommandWrapper();
+        final NicTO nic = new NicTO();
+        nic.setType(Networks.TrafficType.Guest);
+        nic.setName("alubr0");
+        nic.setBroadcastType(Networks.BroadcastDomainType.Vsp);
+        nic.setMac("02:00:7c:98:00:02");
+        final ReplugNicCommand command = new ReplugNicCommand(nic, "i-85-285-VM", VirtualMachine.Type.User);
+        final Answer result = wrapper.execute(command, res);
+
+        verify(_domain).detachDevice(expectedDetachXml);
+        verify(_domain).attachDevice(expectedAttachXml);
+        verify(_domain).updateDeviceFlags(expectedUpdateXml, LibvirtReplugNicCommandWrapper.DomainAffect.LIVE.getValue());
+    }
+
+}
diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManager.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManager.java
index e7a7a95..c44a123 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManager.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManager.java
@@ -25,6 +25,8 @@ import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.agent.api.PlugNicAnswer;
 import com.cloud.agent.api.PlugNicCommand;
 import com.cloud.agent.api.PvlanSetupCommand;
+import com.cloud.agent.api.ReplugNicAnswer;
+import com.cloud.agent.api.ReplugNicCommand;
 import com.cloud.agent.api.SetupGuestNetworkCommand;
 import com.cloud.agent.api.UnPlugNicAnswer;
 import com.cloud.agent.api.UnPlugNicCommand;
@@ -70,6 +72,8 @@ public interface MockNetworkManager extends Manager {
 
     UnPlugNicAnswer unplugNic(UnPlugNicCommand cmd);
 
+    ReplugNicAnswer replugNic(ReplugNicCommand cmd);
+
     IpAssocAnswer ipAssoc(IpAssocVpcCommand cmd);
 
     SetSourceNatAnswer setSourceNat(SetSourceNatCommand cmd);
diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManagerImpl.java
index 0251c0c..41f9ce2 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManagerImpl.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockNetworkManagerImpl.java
@@ -30,6 +30,8 @@ import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.agent.api.PlugNicAnswer;
 import com.cloud.agent.api.PlugNicCommand;
 import com.cloud.agent.api.PvlanSetupCommand;
+import com.cloud.agent.api.ReplugNicAnswer;
+import com.cloud.agent.api.ReplugNicCommand;
 import com.cloud.agent.api.SetupGuestNetworkCommand;
 import com.cloud.agent.api.UnPlugNicAnswer;
 import com.cloud.agent.api.UnPlugNicCommand;
@@ -134,14 +136,25 @@ public class MockNetworkManagerImpl extends ManagerBase implements MockNetworkMa
     public UnPlugNicAnswer unplugNic(UnPlugNicCommand cmd) {
         String vmname = cmd.getVmName();
         if (_mockVmDao.findByVmName(vmname) != null) {
-            s_logger.debug("Plugged NIC (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
+            s_logger.debug("Unplugged NIC (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
             return new UnPlugNicAnswer(cmd, true, "success");
         }
-        s_logger.error("Plug NIC failed for (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
+        s_logger.error("Unplug NIC failed for (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
         return new UnPlugNicAnswer(cmd, false, "failure");
     }
 
     @Override
+    public ReplugNicAnswer replugNic(ReplugNicCommand cmd) {
+        String vmname = cmd.getVmName();
+        if (_mockVmDao.findByVmName(vmname) != null) {
+            s_logger.debug("Replugged NIC (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
+            return new ReplugNicAnswer(cmd, true, "success");
+        }
+        s_logger.error("Replug NIC failed for (dev=" + cmd.getNic().getDeviceId() + ", " + cmd.getNic().getIp() + ") into " + cmd.getVmName());
+        return new ReplugNicAnswer(cmd, false, "failure");
+    }
+
+    @Override
     public IpAssocAnswer ipAssoc(IpAssocVpcCommand cmd) {
         String[] results = new String[cmd.getIpAddresses().length];
         int i = 0;
diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java
index ae06a12..38c2a8e 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java
@@ -26,6 +26,12 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonReader;
+
 import org.apache.cloudstack.ca.SetupCertificateCommand;
 import org.apache.cloudstack.ca.SetupKeyStoreCommand;
 import org.apache.cloudstack.storage.command.DeleteCommand;
@@ -33,8 +39,6 @@ import org.apache.cloudstack.storage.command.DownloadCommand;
 import org.apache.cloudstack.storage.command.DownloadProgressCommand;
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.cloudstack.storage.command.UploadStatusCommand;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachIsoCommand;
@@ -71,6 +75,7 @@ import com.cloud.agent.api.PlugNicCommand;
 import com.cloud.agent.api.PrepareForMigrationCommand;
 import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.agent.api.RebootCommand;
+import com.cloud.agent.api.ReplugNicCommand;
 import com.cloud.agent.api.RevertToVMSnapshotCommand;
 import com.cloud.agent.api.ScaleVmCommand;
 import com.cloud.agent.api.SecStorageFirewallCfgCommand;
@@ -131,8 +136,6 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VirtualMachine.PowerState;
-import com.google.gson.Gson;
-import com.google.gson.stream.JsonReader;
 
 @Component
 public class SimulatorManagerImpl extends ManagerBase implements SimulatorManager, PluggableService {
@@ -392,6 +395,8 @@ public class SimulatorManagerImpl extends ManagerBase implements SimulatorManage
                     answer = _mockNetworkMgr.plugNic((PlugNicCommand)cmd);
                 } else if (cmd instanceof UnPlugNicCommand) {
                     answer = _mockNetworkMgr.unplugNic((UnPlugNicCommand)cmd);
+                } else if (cmd instanceof ReplugNicCommand) {
+                    answer = _mockNetworkMgr.replugNic((ReplugNicCommand)cmd);
                 } else if (cmd instanceof IpAssocVpcCommand) {
                     answer = _mockNetworkMgr.ipAssoc((IpAssocVpcCommand)cmd);
                 } else if (cmd instanceof SetSourceNatCommand) {
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 40ffdf4..7aac8ce 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -53,9 +53,9 @@ import com.vmware.vim25.AboutInfo;
 import com.vmware.vim25.BoolPolicy;
 import com.vmware.vim25.ComputeResourceSummary;
 import com.vmware.vim25.CustomFieldStringValue;
-import com.vmware.vim25.DasVmPriority;
 import com.vmware.vim25.DVPortConfigInfo;
 import com.vmware.vim25.DVPortConfigSpec;
+import com.vmware.vim25.DasVmPriority;
 import com.vmware.vim25.DatastoreSummary;
 import com.vmware.vim25.DistributedVirtualPort;
 import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
@@ -178,6 +178,8 @@ import com.cloud.agent.api.ReadyCommand;
 import com.cloud.agent.api.RebootAnswer;
 import com.cloud.agent.api.RebootCommand;
 import com.cloud.agent.api.RebootRouterCommand;
+import com.cloud.agent.api.ReplugNicAnswer;
+import com.cloud.agent.api.ReplugNicCommand;
 import com.cloud.agent.api.RevertToVMSnapshotAnswer;
 import com.cloud.agent.api.RevertToVMSnapshotCommand;
 import com.cloud.agent.api.ScaleVmAnswer;
@@ -491,6 +493,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 answer = execute((CheckNetworkCommand)cmd);
             } else if (clz == PlugNicCommand.class) {
                 answer = execute((PlugNicCommand)cmd);
+            } else if (clz == ReplugNicCommand.class) {
+                answer = execute((ReplugNicCommand)cmd);
             } else if (clz == UnPlugNicCommand.class) {
                 answer = execute((UnPlugNicCommand)cmd);
             } else if (cmd instanceof CreateVMSnapshotCommand) {
@@ -1116,6 +1120,87 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    private ReplugNicAnswer execute(ReplugNicCommand cmd) {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info("Executing resource ReplugNicCommand " + _gson.toJson(cmd));
+        }
+
+        getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+        VmwareContext context = getServiceContext();
+        try {
+            VmwareHypervisorHost hyperHost = getHyperHost(context);
+
+            String vmName = cmd.getVmName();
+            VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
+
+            if (vmMo == null) {
+                if (hyperHost instanceof HostMO) {
+                    ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor());
+                    vmMo = clusterMo.findVmOnHyperHost(vmName);
+                }
+            }
+
+            if (vmMo == null) {
+                String msg = "Router " + vmName + " no longer exists to execute ReplugNic command";
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+
+            /*
+            if(!isVMWareToolsInstalled(vmMo)){
+                String errMsg = "vmware tools is not installed or not running, cannot add nic to vm " + vmName;
+                s_logger.debug(errMsg);
+                return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + errMsg);
+            }
+             */
+            // Fallback to E1000 if no specific nicAdapter is passed
+            VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000;
+            Map<String, String> details = cmd.getDetails();
+            if (details != null) {
+                nicDeviceType = VirtualEthernetCardType.valueOf((String) details.get("nicAdapter"));
+            }
+
+            NicTO nicTo = cmd.getNic();
+
+            VirtualDevice nic = findVirtualNicDevice(vmMo, nicTo.getMac());
+            if (nic == null) {
+                return new ReplugNicAnswer(cmd, false, "Nic to replug not found");
+            }
+
+            Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, cmd.getVMType());
+            String dvSwitchUuid = null;
+            if (VmwareHelper.isDvPortGroup(networkInfo.first())) {
+                ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter();
+                DatacenterMO dataCenterMo = new DatacenterMO(context, dcMor);
+                ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first());
+                dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);
+                s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid);
+                VmwareHelper.updateDvNicDevice(nic, networkInfo.first(), dvSwitchUuid);
+            } else {
+                s_logger.info("Preparing NIC device on network " + networkInfo.second());
+
+                VmwareHelper.updateNicDevice(nic, networkInfo.first(), networkInfo.second());
+            }
+
+            VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
+            //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
+            VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
+            deviceConfigSpec.setDevice(nic);
+            deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
+
+            vmConfigSpec.getDeviceChange().add(deviceConfigSpec);
+            setNuageVspVrIpInExtraConfig(vmConfigSpec.getExtraConfig(), nicTo, dvSwitchUuid);
+            if (!vmMo.configureVm(vmConfigSpec)) {
+                throw new Exception("Failed to configure devices when running ReplugNicCommand");
+            }
+
+            return new ReplugNicAnswer(cmd, true, "success");
+        } catch (Exception e) {
+            s_logger.error("Unexpected exception: ", e);
+            return new ReplugNicAnswer(cmd, false, "Unable to execute ReplugNicCommand due to " + e.toString());
+        }
+    }
+
     private UnPlugNicAnswer execute(UnPlugNicCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource UnPlugNicCommand " + _gson.toJson(cmd));
diff --git a/plugins/network-elements/nuage-vsp/pom.xml b/plugins/network-elements/nuage-vsp/pom.xml
index fe51c8b..bea8cb9 100644
--- a/plugins/network-elements/nuage-vsp/pom.xml
+++ b/plugins/network-elements/nuage-vsp/pom.xml
@@ -35,7 +35,7 @@
     </repository>
   </repositories>
   <properties>
-      <nuage.vsp.client.version>1.0.5</nuage.vsp.client.version>
+      <nuage.vsp.client.version>1.0.6</nuage.vsp.client.version>
   </properties>
   <dependencies>
     <dependency>
diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java
index 16cbc9d..e91901a 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java
+++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java
@@ -19,40 +19,7 @@
 
 package com.cloud.network.element;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-
 import org.apache.commons.lang3.StringUtils;
-import net.nuage.vsp.acs.client.api.model.VspAclRule;
-import net.nuage.vsp.acs.client.api.model.VspDhcpDomainOption;
-import net.nuage.vsp.acs.client.api.model.VspNetwork;
-import net.nuage.vsp.acs.client.api.model.VspStaticNat;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.log4j.Logger;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-
-import org.apache.cloudstack.api.InternalIdentity;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.cloudstack.network.ExternalNetworkDeviceManager;
-import org.apache.cloudstack.network.topology.NetworkTopologyContext;
-import org.apache.cloudstack.resourcedetail.VpcDetailVO;
-import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.StartupCommand;
@@ -65,7 +32,6 @@ import com.cloud.agent.api.element.ShutDownVpcVspCommand;
 import com.cloud.agent.api.element.ShutDownVspCommand;
 import com.cloud.dc.Vlan;
 import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.VlanDao;
 import com.cloud.dc.dao.VlanDetailsDao;
 import com.cloud.deploy.DeployDestination;
@@ -77,11 +43,11 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.exception.UnsupportedServiceException;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
-import com.cloud.host.dao.HostDao;
 import com.cloud.network.Network;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
+import com.cloud.network.NetworkMigrationManager;
 import com.cloud.network.NetworkModel;
 import com.cloud.network.Networks;
 import com.cloud.network.PhysicalNetworkServiceProvider;
@@ -90,14 +56,11 @@ import com.cloud.network.dao.FirewallRulesCidrsDao;
 import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
-import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkServiceMapDao;
-import com.cloud.network.dao.NuageVspDao;
 import com.cloud.network.dao.PhysicalNetworkDao;
 import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.network.manager.NuageVspManager;
 import com.cloud.network.manager.NuageVspManagerImpl;
-import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
 import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.FirewallRule.FirewallRuleType;
 import com.cloud.network.rules.FirewallRuleVO;
@@ -109,16 +72,16 @@ import com.cloud.network.vpc.PrivateGateway;
 import com.cloud.network.vpc.StaticRouteProfile;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.network.vpc.VpcOfferingServiceMapVO;
-import com.cloud.network.vpc.dao.VpcDao;
 import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.offerings.dao.NetworkOfferingDao;
-import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.resource.ResourceManager;
 import com.cloud.resource.ResourceStateAdapter;
 import com.cloud.resource.ServerResource;
 import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.server.ResourceTag;
+import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.util.NuageVspEntityBuilder;
 import com.cloud.util.NuageVspUtil;
 import com.cloud.utils.Pair;
@@ -132,6 +95,33 @@ import com.cloud.vm.ReservationContext;
 import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.NicDao;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import net.nuage.vsp.acs.client.api.model.VspAclRule;
+import net.nuage.vsp.acs.client.api.model.VspDhcpDomainOption;
+import net.nuage.vsp.acs.client.api.model.VspNetwork;
+import net.nuage.vsp.acs.client.api.model.VspStaticNat;
+import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.network.ExternalNetworkDeviceManager;
+import org.apache.cloudstack.resourcedetail.VpcDetailVO;
+import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.log4j.Logger;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 public class NuageVspElement extends AdapterBase implements ConnectivityProvider, IpDeployer, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider,
         DhcpServiceProvider, ResourceStateAdapter, VpcProvider, NetworkACLServiceProvider {
@@ -165,20 +155,12 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
     @Inject
     ResourceManager _resourceMgr;
     @Inject
-    HostDao _hostDao;
-    @Inject
     NetworkModel _networkModel;
     @Inject
     NetworkServiceMapDao _ntwkSrvcDao;
     @Inject
-    NuageVspDao _nuageVspDao;
-    @Inject
-    NetworkDao _networkDao;
-    @Inject
     DomainDao _domainDao;
     @Inject
-    DataCenterDao _dcDao;
-    @Inject
     IPAddressDao _ipAddressDao;
     @Inject
     VlanDao _vlanDao;
@@ -187,12 +169,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
     @Inject
     NicDao _nicDao;
     @Inject
-    VpcDao _vpcDao;
-    @Inject
     VpcOfferingServiceMapDao _vpcOfferingSrvcDao;
     @Inject
-    NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
-    @Inject
     AgentManager _agentMgr;
     @Inject
     NetworkOfferingDao _ntwkOfferingDao;
@@ -212,15 +190,10 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
     NuageVspEntityBuilder _nuageVspEntityBuilder;
     @Inject
     VpcDetailsDao _vpcDetailsDao;
-
-    @Inject
-    NetworkModel _networkMgr;
-    @Inject
-    NetworkTopologyContext networkTopologyContext;
     @Inject
     DomainRouterDao _routerDao;
     @Inject
-    VpcVirtualNetworkApplianceManager _routerMgr;
+    ResourceTagDao _resourceTagDao;
 
     @Override
     public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> service) throws ResourceUnavailableException {
@@ -714,6 +687,17 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
                 preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key());
             }
 
+            cleanUpVpcCaching(vpc.getId());
+            //related to migration caching
+            List<? extends ResourceTag> vpcResourceDetails = _resourceTagDao.listByResourceUuid(vpc.getUuid());
+            if (vpcResourceDetails != null) {
+                vpcResourceDetails.stream()
+                                  .filter(item -> item.getKey().equals(NetworkMigrationManager.MIGRATION))
+                                  .findFirst()
+                                  .map(ResourceTag::getResourceId)
+                                  .ifPresent(this::cleanUpVpcCaching);
+            }
+
             ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName, domainRouterUuids);
             Answer answer =  _agentMgr.easySend(nuageVspHost.getId(), cmd);
             if (answer == null || !answer.getResult()) {
@@ -721,11 +705,17 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
                 if ((null != answer) && (null != answer.getDetails())) {
                     throw new ResourceUnavailableException(answer.getDetails(), Vpc.class, vpc.getId());
                 }
+                return false;
             }
         }
         return true;
     }
 
+    private void cleanUpVpcCaching(long vpcId) {
+        _vpcDetailsDao.removeDetail(vpcId, NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID);
+        _vpcDetailsDao.removeDetail(vpcId, NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID);
+    }
+
     private Long getPhysicalNetworkId(Long zoneId) {
         Long guestPhysicalNetworkId = 0L;
         List<PhysicalNetworkVO> physicalNetworkList = _physicalNetworkDao.listByZone(zoneId);
diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java
index b1577de..f43e350 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java
+++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java
@@ -223,7 +223,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
                 implemented.setCidr(network.getCidr());
             }
 
-            VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented);
+            VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true);
             String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
             String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
             implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
@@ -268,22 +268,20 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
     }
 
     private void saveNetworkAndVpcDetails(VspNetwork vspNetwork, NetworkRelatedVsdIds networkRelatedVsdIds, Long vpcId) {
-
-
         if (!vspNetwork.isShared() && !vspNetwork.getNetworkRelatedVsdIds().equals(networkRelatedVsdIds)) {
             Map<String, String> networkDetails = constructNetworkDetails(networkRelatedVsdIds, vspNetwork.isVpc());
 
+            long networkId = vspNetwork.getId();
+
             for (Map.Entry<String, String> networkDetail : networkDetails.entrySet()) {
-                NetworkDetailVO networkDetailVO = new NetworkDetailVO(vspNetwork.getId(), networkDetail.getKey(), networkDetail.getValue(), false);
-                _networkDetailsDao.persist(networkDetailVO);
+                _networkDetailsDao.addDetail(networkId, networkDetail.getKey(), networkDetail.getValue(), false);
             }
 
             if(vspNetwork.isVpc()) {
                 Map<String, String> vpcDetails = constructVpcDetails(networkRelatedVsdIds);
 
                 for (Map.Entry<String, String> vpcDetail : vpcDetails.entrySet()) {
-                    VpcDetailVO vpcDetailVO = new VpcDetailVO(vpcId, vpcDetail.getKey(), vpcDetail.getValue(), false);
-                    _vpcDetailsDao.persist(vpcDetailVO);
+                    _vpcDetailsDao.addDetail(vpcId, vpcDetail.getKey(), vpcDetail.getValue(), false);
                 }
             }
         }
@@ -355,6 +353,16 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
             HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(network.getPhysicalNetworkId());
             VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network);
 
+            if (vm.getType() == VirtualMachine.Type.DomainRouter && vspNetwork.getVirtualRouterIp().equals("null")) {
+                //In case of upgrade network offering
+                vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network, true);
+                String broadcastUriStr = network.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
+                NetworkVO updatedNetwork = _networkDao.createForUpdate(network.getId());
+                updatedNetwork.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
+                _networkDao.update(updatedNetwork.getId(), updatedNetwork);
+                network = _networkDao.findById(network.getId());
+            }
+
             if (vspNetwork.isShared()) {
                 vspNetwork = _nuageVspEntityBuilder.updateVspNetworkByPublicIp(vspNetwork, network, nic.getIPv4Address());
 
@@ -623,6 +631,17 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Handling trash() call back to delete the network " + network.getName() + " with uuid " + network.getUuid() + " from VSP");
             }
+
+            boolean networkMigrationCopy = network.getRelated() != network.getId();
+
+            cleanUpNetworkCaching(network.getId());
+            if (networkMigrationCopy) {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Network " + network.getName() + " is a copy of a migrated network. Cleaning up network details of related network.");
+                }
+                cleanUpNetworkCaching(network.getRelated());
+            }
+
             VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
             HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(network.getPhysicalNetworkId());
             TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork);
@@ -640,6 +659,12 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
         return super.trash(network, offering);
     }
 
+    private void cleanUpNetworkCaching(long id) {
+        _networkDetailsDao.removeDetail(id, NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID);
+        _networkDetailsDao.removeDetail(id, NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID);
+        _networkDetailsDao.removeDetail(id, NuageVspManager.NETWORK_METADATA_VSD_SUBNET_ID);
+    }
+
     private boolean networkHasDns(Network network) {
 
         if (network != null) {
diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java
index 5a0a5d12..c024a7b 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java
+++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java
@@ -19,6 +19,7 @@
 
 package com.cloud.util;
 
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -159,11 +160,18 @@ public class NuageVspEntityBuilder {
     }
 
     public VspNetwork buildVspNetwork(Network network) {
-        return buildVspNetwork(network.getDomainId(), network);
+        return buildVspNetwork(network.getDomainId(), network, false);
     }
 
-    //TODO:Sigert implement caching in this function. retrieve data
     public VspNetwork buildVspNetwork(long domainId, Network network) {
+        return buildVspNetwork(domainId, network, false);
+    }
+
+    public VspNetwork buildVspNetwork(Network network, boolean recalculateBroadcastUri) {
+        return buildVspNetwork(network.getDomainId(), network, recalculateBroadcastUri);
+    }
+
+    public VspNetwork buildVspNetwork(long domainId, Network network, boolean recalculateBroadcastUri) {
         VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder()
                 .id(network.getId())
                 .uuid(network.getUuid())
@@ -247,7 +255,7 @@ public class NuageVspEntityBuilder {
             try {
                 List<Pair<String, String>> ipAddressRanges =
                         networkOffering.getGuestType() == Network.GuestType.Shared ? getSharedIpAddressRanges(network.getId()) : getIpAddressRanges(network);
-                String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges);
+                String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges, recalculateBroadcastUri);
                 vspNetworkBuilder.virtualRouterIp(virtualRouterIp);
             } catch (InsufficientVirtualNetworkCapacityException ex) {
                 s_logger.error("There is an insufficient network capacity in network " + network.getId(), ex);
@@ -332,10 +340,20 @@ public class NuageVspEntityBuilder {
         return null;
     }
 
-    private String getVirtualRouterIP(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
-        if (network.getBroadcastUri() != null) {
+    private String getVirtualRouterIP(Network network, List<Pair<String, String>> ipAddressRanges, boolean recalculateBroadcastUri) throws InsufficientVirtualNetworkCapacityException {
+        //Add a check to see if a VR should be present in the offering or not?
+        if (!recalculateBroadcastUri && network.getBroadcastUri() != null) {
             return network.getBroadcastUri().getPath().substring(1);
         }
+        ensureIpCapacity(network, ipAddressRanges);
+
+        if(network.getGuestType() == Network.GuestType.Shared) {
+            return ipAddressRanges.stream()
+                                  .sorted(Comparator.comparingLong(p -> NetUtils.ip2Long(p.getLeft())))
+                                  .findFirst()
+                                  .map(Pair::getLeft)
+                                  .orElseThrow(() -> new IllegalArgumentException("Shared network without ip ranges? How can this happen?"));
+        }
 
         Pair<String, String> lowestIpAddressRange = null;
         long ipCount = 0;
@@ -351,6 +369,33 @@ public class NuageVspEntityBuilder {
             }
         }
 
+
+        Network networkToCheck;
+        if (isMigratingNetwork(network)) {
+            networkToCheck = _networkDao.findById(network.getRelated());
+        } else {
+            networkToCheck = network;
+        }
+
+        Long freeIp = _networkModel.getAvailableIps(networkToCheck, null)
+                                   .stream()
+                                   .findFirst()
+                                   .orElseThrow(() -> new InsufficientVirtualNetworkCapacityException("There is no free ip available for the VirtualRouter.",
+                                                                                                      Network.class,
+                                                                                                      network.getId()));
+
+        return NetUtils.long2Ip(freeIp);
+    }
+
+    private boolean isMigratingNetwork(Network network) {
+        return network.getRelated() != network.getId();
+    }
+
+    private void ensureIpCapacity(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
+        long ipCount = ipAddressRanges.stream()
+                                      .mapToLong(this::getIpCount)
+                                      .sum();
+
         if (ipCount == 0) {
             throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class,
                     network.getId());
@@ -358,12 +403,10 @@ public class NuageVspEntityBuilder {
             throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class,
                     network.getId());
         }
+    }
 
-        String virtualRouterIp = lowestIpAddressRange.getLeft();
-        long lowestIp = NetUtils.ip2Long(lowestIpAddressRange.getLeft());
-        lowestIp = lowestIp + 1;
-        lowestIpAddressRange.setLeft(NetUtils.long2Ip(lowestIp));
-        return virtualRouterIp;
+    private long getIpCount(Pair<String, String> ipAddressRange) {
+        return NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1;
     }
 
     public VspVm buildVspVm(VirtualMachine vm, Network network) {
diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java
index f5a0f40..fea759d 100644
--- a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java
+++ b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java
@@ -89,11 +89,18 @@ public class NuageTest {
         ConfigKey.init(configDepot);
 
         when(_nuageVspEntityBuilder.buildVspDomain(any(Domain.class))).thenReturn(buildVspDomain());
-        when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class))).thenReturn(buildVspNetwork());
-        when(_nuageVspEntityBuilder.buildVspNetwork(anyLong(), any(Network.class))).thenReturn(buildVspNetwork());
+
+        VspNetwork vspNetwork = buildVspNetwork();
+        when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class))).thenReturn(vspNetwork);
+        when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class), anyBoolean())).thenReturn(vspNetwork);
+        when(_nuageVspEntityBuilder.buildVspNetwork(anyLong(), any(Network.class))).thenReturn(vspNetwork);
+        when(_nuageVspEntityBuilder.buildVspNetwork(anyLong(), any(Network.class), anyBoolean())).thenReturn(vspNetwork);
+
         when(_nuageVspEntityBuilder.buildVspVm(any(VirtualMachine.class), any(Network.class))).thenReturn(buildVspVm());
+
         when(_nuageVspEntityBuilder.buildVspNic(anyString(), any(NicProfile.class))).thenReturn(buildVspNic());
         when(_nuageVspEntityBuilder.buildVspNic(any(NicVO.class))).thenReturn(buildVspNic());
+
         when(_nuageVspEntityBuilder.buildVspStaticNat(anyBoolean(), any(IPAddressVO.class), any(VlanVO.class), any(NicVO.class))).thenReturn(buildVspStaticNat());
         when(_nuageVspEntityBuilder.buildVspAclRule(any(FirewallRule.class), any(Network.class))).thenReturn(buildVspAclRule());
         when(_nuageVspEntityBuilder.buildVspAclRule(any(NetworkACLItem.class))).thenReturn(buildVspAclRule());
diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java
index 3805b13..43d465f 100644
--- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java
+++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Set;
 
+import com.cloud.tags.dao.ResourceTagDao;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InjectMocks;
@@ -107,6 +108,7 @@ public class NuageVspElementTest extends NuageTest {
     @Mock private VpcDetailsDao _vpcDetailsDao;
     @Mock private DomainRouterDao _domainRouterDao;
     @Mock private ResourceManager _resourceManager;
+    @Mock private ResourceTagDao _resourceTagDao;
 
     @Before
     public void setUp() throws Exception {
diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
index 94e8559..aacae26 100644
--- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
+++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
@@ -107,6 +107,8 @@
 
     <bean id="ipv6AddressManagerImpl" class="com.cloud.network.Ipv6AddressManagerImpl" />
 
+    <bean id="NetworkMigrationManagerImpl" class="com.cloud.network.NetworkMigrationManagerImpl" />
+
 
     <bean id="alertManagerImpl" class="com.cloud.alert.AlertManagerImpl" />
 
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 034111e..dfc7c37 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -5071,6 +5071,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         final Integer maxconn = cmd.getMaxconnections();
         Availability availability = null;
         final String state = cmd.getState();
+        final String tags = cmd.getTags();
         CallContext.current().setEventDetails(" Id: " + id);
 
         // Verify input parameters
@@ -5111,6 +5112,25 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             }
         }
 
+        if (tags != null) {
+            List<DataCenterVO> dataCenters = _zoneDao.listAll();
+            TrafficType trafficType = offeringToUpdate.getTrafficType();
+            String oldTags = offeringToUpdate.getTags();
+
+            for (DataCenterVO dataCenter : dataCenters) {
+                long zoneId = dataCenter.getId();
+                long newPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, tags, trafficType);
+                if (oldTags != null) {
+                    long oldPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, oldTags, trafficType);
+                    if (newPhysicalNetworkId != oldPhysicalNetworkId) {
+                        throw new InvalidParameterValueException("New tags: selects different physical network for zone " + zoneId);
+                    }
+                }
+            }
+
+            offering.setTags(tags);
+        }
+
         // Verify availability
         if (availabilityStr != null) {
             for (final Availability avlb : Availability.values()) {
diff --git a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java
index f3aedef..c5006b4 100644
--- a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java
+++ b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
 import org.apache.cloudstack.api.ResourceDetail;
 import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
 import org.apache.cloudstack.resourcedetail.dao.AutoScaleVmGroupDetailsDao;
@@ -124,6 +125,8 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource
     SnapshotPolicyDetailsDao _snapshotPolicyDetailsDao;
     @Inject
     GuestOsDetailsDao _guestOsDetailsDao;
+    @Inject
+    NetworkOfferingDetailsDao _networkOfferingDetailsDao;
 
     private static Map<ResourceObjectType, ResourceDetailsDao<? extends ResourceDetail>> s_daoMap = new HashMap<ResourceObjectType, ResourceDetailsDao<? extends ResourceDetail>>();
 
@@ -157,6 +160,7 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource
         s_daoMap.put(ResourceObjectType.LBHealthCheckPolicy, _healthcheckPolicyDetailsDao);
         s_daoMap.put(ResourceObjectType.SnapshotPolicy, _snapshotPolicyDetailsDao);
         s_daoMap.put(ResourceObjectType.GuestOs, _guestOsDetailsDao);
+        s_daoMap.put(ResourceObjectType.NetworkOffering, _networkOfferingDetailsDao);
         return true;
     }
 
@@ -200,7 +204,11 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource
         long id = _taggedResourceMgr.getResourceId(resourceId, resourceType);
 
         DetailDaoHelper newDetailDaoHelper = new DetailDaoHelper(resourceType);
-        newDetailDaoHelper.removeDetail(id, key);
+        if (key != null) {
+            newDetailDaoHelper.removeDetail(id, key);
+        } else {
+            newDetailDaoHelper.removeDetails(id);
+        }
 
         return true;
     }
@@ -225,6 +233,10 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource
             dao.removeDetail(resourceId, key);
         }
 
+        private void removeDetails(long resourceId) {
+            dao.removeDetails(resourceId);
+        }
+
         private ResourceDetail getDetail(long resourceId, String key) {
             return dao.findDetail(resourceId, key);
         }
diff --git a/server/src/com/cloud/network/NetworkMigrationManager.java b/server/src/com/cloud/network/NetworkMigrationManager.java
new file mode 100644
index 0000000..98bf849
--- /dev/null
+++ b/server/src/com/cloud/network/NetworkMigrationManager.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.network;
+
+import com.cloud.network.vpc.Vpc;
+import com.cloud.offering.NetworkOffering;
+
+/**
+ * The NetworkMigrationManager should be used for migration purpose ONLY.
+ */
+public interface NetworkMigrationManager {
+
+    String MIGRATION = "migration";
+    /**
+     * Returns a copy of the provided network.
+     * All nics in the orginal network will be re-assigned to the newly created network.
+     * All network details will be copied to the newly created network.
+     * @param network the network to be copied
+     * @param networkOffering the network offering of the network that is copied
+     * @return the networkid of the copy
+     */
+    long makeCopyOfNetwork(Network network, NetworkOffering networkOffering, Long vpcId);
+
+    /**
+     * Returns a copy of the provided vpc
+     * All acls rules and public ips will be re-assigned to the newly created vpc.
+     * @param vpcId the vpc id of the vpc that needs to be copied
+     * @param vpcOfferingId the new vpc offering id
+     * @return the vpc id of the copy
+     */
+    Long makeCopyOfVpc(long vpcId, long vpcOfferingId);
+
+    /**
+     * Starts the vpc if, the vpc is not already started
+     */
+    void startVpc(Vpc vpc);
+
+    /**
+     * Upgrade the physical network and the offering of a network.
+     * @param networkId the networkid of the network that needs to be upgraded.
+     * @param newPhysicalNetworkId the id of the new physical network where the network should be moved to.
+     * @param networkOfferingId the new network offering.
+     * @return the networkid of the upgraded network
+     */
+    Network upgradeNetworkToNewNetworkOffering (long networkId, long newPhysicalNetworkId, long networkOfferingId, Long vpcId);
+
+    /**
+     * Deletes the copy of a network which was previously created by the networkMigrationManager
+     * For deletion of the copy the old UUID of the original network is used to assure that plugins, using the UUID, clean up the network correctly.
+     * @param networkCopyId the networkId of the copied network
+     * @param originalNetworkId the networkId of the original network
+     */
+    void deleteCopyOfNetwork(long networkCopyId, long originalNetworkId);
+
+    /**
+     * Deletes the copy of a vpc which was previously created by the networkMigrationManager
+     * For deletion the copy of the old UUID of the original vpc is used to assure that plugins, using the UUID, clean up the vpc correctly.
+     * @param vpcCopyId the vpc id of the copied vpc
+     * @param originalVpcId the vpc id of the original vpc
+     */
+    void deleteCopyOfVpc(long vpcCopyId, long originalVpcId);
+
+    /**
+     * Moves all the nics from the srcNetwork to the network in the new physical network.
+     * The nics in the source network will be marked as removed afterwards.
+     * @param srcNetwork the source network containing the nics to be moved
+     * @param networkInNewPhysicalNet the destination network where the nics need to be recreated.
+     */
+    void assignNicsToNewPhysicalNetwork(Network srcNetwork, Network networkInNewPhysicalNet);
+}
diff --git a/server/src/com/cloud/network/NetworkMigrationManagerImpl.java b/server/src/com/cloud/network/NetworkMigrationManagerImpl.java
new file mode 100644
index 0000000..956f1fb
--- /dev/null
+++ b/server/src/com/cloud/network/NetworkMigrationManagerImpl.java
@@ -0,0 +1,693 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.network;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
+import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO;
+import org.apache.cloudstack.resourcedetail.VpcDetailVO;
+import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao;
+import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
+
+import com.cloud.configuration.Resource;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.dao.HostDao;
+import com.cloud.network.dao.FirewallRulesCidrsDao;
+import com.cloud.network.dao.FirewallRulesCidrsVO;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDetailVO;
+import com.cloud.network.dao.NetworkDetailsDao;
+import com.cloud.network.dao.NetworkDomainDao;
+import com.cloud.network.dao.NetworkDomainVO;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.RouterNetworkDao;
+import com.cloud.network.dao.RouterNetworkVO;
+import com.cloud.network.guru.NetworkGuru;
+import com.cloud.network.router.VirtualRouter;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.rules.RulesManager;
+import com.cloud.network.vpc.NetworkACLVO;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.network.vpc.VpcGatewayVO;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpc.VpcService;
+import com.cloud.network.vpc.VpcVO;
+import com.cloud.network.vpc.dao.NetworkACLDao;
+import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.network.vpc.dao.VpcGatewayDao;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.server.ResourceTag;
+import com.cloud.tags.ResourceTagVO;
+import com.cloud.tags.dao.ResourceTagDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.DomainRouterVO;
+import com.cloud.vm.Nic;
+import com.cloud.vm.NicDetailVO;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.ReservationContextImpl;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfileImpl;
+import com.cloud.vm.dao.DomainRouterDao;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.NicDetailsDao;
+import com.cloud.vm.dao.NicIpAliasDao;
+import com.cloud.vm.dao.NicSecondaryIpDao;
+import com.cloud.vm.dao.UserVmDao;
+
+public class NetworkMigrationManagerImpl implements NetworkMigrationManager {
+    public static final Logger s_logger = Logger.getLogger(NetworkMigrationManagerImpl.class.getName());
+
+    @Inject
+    private DataCenterDao _dcDao = null;
+    @Inject
+    private NetworkDetailsDao _networkDetailsDao = null;
+    @Inject
+    private AccountDao _accountDao = null;
+    @Inject
+    private NetworkDomainDao _networkDomainDao = null;
+    @Inject
+    private NetworkOrchestrationService _networkMgr = null;
+    @Inject
+    private ResourceLimitService _resourceLimitMgr = null;
+    @Inject
+    private NetworkDao _networksDao = null;
+    @Inject
+    private NetworkOfferingDao _networkOfferingDao = null;
+    @Inject
+    private NetworkOfferingServiceMapDao _networkOfferingServiceDao = null;
+    @Inject
+    private NicDao _nicDao = null;
+    @Inject
+    private NicSecondaryIpDao _nicSecondaryIpDao = null;
+    @Inject
+    private NicIpAliasDao _nicIpAliasDao = null;
+    @Inject
+    private NicDetailsDao _nicDetailsDao = null;
+    @Inject
+    private FirewallRulesDao _firewallDao = null;
+    @Inject
+    private FirewallRulesCidrsDao _firewallRulesCidrDao = null;
+    @Inject
+    private FirewallRuleDetailsDao _firewallRuleDetailsDao = null;
+    @Inject
+    private EntityManager _entityMgr = null;
+    @Inject
+    private RouterNetworkDao _routerNetworkDao = null;
+    @Inject
+    private DomainRouterDao _routerDao = null;
+    @Inject
+    private NetworkService _networkService = null;
+    @Inject
+    private UserVmDao _vmDao = null;
+    @Inject
+    private NetworkModel _networkModel= null;
+    @Inject
+    private VMNetworkMapDao _vmNetworkMapDao = null;
+    @Inject
+    private HostDao _hostDao = null;
+    @Inject
+    private VirtualMachineManager _itMgr = null;
+    @Inject
+    private IPAddressDao _ipAddressDao = null;
+    @Inject
+    private RulesManager _rulesMgr = null;
+    @Inject
+    private VpcDao _vpcDao = null;
+    @Inject
+    private VpcDetailsDao _vpcDetailsDao = null;
+    @Inject
+    private IpAddressManager _ipAddressManager = null;
+    @Inject
+    private VpcService _vpcService = null;
+    @Inject
+    private NetworkACLDao _networkACLDao = null;
+    @Inject
+    private VpcManager _vpcManager = null;
+    @Inject
+    private VpcGatewayDao _vpcGatewayDao = null;
+    @Inject
+    private ResourceTagDao _resourceTagDao = null;
+
+    @Override public long makeCopyOfNetwork(Network network, NetworkOffering networkOffering, Long vpcId) {
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Making a copy of network with uuid " + network.getUuid() + " and id " + network.getId() + " for migration.");
+        }
+        long originalNetworkId = network.getId();
+        NetworkDomainVO domainNetworkMapByNetworkId = _networkDomainDao.getDomainNetworkMapByNetworkId(originalNetworkId);
+        AccountVO networkAccount = _accountDao.findById(network.getAccountId());
+
+        boolean subdomainAccess = true;
+        if (domainNetworkMapByNetworkId != null) {
+            subdomainAccess = domainNetworkMapByNetworkId.isSubdomainAccess();
+        }
+        DataCenterDeployment plan = new DataCenterDeployment(network.getDataCenterId(), null, null, null, null, network.getPhysicalNetworkId());
+
+        List<? extends Network> networks = _networkMgr.setupNetwork(networkAccount, networkOffering, network, plan, network.getName(), network.getDisplayText(), true,
+                                                                    network.getDomainId(), network.getAclType(), subdomainAccess,
+                                                                    vpcId, true);
+        _resourceLimitMgr.incrementResourceCount(network.getAccountId(), Resource.ResourceType.network, network.isDisplay());
+
+        long networkCopyId;
+        if (networks == null || networks.isEmpty()) {
+            throw new CloudRuntimeException("Fail to create a network");
+        } else {
+            DataCenter zone = _dcDao.findById(network.getDataCenterId());
+            String guestNetworkCidr = zone.getGuestNetworkCidr();
+
+            if (networks.get(0).getGuestType() == Network.GuestType.Isolated
+                    && networks.get(0).getTrafficType() == Networks.TrafficType.Guest) {
+                Network networkCopy = networks.get(0);
+                for (final Network nw : networks) {
+                    if (nw.getCidr() != null && nw.getCidr().equals(guestNetworkCidr)) {
+                        networkCopy = nw;
+                    }
+                }
+                networkCopyId = networkCopy.getId();
+            } else {
+                // For shared network
+                networkCopyId = networks.get(0).getId();
+            }
+        }
+
+        //Update the related network
+        NetworkVO originalNetwork = _networksDao.findById(originalNetworkId);
+        originalNetwork.setRelated(networkCopyId);
+        _networksDao.update(originalNetworkId, originalNetwork);
+
+        NetworkVO copiedNetwork = _networksDao.findById(networkCopyId);
+        copiedNetwork.setRelated(originalNetworkId);
+        copiedNetwork.setDisplayNetwork(false);
+        copiedNetwork.setBroadcastUri(network.getBroadcastUri());
+        copiedNetwork.setState(network.getState());
+        _networksDao.update(networkCopyId, copiedNetwork);
+
+        copyNetworkDetails(originalNetworkId, networkCopyId);
+        copyFirewallRulesToNewNetwork(network, networkCopyId);
+        assignUserNicsToNewNetwork(originalNetworkId, networkCopyId);
+        assignRouterNicsToNewNetwork(network.getId(), networkCopyId);
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Succesfully created a copy of network  " + originalNetwork.getName() + "(" + originalNetwork.getUuid() + ") id is " + originalNetwork.getId() + " for migration. The network copy has uuid " + network.getUuid() + " and id " + network.getId());
+        }
+        return networkCopyId;
+    }
+
+    @DB
+    private void copyNetworkDetails(long srcNetworkId, long dstNetworkId) {
+        List<NetworkDetailVO> networkDetails = _networkDetailsDao.listDetails(srcNetworkId);
+
+        for (NetworkDetailVO networkDetail : networkDetails) {
+            _networkDetailsDao.persist(new NetworkDetailVO(dstNetworkId, networkDetail.getName(), networkDetail.getValue(), networkDetail.isDisplay()));
+        }
+    }
+
+    /**
+     * reassigns the nics to the new network from the src network.
+     * @param srcNetworkId
+     * @param dstNetworkId
+     */
+    private void assignUserNicsToNewNetwork(long srcNetworkId, long dstNetworkId) {
+        List<NicVO> nics = _nicDao.listByNetworkId(srcNetworkId);
+
+        for (NicVO nic : nics) {
+            if (nic.getVmType() == VirtualMachine.Type.User) {
+                nic.setNetworkId(dstNetworkId);
+                _nicDao.persist(nic);
+
+                //update the number of active nics in both networks after migration.
+                if (nic.getState() == Nic.State.Reserved) {
+                    _networksDao.changeActiveNicsBy(srcNetworkId, -1);
+                    _networksDao.changeActiveNicsBy(dstNetworkId, 1);
+                }
+            }
+        }
+
+        List<? extends IPAddressVO> publicIps = _ipAddressDao.listByAssociatedNetwork(srcNetworkId, null);
+
+        for (IPAddressVO ipAddress : publicIps) {
+                ipAddress.setAssociatedWithNetworkId(dstNetworkId);
+                _ipAddressDao.persist(ipAddress);
+        }
+    }
+
+    @Override
+    public Long makeCopyOfVpc(long vpcId, long vpcOfferingId) {
+        VpcVO vpc = _vpcDao.findById(vpcId);
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Making a copy of vpc with uuid " + vpc.getUuid() + " and id " + vpc.getId() + " for migration.");
+        }
+        if (vpc == null) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Specified vpc id doesn't exist in the system");
+            ex.addProxyObject(String.valueOf(vpcId), "vpcId");
+            throw ex;
+        }
+
+        Vpc copyOfVpc;
+        long copyOfVpcId;
+        try {
+            copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(), vpc.getDisplayText(), vpc.getCidr(),
+                                              vpc.getNetworkDomain(), vpc.isDisplay());
+            copyOfVpcId = copyOfVpc.getId();
+            //on resume of migration the uuid will be swapped already. So the copy will have the value of the original vpcid.
+            _resourceTagDao.persist(new ResourceTagVO(MIGRATION, Long.toString(vpcId), vpc.getAccountId(), vpc.getDomainId(), copyOfVpcId, ResourceTag.ResourceObjectType.Vpc, null, vpc.getUuid()));
+            VpcVO copyVpcVO = _vpcDao.findById(copyOfVpcId);
+            vpc.setDisplay(false);
+            swapUuids(vpc, copyVpcVO);
+            reassignACLRulesToNewVpc(vpcId, copyOfVpcId);
+            reassignPublicIpsToNewVpc(vpcId, copyOfVpc);
+            copyVpcDetails(vpcId, copyOfVpcId);
+            reassignGatewayToNewVpc(vpcId, copyOfVpcId);
+            copyVpcResourceTagsToNewVpc(vpcId, copyOfVpcId);
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Succesfully created a copy of network  " + vpc.getName() + "(" + vpc.getUuid() + ") id is " + vpc.getId() + " for migration. The network copy has uuid " + copyVpcVO.getUuid() + " and id " + copyOfVpc.getId());
+            }
+        } catch (ResourceAllocationException e) {
+            throw new CloudRuntimeException(e.getMessage());
+        }
+
+        return copyOfVpcId;
+    }
+
+    @Override
+    public void startVpc(Vpc vpc) {
+        if (vpc.getState() != Vpc.State.Enabled) {
+            try {
+                _vpcService.startVpc(vpc.getId(), true);
+            } catch (ResourceUnavailableException | InsufficientCapacityException e) {
+                s_logger.error("Vpc can not be started. Aborting migration process");
+                throw new CloudRuntimeException("Vpc can not be started.", e);
+            }
+        }
+    }
+
+
+    private void copyVpcDetails(long srcVpcId, long dstVpcId) {
+        List<VpcDetailVO> vpcDetails = _vpcDetailsDao.listDetails(srcVpcId);
+
+        for (VpcDetailVO vpcDetail : vpcDetails) {
+            _vpcDetailsDao.persist(new VpcDetailVO(dstVpcId, vpcDetail.getName(), vpcDetail.getValue(), vpcDetail.isDisplay()));
+        }
+    }
+
+    /**
+     * Reassign the ACL rules from the original vpc to the new VPC
+     * @param srcVpcId
+     * @param dstVpcId
+     */
+    private void reassignACLRulesToNewVpc(long srcVpcId, long dstVpcId){
+        List<NetworkACLVO> networkACL = _networkACLDao.listByVpcId(srcVpcId);
+
+        for (NetworkACLVO aclList : networkACL) {
+            aclList.setVpcId(dstVpcId);
+            _networkACLDao.persist(aclList);
+        }
+    }
+
+    private void reassignPublicIpsToNewVpc(long srcVpcId, Vpc dstVpc) {
+        List<? extends IPAddressVO> publicIps = _ipAddressDao.listByAssociatedVpc(srcVpcId, _vpcManager.isSrcNatIpRequired(dstVpc.getVpcOfferingId()) ? null : false);
+
+        for(IPAddressVO publicIp : publicIps) {
+            publicIp.setVpcId(dstVpc.getId());
+            _ipAddressDao.persist(publicIp);
+        }
+    }
+
+    private void reassignGatewayToNewVpc(long srcVpcId, long dstVpcId){
+        List<VpcGatewayVO> vpcGateways = _vpcGatewayDao.listByVpcId(srcVpcId);
+        for (VpcGatewayVO vpcGateway : vpcGateways) {
+            vpcGateway.setVpcId(dstVpcId);
+            _vpcGatewayDao.persist(vpcGateway);
+        }
+    }
+
+    private void copyVpcResourceTagsToNewVpc(long srcVpcId, long dstVpcId){
+        List<? extends ResourceTag> resourceTags = _resourceTagDao.listBy(srcVpcId, ResourceTag.ResourceObjectType.Vpc);
+        for (ResourceTag resourceTag : resourceTags) {
+            resourceTag.setResourceId(dstVpcId);
+            _resourceTagDao.persist(
+                    new ResourceTagVO(
+                            resourceTag.getKey(),
+                            resourceTag.getValue(),
+                            resourceTag.getAccountId(),
+                            resourceTag.getDomainId(),
+                            dstVpcId,
+                            resourceTag.getResourceType(),
+                            resourceTag.getCustomer(),
+                            resourceTag.getResourceUuid()));
+        }
+    }
+
+    private void copyFirewallRulesToNewNetwork(Network srcNetwork, long dstNetworkId) {
+        List<FirewallRuleVO> firewallRules = _firewallDao.listByNetworkPurposeTrafficType(srcNetwork.getId(), FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress);
+        firewallRules.addAll(_firewallDao.listByNetworkPurposeTrafficType(srcNetwork.getId(), FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress));
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Copying firewall rules from network with id " + srcNetwork.getId() + " to network with id " + dstNetworkId);
+        }
+
+        //Loop over all the firewall rules in the original network and copy all values to a new firewall rule
+        //Copy all objects that are dependant on the firewall rules
+        for (FirewallRuleVO originalFirewallRule : firewallRules) {
+            FirewallRuleVO ruleVO = new FirewallRuleVO(originalFirewallRule.getXid(),
+                                                       originalFirewallRule.getSourceIpAddressId(),
+                                                       originalFirewallRule.getSourcePortStart(),
+                                                       originalFirewallRule.getSourcePortEnd(),
+                                                       originalFirewallRule.getProtocol(),
+                                                       dstNetworkId,
+                                                       srcNetwork.getAccountId(),
+                                                       srcNetwork.getDomainId(),
+                                                       originalFirewallRule.getPurpose(),
+                                                       originalFirewallRule.getSourceCidrList(),
+                                                       originalFirewallRule.getDestinationCidrList(),
+                                                       originalFirewallRule.getIcmpCode(),
+                                                       originalFirewallRule.getIcmpType(),
+                                                       originalFirewallRule.getRelated(),
+                                                       originalFirewallRule.getTrafficType(),
+                                                       originalFirewallRule.getType());
+
+            ruleVO = _firewallDao.persist(ruleVO);
+
+            //Firewall rule cidrs
+            List<FirewallRulesCidrsVO> firewallRulesCidrsVOS = _firewallRulesCidrDao.listByFirewallRuleId(originalFirewallRule.getId());
+            for (FirewallRulesCidrsVO firewallRulesCidrVO: firewallRulesCidrsVOS) {
+                _firewallRulesCidrDao.persist(new FirewallRulesCidrsVO(ruleVO.getId(), firewallRulesCidrVO.getSourceCidrList()));
+            }
+
+            //Firewall rules details
+            List<FirewallRuleDetailVO> originalFirewallRuleDetails = _firewallRuleDetailsDao.listDetails(originalFirewallRule.getId());
+            for (FirewallRuleDetailVO originalFirewallRuleDetail : originalFirewallRuleDetails) {
+                _firewallRuleDetailsDao.persist(new FirewallRuleDetailVO(ruleVO.getId(), originalFirewallRuleDetail.getName(), originalFirewallRuleDetail.getValue(), originalFirewallRuleDetail.isDisplay()));
+            }
+        }
+    }
+
+    private void assignRouterNicsToNewNetwork(long srcNetworkId, long dstNetworkId) {
+        final List<DomainRouterVO> routers = _routerDao.listByNetworkAndRole(srcNetworkId, VirtualRouter.Role.VIRTUAL_ROUTER);
+        for (DomainRouterVO domainRouter : routers) {
+            NicVO vrNic = _nicDao.findByNetworkIdAndType(srcNetworkId, VirtualMachine.Type.DomainRouter);
+            vrNic.setNetworkId(dstNetworkId);
+            _nicDao.update(vrNic.getId(), vrNic);
+
+            RouterNetworkVO routerNetwork = _routerNetworkDao.findByRouterAndNetwork(domainRouter.getId(), srcNetworkId);
+            routerNetwork.setNetworkId(dstNetworkId);
+            _routerNetworkDao.persist(routerNetwork);
+        }
+    }
+
+    @Override
+    public Network upgradeNetworkToNewNetworkOffering(long networkId, long newPhysicalNetworkId, long networkOfferingId, Long vpcId) {
+        s_logger.debug("upgrading network to network with new offering.");
+        NetworkVO network = _networksDao.findById(networkId);
+        NetworkOffering newOffering = _networkOfferingDao.findByIdIncludingRemoved(networkOfferingId);
+        long gurusImplementing = 0;
+        network.setBroadcastUri(null);
+        AccountVO networkAccount = _accountDao.findById(network.getAccountId());
+        DataCenterDeployment plan = new DataCenterDeployment(network.getDataCenterId(), null, null, null, null, newPhysicalNetworkId);
+        for (final NetworkGuru guru : _networkMgr.getNetworkGurus()) {
+
+            final Network designedNetwork = guru.design(newOffering, plan, network, networkAccount);
+            if (designedNetwork == null) {
+                continue;
+            }
+
+            gurusImplementing++;
+            if (gurusImplementing > 1) {
+                throw new CloudRuntimeException("Failed to migrate network to new physical network. Multiple network guru's for the same network are currently not supported.");
+            }
+
+            network.setTrafficType(designedNetwork.getTrafficType());
+            network.setMode(designedNetwork.getMode());
+            network.setBroadcastDomainType(designedNetwork.getBroadcastDomainType());
+            network.setBroadcastUri(designedNetwork.getBroadcastUri());
+            network.setNetworkOfferingId(designedNetwork.getNetworkOfferingId());
+            network.setState(designedNetwork.getState());
+            network.setPhysicalNetworkId(designedNetwork.getPhysicalNetworkId());
+            network.setRedundant(designedNetwork.isRedundant());
+            network.setGateway(designedNetwork.getGateway());
+            network.setCidr(designedNetwork.getCidr());
+            network.setGuruName(guru.getName());
+            network.setVpcId(vpcId);
+        }
+        _networksDao.update(network.getId(), network, _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), newPhysicalNetworkId));
+        return network;
+    }
+
+    @Override
+    public void deleteCopyOfNetwork(long networkCopyId, long originalNetworkId) {
+        NetworkVO networkCopy = _networksDao.findById(networkCopyId);
+
+        NicVO userNic = _nicDao.findByNetworkIdAndType(networkCopyId, VirtualMachine.Type.User);
+        if (userNic != null) {
+            s_logger.error("Something went wrong while migrating nics from the old network to the new network. Failed to delete copy of network. There are still user nics present in the network.");
+            throw new CloudRuntimeException("Failed to delete copy of network. There are still user nics present in the network.");
+        }
+
+        NetworkVO originalNetwork = _networksDao.findById(originalNetworkId);
+
+        swapUuids(originalNetwork, networkCopy);
+        try {
+            if (!_networkService.deleteNetwork(networkCopy.getId(), true)) {
+                throw new CloudRuntimeException("Failed to delete network. Clean up not successful.");
+            }
+        } finally {
+            swapUuids(networkCopy, originalNetwork);
+        }
+        originalNetwork.setRelated(originalNetworkId);
+        _networksDao.persist(originalNetwork);
+    }
+
+    @Override
+    public void deleteCopyOfVpc(long vpcCopyId, long originalVpcId) {
+        VpcVO copyOfvpc = _vpcDao.findById(vpcCopyId);
+        VpcVO originalVpc = _vpcDao.findById(originalVpcId);
+
+        //Be sure that when we delete the vpc, it has the uuid with what it was created.
+        swapUuids(copyOfvpc, originalVpc);
+        try {
+            if(!_vpcService.deleteVpc(vpcCopyId)) {
+                throw new CloudRuntimeException("Deletion of VPC failed. Clean up was not successful.");
+            }
+        } catch (ResourceUnavailableException e) {
+            throw new CloudRuntimeException(e.getMessage());
+        } finally {
+            swapUuids(originalVpc, copyOfvpc);
+        }
+        _resourceTagDao.removeByResourceIdAndKey(originalVpcId, ResourceTag.ResourceObjectType.Vpc, MIGRATION);
+    }
+
+    private Boolean migrateNicsInDB(NicVO originalNic, Network networkInNewPhysicalNet, DataCenter dc, ReservationContext context) {
+        s_logger.debug("migrating nics in database.");
+        UserVmVO vmVO = _vmDao.findById(originalNic.getInstanceId());
+        VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vmVO, null, null, null, null);
+        NicProfile nicProfile = new NicProfile(originalNic, networkInNewPhysicalNet, null, null, null, _networkModel.isSecurityGroupSupportedInNetwork(networkInNewPhysicalNet), null);
+        try {
+            nicProfile = _networkMgr.allocateNic(nicProfile, networkInNewPhysicalNet, originalNic.isDefaultNic(), nicProfile.getDeviceId(), vmProfile).first();
+        } catch (InsufficientVirtualNetworkCapacityException | InsufficientAddressCapacityException e) {
+            throw new CloudRuntimeException("Allocation of new nicProfile failed during migration", e);
+        }
+
+        //Update vm_network_map table
+        if (vmProfile.getType() == VirtualMachine.Type.User) {
+            final VMNetworkMapVO vno = new VMNetworkMapVO(vmVO.getId(), networkInNewPhysicalNet.getId());
+            _vmNetworkMapDao.persist(vno);
+        }
+
+        NicVO newNic = _nicDao.findById(nicProfile.getId());
+
+        copyNicDetails(originalNic.getId(), newNic.getId());
+        //Update nic uuid here
+        moveServices(originalNic, newNic);
+
+        if (originalNic.getState() == Nic.State.Reserved) {
+            final VirtualMachine vm = vmProfile.getVirtualMachine();
+            final Host host = _hostDao.findById(vm.getHostId());
+            final DeployDestination dest = new DeployDestination(dc, null, null, host);
+
+            try {
+                nicProfile = _networkMgr.prepareNic(vmProfile, dest, context, nicProfile.getId(), networkInNewPhysicalNet);
+                 _itMgr.replugNic(networkInNewPhysicalNet, _itMgr.toNicTO(nicProfile, host.getHypervisorType()), _itMgr.toVmTO(vmProfile), context, dest);
+            } catch (ResourceUnavailableException | InsufficientCapacityException e) {
+                throw new CloudRuntimeException("Migration of Nic failed", e);
+            }
+        }
+
+        //Mark the old nic as removed
+        markAsNonDefault(originalNic);
+        _networkMgr.removeNic(vmProfile, originalNic);
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Nic is migrated successfully for vm " + vmVO + " to " + networkInNewPhysicalNet);
+        }
+        return true;
+    }
+
+    @Override
+    public void assignNicsToNewPhysicalNetwork(Network srcNetwork, Network networkInNewPhysicalNet) {
+        List<NicVO> nics = _nicDao.listByNetworkId(srcNetwork.getId());
+
+        final CallContext cctx = CallContext.current();
+        final ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount());
+        final DataCenter dc = _entityMgr.findById(DataCenter.class, networkInNewPhysicalNet.getDataCenterId());
+
+        //For each nic in the old network check if the nic belongs to a guest vm and migrate it to the new network.
+        for (NicVO originalNic : nics) {
+            if (originalNic.getVmType() != VirtualMachine.Type.User) {
+                continue;
+            }
+
+            Transaction.execute((TransactionCallback<Boolean>)
+                                            (status) -> migrateNicsInDB(originalNic, networkInNewPhysicalNet, dc, context));
+        }
+
+        //Now that nics are migrated we can migrate the static nats on those nics
+        reapplyPublicIps(srcNetwork, networkInNewPhysicalNet);
+    }
+
+    private void reapplyPublicIps(Network networkInOldPhysicalNetwork, Network networkInNewPhysicalNet) {
+        CallContext ctx = CallContext.current();
+        long callerUserId = ctx.getCallingUserId();
+        Account caller = ctx.getCallingAccount();
+
+        AccountVO networkAccount = _accountDao.findById(networkInNewPhysicalNet.getAccountId());
+        List<? extends IPAddressVO> staticNatIps = _ipAddressDao.listStaticNatPublicIps(networkInOldPhysicalNetwork.getId());
+
+        List<String> providers = _networkOfferingServiceDao.listProvidersForServiceForNetworkOffering(networkInNewPhysicalNet.getNetworkOfferingId(), Network.Service.SourceNat);
+        boolean isSrcNatIpNeeded = providers.stream().anyMatch(provider -> provider.contains(Network.Provider.VirtualRouter.getName()));
+
+        for (IPAddressVO ipAddress : staticNatIps) {
+            if (!ipAddress.isSourceNat() || isSrcNatIpNeeded) {
+                ipAddress.setAssociatedWithNetworkId(networkInNewPhysicalNet.getId());
+                _ipAddressDao.persist(ipAddress);
+            } else {
+                _ipAddressManager.disassociatePublicIpAddress(ipAddress.getId(), callerUserId, caller);
+            }
+        }
+
+        _rulesMgr.applyStaticNatsForNetwork(networkInNewPhysicalNet.getId(), false, networkAccount);
+    }
+
+    private void copyNicDetails(long originalNicId, long dstNicId) {
+        List<NicDetailVO> nicDetails = _nicDetailsDao.listDetails(originalNicId);
+
+        for (NicDetailVO nicDetail : nicDetails) {
+            _nicDetailsDao.persist(new NicDetailVO(dstNicId, nicDetail.getName(), nicDetail.getValue(), nicDetail.isDisplay()));
+        }
+    }
+
+    private void moveServices(NicVO originalNic, NicVO newNic) {
+        _nicIpAliasDao.moveIpAliases(originalNic.getId(), newNic.getId());
+        _nicSecondaryIpDao.moveSecondaryIps(originalNic.getId(), newNic.getId());
+        swapUuids(originalNic, newNic);
+    }
+
+    private void markAsNonDefault(NicVO nic) {
+        nic.setDefaultNic(false);
+        _nicDao.persist(nic);
+    }
+
+    /**
+     * Swaps the UUID's of the given nics's
+     * @param oldNic
+     * @param newNic
+     */
+    private void swapUuids(NicVO oldNic, NicVO newNic) {
+        final String realUuid = oldNic.getUuid();
+        final String dummyUuid = newNic.getUuid();
+
+        oldNic.setUuid(dummyUuid.replace("-", "+"));
+        newNic.setUuid(realUuid);
+        _nicDao.persist(oldNic);
+        _nicDao.persist(newNic);
+
+        oldNic.setUuid(dummyUuid);
+        _nicDao.persist(oldNic);
+    }
+
+    /**
+     * Swaps the UUID's of the given networks
+     * @param oldNetwork
+     * @param newNetwork
+     */
+    private void swapUuids(NetworkVO oldNetwork, NetworkVO newNetwork) {
+        String realUuid = oldNetwork.getUuid();
+        String dummyUuid = newNetwork.getUuid();
+
+        oldNetwork.setUuid(dummyUuid.replace("-","+"));
+        newNetwork.setUuid(realUuid);
+        _networksDao.update(oldNetwork.getId(), oldNetwork);
+        _networksDao.update(newNetwork.getId(), newNetwork);
+
+        oldNetwork.setUuid(dummyUuid);
+        _networksDao.update(oldNetwork.getId(), oldNetwork);
+    }
+
+    /**
+     * Swaps the UUID's of the given vpcs
+     * @param oldVpc
+     * @param newVpc
+     */
+    private void swapUuids(VpcVO oldVpc, VpcVO newVpc) {
+        String realUuid = oldVpc.getUuid();
+        String dummyUuid = newVpc.getUuid();
+
+        oldVpc.setUuid(dummyUuid.replace("-","+"));
+        newVpc.setUuid(realUuid);
+        _vpcDao.update(oldVpc.getId(), oldVpc);
+        _vpcDao.update(newVpc.getId(), newVpc);
+
+        oldVpc.setUuid(dummyUuid);
+        _vpcDao.update(oldVpc.getId(), oldVpc);
+    }
+
+}
diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java
index 9330da1..576503e 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -34,13 +34,14 @@ import java.util.Collections;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.log4j.Logger;
 
 import com.cloud.api.ApiDBUtils;
 import com.cloud.configuration.Config;
@@ -100,7 +101,6 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.projects.dao.ProjectAccountDao;
-import com.cloud.server.ConfigurationServer;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.AccountVO;
@@ -146,23 +146,18 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
     AccountManager _accountMgr;
     @Inject
     ConfigurationDao _configDao;
-
     @Inject
     ConfigurationManager _configMgr;
-
     @Inject
     NetworkOfferingDao _networkOfferingDao = null;
     @Inject
     NetworkDao _networksDao = null;
     @Inject
     NicDao _nicDao = null;
-
     @Inject
     PodVlanMapDao _podVlanMapDao;
-    @Inject
-    ConfigurationServer _configServer;
 
-    List<NetworkElement> networkElements;
+    private List<NetworkElement> networkElements;
 
     public List<NetworkElement> getNetworkElements() {
         return networkElements;
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 7669fd3..a2b5dc1 100644
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -33,12 +33,12 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.UUID;
-
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ApiConstants;
@@ -58,7 +58,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
-import org.apache.log4j.Logger;
 
 import com.cloud.api.ApiDBUtils;
 import com.cloud.configuration.Config;
@@ -70,10 +69,8 @@ import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.DataCenterVnetVO;
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.AccountVlanMapDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DataCenterVnetDao;
-import com.cloud.dc.dao.HostPodDao;
 import com.cloud.dc.dao.VlanDao;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.domain.Domain;
@@ -82,8 +79,6 @@ import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;
-import com.cloud.event.dao.EventDao;
-import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -108,7 +103,6 @@ import com.cloud.network.dao.AccountGuestVlanMapVO;
 import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
-import com.cloud.network.dao.LoadBalancerVMMapDao;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkDetailVO;
 import com.cloud.network.dao.NetworkDetailsDao;
@@ -128,7 +122,6 @@ import com.cloud.network.element.OvsProviderVO;
 import com.cloud.network.element.VirtualRouterElement;
 import com.cloud.network.element.VpcVirtualRouterElement;
 import com.cloud.network.guru.NetworkGuru;
-import com.cloud.network.lb.LoadBalancingRulesService;
 import com.cloud.network.rules.FirewallRule.Purpose;
 import com.cloud.network.rules.FirewallRuleVO;
 import com.cloud.network.rules.RulesManager;
@@ -141,6 +134,7 @@ import com.cloud.network.vpc.VpcManager;
 import com.cloud.network.vpc.dao.NetworkACLDao;
 import com.cloud.network.vpc.dao.PrivateIpDao;
 import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.network.vpc.dao.VpcOfferingDao;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.offerings.dao.NetworkOfferingDao;
@@ -148,11 +142,13 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.org.Grouping;
 import com.cloud.projects.Project;
 import com.cloud.projects.ProjectManager;
+import com.cloud.server.ResourceTag;
 import com.cloud.server.ResourceTag.ResourceObjectType;
 import com.cloud.tags.ResourceTagVO;
 import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
+import com.cloud.user.AccountService;
 import com.cloud.user.AccountVO;
 import com.cloud.user.DomainManager;
 import com.cloud.user.ResourceLimitService;
@@ -191,7 +187,6 @@ import com.cloud.vm.SecondaryStorageVmVO;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
-import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.NicSecondaryIpDao;
 import com.cloud.vm.dao.NicSecondaryIpVO;
@@ -227,19 +222,14 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     @Inject
     UserDao _userDao = null;
     @Inject
-    EventDao _eventDao = null;
-    @Inject
     ConfigurationDao _configDao;
     @Inject
     UserVmDao _userVmDao = null;
-
     @Inject
     AccountManager _accountMgr;
     @Inject
     ConfigurationManager _configMgr;
     @Inject
-    AccountVlanMapDao _accountVlanMapDao;
-    @Inject
     NetworkOfferingDao _networkOfferingDao = null;
     @Inject
     NetworkDao _networksDao = null;
@@ -247,23 +237,15 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     NicDao _nicDao = null;
     @Inject
     RulesManager _rulesMgr;
-
-    @Inject
-    UsageEventDao _usageEventDao;
-
     List<NetworkGuru> _networkGurus;
-
     @Inject
     NetworkDomainDao _networkDomainDao;
     @Inject
     VMInstanceDao _vmDao;
-
     @Inject
     FirewallRulesDao _firewallDao;
-
     @Inject
     ResourceLimitService _resourceLimitMgr;
-
     @Inject
     DomainManager _domainMgr;
     @Inject
@@ -274,10 +256,8 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     PhysicalNetworkDao _physicalNetworkDao;
     @Inject
     PhysicalNetworkServiceProviderDao _pNSPDao;
-
     @Inject
     PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
-
     @Inject
     NetworkServiceMapDao _ntwkSrvcDao;
     @Inject
@@ -292,17 +272,13 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     NetworkOrchestrationService _networkMgr;
     @Inject
     NetworkModel _networkModel;
-
     @Inject
     NicSecondaryIpDao _nicSecondaryIpDao;
-
     @Inject
     PortForwardingRulesDao _portForwardingDao;
     @Inject
     HostDao _hostDao;
     @Inject
-    HostPodDao _hostPodDao;
-    @Inject
     InternalLoadBalancerElementService _internalLbElementSvc;
     @Inject
     DataCenterVnetDao _datacneterVnet;
@@ -319,25 +295,19 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     @Inject
     EntityManager _entityMgr;
     @Inject
-    LoadBalancerVMMapDao _lbVmMapDao;
-
-    @Inject
-    LoadBalancingRulesService _lbService;
-
-    @Inject
     public SecurityGroupService _securityGroupService;
-
     @Inject
     MessageBus _messageBus;
-
-    @Inject
-    DomainRouterDao _routerDao;
-
     @Inject
     NetworkDetailsDao _networkDetailsDao;
-
     @Inject
     LoadBalancerDao _loadBalancerDao;
+    @Inject
+    NetworkMigrationManager _networkMigrationManager;
+    @Inject
+    VpcOfferingDao _vpcOfferingDao;
+    @Inject
+    AccountService _accountService;
 
     int _cidrLimit;
     boolean _allowSubdomainNetworkAccess;
@@ -947,9 +917,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
 
         // don't allow releasing system ip address
         if (ipVO.getSystem()) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Can't release system IP address with specified id");
-            ex.addProxyObject(ipVO.getUuid(), "systemIpAddrId");
-            throw ex;
+            throwInvalidIdException("Can't release system IP address with specified id", ipVO.getUuid(), "systemIpAddrId");
         }
 
         boolean success = _ipAddrMgr.disassociatePublicIpAddress(ipAddressId, userId, caller);
@@ -1319,9 +1287,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
 
         // Can add vlan range only to the network which allows it
         if (createVlan && !ntwkOff.getSpecifyIpRanges()) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id doesn't support adding multiple ip ranges");
-            ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId");
-            throw ex;
+            throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), "networkOfferingId");
         }
 
         Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zoneId, domainId,
@@ -1521,9 +1487,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                 }
                 if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) {
                     // getProject() returns type ProjectVO.
-                    InvalidParameterValueException ex = new InvalidParameterValueException("Account " + caller + " cannot access specified project id");
-                    ex.addProxyObject(project.getUuid(), "projectId");
-                    throw ex;
+                    throwInvalidIdException("Account " + caller + " cannot access specified project id", project.getUuid(), "projectId");
                 }
 
                 //add project account
@@ -1847,16 +1811,12 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         if (network == null) {
             // see NetworkVO.java
 
-            InvalidParameterValueException ex = new InvalidParameterValueException("unable to find network with specified id");
-            ex.addProxyObject(String.valueOf(networkId), "networkId");
-            throw ex;
+            throwInvalidIdException("unable to find network with specified id", String.valueOf(networkId), "networkId");
         }
 
         // don't allow to delete system network
         if (isNetworkSystem(network)) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id is system and can't be removed");
-            ex.addProxyObject(network.getUuid(), "networkId");
-            throw ex;
+            throwInvalidIdException("Network with specified id is system and can't be removed", network.getUuid(), "networkId");
         }
 
         Account owner = _accountMgr.getAccount(network.getAccountId());
@@ -1891,9 +1851,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // Check if network exists
         NetworkVO network = _networksDao.findById(networkId);
         if (network == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id doesn't exist");
-            ex.addProxyObject(networkId.toString(), "networkId");
-            throw ex;
+            throwInvalidIdException("Network with specified id doesn't exist", networkId.toString(), "networkId");
         }
 
         // Don't allow to restart network if it's not in Implemented/Setup state
@@ -2019,9 +1977,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         final NetworkVO network = _networksDao.findById(networkId);
         if (network == null) {
             // see NetworkVO.java
-            InvalidParameterValueException ex = new InvalidParameterValueException("Specified network id doesn't exist in the system");
-            ex.addProxyObject(String.valueOf(networkId), "networkId");
-            throw ex;
+            throwInvalidIdException("Specified network id doesn't exist in the system", String.valueOf(networkId), "networkId");
         }
 
         //perform below validation if the network is vpc network
@@ -2083,17 +2039,13 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
         if (networkOfferingId != null) {
             if (networkOffering == null || networkOffering.isSystemOnly()) {
-                InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering with specified id");
-                ex.addProxyObject(networkOfferingId.toString(), "networkOfferingId");
-                throw ex;
+                throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), "networkOfferingId");
             }
 
             // network offering should be in Enabled state
             if (networkOffering.getState() != NetworkOffering.State.Enabled) {
-                InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id is not in " + NetworkOffering.State.Enabled
-                        + " state, can't upgrade to it");
-                ex.addProxyObject(networkOffering.getUuid(), "networkOfferingId");
-                throw ex;
+                throwInvalidIdException("Network offering with specified id is not in " + NetworkOffering.State.Enabled
+                        + " state, can't upgrade to it", networkOffering.getUuid(), "networkOfferingId");
             }
             //can't update from vpc to non-vpc network offering
             boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering);
@@ -2112,9 +2064,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                 }
                 if (changeCidr) {
                     if (!checkForNonStoppedVmInNetwork(network.getId())) {
-                        InvalidParameterValueException ex = new InvalidParameterValueException("All user vm of network of specified id should be stopped before changing CIDR!");
-                        ex.addProxyObject(network.getUuid(), "networkId");
-                        throw ex;
+                        throwInvalidIdException("All user vm of network of specified id should be stopped before changing CIDR!", network.getUuid(), "networkId");
                     }
                 }
                 // check if the network is upgradable
@@ -2171,7 +2121,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             if (network.getGuestType() != GuestType.Isolated) {
                 throw new InvalidParameterValueException("Can only allow IP Reservation in networks with guest type " + GuestType.Isolated);
             }
-            if (networkOfferingChanged == true) {
+            if (networkOfferingChanged) {
                 throw new InvalidParameterValueException("Cannot specify this nework offering change and guestVmCidr at same time. Specify only one.");
             }
             if (!(network.getState() == Network.State.Implemented)) {
@@ -2214,12 +2164,10 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                 for (NicVO nic : nicsPresent) {
                     long nicIp = NetUtils.ip2Long(nic.getIPv4Address());
                     //check if nic IP is outside the guest vm cidr
-                    if (nicIp < startIp || nicIp > endIp) {
-                    if (!(nic.getState() == Nic.State.Deallocating)) {
+                    if ((nicIp < startIp || nicIp > endIp) && nic.getState() != Nic.State.Deallocating) {
                             throw new InvalidParameterValueException("Active IPs like " + nic.getIPv4Address() + " exist outside the Guest VM CIDR. Cannot apply reservation ");
-                            }
-                        }
                     }
+                }
 
                 // In some scenarios even though guesVmCidr and network CIDR do not appear similar but
                 // the IP ranges exactly matches, in these special cases make sure no Reservation gets applied
@@ -2259,7 +2207,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate
         // states - Shutdown and Implementing
         int resourceCount=1;
-        if(updateInSequence && restartNetwork && _networkOfferingDao.findById(network.getNetworkOfferingId()).getRedundantRouter()
+        if (updateInSequence && restartNetwork && _networkOfferingDao.findById(network.getNetworkOfferingId()).getRedundantRouter()
                 && (networkOfferingId==null || _networkOfferingDao.findById(networkOfferingId).getRedundantRouter()) && network.getVpcId()==null) {
             _networkMgr.canUpdateInSequence(network, forced);
             NetworkDetailVO networkDetail =new NetworkDetailVO(network.getId(),Network.updatingInSequence,"true",true);
@@ -2268,19 +2216,20 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             resourceCount=_networkMgr.getResourceCount(network);
         }
         List<String > servicesNotInNewOffering = null;
-        if(networkOfferingId != null)
-                 servicesNotInNewOffering = _networkMgr.getServicesNotSupportedInNewOffering(network,networkOfferingId);
-        if(!forced && servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()){
+        if (networkOfferingId != null) {
+            servicesNotInNewOffering = _networkMgr.getServicesNotSupportedInNewOffering(network, networkOfferingId);
+        }
+        if (!forced && servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) {
             NetworkOfferingVO newOffering = _networkOfferingDao.findById(networkOfferingId);
             throw new CloudRuntimeException("The new offering:"+newOffering.getUniqueName()
                     +" will remove the following services "+servicesNotInNewOffering +"along with all the related configuration currently in use. will not proceed with the network update." +
                     "set forced parameter to true for forcing an update.");
         }
-        try{
-            if(servicesNotInNewOffering!=null && !servicesNotInNewOffering.isEmpty()){
+        try {
+            if (servicesNotInNewOffering!=null && !servicesNotInNewOffering.isEmpty()) {
                 _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering,network);
             }
-        }catch (Throwable e){
+        } catch (Throwable e) {
             s_logger.debug("failed to cleanup config related to unused services error:"+e.getMessage());
         }
 
@@ -2411,13 +2360,14 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                     }
                 }
                 resourceCount--;
-            } while(updateInSequence && resourceCount>0);
-        }catch (Exception exception){
-             if(updateInSequence)
-                 _networkMgr.finalizeUpdateInSequence(network,false);
+            } while (updateInSequence && resourceCount>0);
+        } catch (Exception exception) {
+             if (updateInSequence) {
+                 _networkMgr.finalizeUpdateInSequence(network, false);
+             }
              throw new CloudRuntimeException("failed to update network "+network.getUuid()+" due to "+exception.getMessage());
-        }finally {
-            if(updateInSequence){
+        } finally {
+            if (updateInSequence) {
                 if( _networkDetailsDao.findDetail(networkId,Network.updatingInSequence)!=null){
                     _networkDetailsDao.removeDetail(networkId,Network.updatingInSequence);
                 }
@@ -2426,74 +2376,357 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         return getNetwork(network.getId());
     }
 
-    protected Set<Long> getAvailableIps(Network network, String requestedIp) {
-        String[] cidr = network.getCidr().split("/");
-        List<String> ips = _nicDao.listIpAddressInNetwork(network.getId());
-        Set<Long> usedIps = new TreeSet<Long>();
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_MIGRATE, eventDescription = "migrating network", async = true)
+    public Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume) {
+        NetworkVO network = _networksDao.findById(networkId);
+        NetworkOffering newNtwkOff = _networkOfferingDao.findById(networkOfferingId);
 
-        for (String ip : ips) {
-            if (requestedIp != null && requestedIp.equals(ip)) {
-                s_logger.warn("Requested ip address " + requestedIp + " is already in use in network" + network);
-                return null;
+        //perform below validation if the network is vpc network
+        if (network.getVpcId() != null) {
+            s_logger.warn("Failed to migrate network as the specified network is a vpc tier. Use migrateVpc.");
+            throw new InvalidParameterValueException("Failed to migrate network as the specified network is a vpc tier. Use migrateVpc.");
+        }
+
+        if (_configMgr.isOfferingForVpc(newNtwkOff)) {
+            s_logger.warn("Failed to migrate network as the specified network offering is a VPC offering");
+            throw new InvalidParameterValueException("Failed to migrate network as the specified network offering is a VPC offering");
+        }
+
+        verifyNetworkCanBeMigrated(callerAccount, network);
+
+        //Retrieve new Physical NetworkId
+        long newPhysicalNetworkId = findPhysicalNetworkId(network.getDataCenterId(), newNtwkOff.getTags(), newNtwkOff.getTrafficType());
+
+        final long oldNetworkOfferingId = network.getNetworkOfferingId();
+        NetworkOffering oldNtwkOff = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+
+        if (!resume && network.getRelated() != network.getId()) {
+            s_logger.warn("Related network is not equal to network id. You might want to re-run migration with resume = true command.");
+            throw new CloudRuntimeException("Failed to migrate network as previous migration left this network in transient condition. Specify resume as true.");
+        }
+
+        if (networkNeedsMigration(network, newPhysicalNetworkId, oldNtwkOff, newNtwkOff)) {
+            return migrateNetworkToPhysicalNetwork(network, oldNtwkOff, newNtwkOff, null, null, newPhysicalNetworkId, callerAccount, callerUser);
+        } else {
+            s_logger.info("Network does not need migration.");
+            return network;
+        }
+    }
+
+    private class NetworkCopy {
+        private Long networkIdInOldPhysicalNet;
+        private Network networkInNewPhysicalNet;
+
+        public NetworkCopy(Long networkIdInOldPhysicalNet, Network networkInNewPhysicalNet) {
+            this.networkIdInOldPhysicalNet = networkIdInOldPhysicalNet;
+            this.networkInNewPhysicalNet = networkInNewPhysicalNet;
+        }
+
+        public Long getNetworkIdInOldPhysicalNet() {
+            return networkIdInOldPhysicalNet;
+        }
+
+        public Network getNetworkInNewPhysicalNet() {
+            return networkInNewPhysicalNet;
+        }
+    }
+
+    private Network migrateNetworkToPhysicalNetwork(Network network, NetworkOffering oldNtwkOff, NetworkOffering newNtwkOff, Long oldVpcId, Long newVpcId, long newPhysicalNetworkId, Account callerAccount, User callerUser) {
+        boolean resume = network.getRelated() != network.getId();
+
+        NetworkCopy networkCopy;
+
+        // Resume is only true when there is already a copy of the network created
+        if (resume) {
+            Network networkInNewPhysicalNet = network;
+            networkCopy = new NetworkCopy(network.getRelated(), networkInNewPhysicalNet);
+
+            //the new network could already be implemented, check if the already partially upgrade networks has the same network offering as before or check if it still has the original network offering
+            //the old network offering uuid should be the one of the already created copy
+            if (networkInNewPhysicalNet.getNetworkOfferingId() != newNtwkOff.getId()) {
+                throw new InvalidParameterValueException("Failed to resume migrating network as network offering does not match previously specified network offering (" + newNtwkOff.getUuid() + ")");
             }
+        } else {
+            networkCopy = Transaction.execute(
+                    (TransactionCallback<NetworkCopy>)
+                            (status) -> migrateNetworkInDb(network, oldNtwkOff, newNtwkOff, oldVpcId, newVpcId, newPhysicalNetworkId));
+        }
+
+        Long networkIdInOldPhysicalNet = networkCopy.getNetworkIdInOldPhysicalNet();
+        Network networkInNewPhysicalNet = networkCopy.getNetworkInNewPhysicalNet();
+
+        ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount);
+        DataCenter zone = _dcDao.findById(network.getDataCenterId());
+        NetworkVO networkInOldPhysNet = _networksDao.findById(networkIdInOldPhysicalNet);
 
-            usedIps.add(NetUtils.ip2Long(ip));
+        boolean shouldImplement = (newNtwkOff.getIsPersistent()
+                    || networkInOldPhysNet.getState() == Network.State.Implemented)
+                && networkInNewPhysicalNet.getState() != Network.State.Implemented;
+
+        if (shouldImplement) {
+            DeployDestination dest = new DeployDestination(zone, null, null, null);
+            s_logger.debug("Implementing the network " + network + " elements and resources as a part of network update");
+            try {
+                networkInNewPhysicalNet = _networkMgr.implementNetwork(networkInNewPhysicalNet.getId(), dest, context)
+                                                     .second();
+            } catch (Exception ex) {
+                s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network update due to ", ex);
+                CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of network update");
+                e.addProxyObject(network.getUuid(), "networkId");
+                throw e;
+            }
         }
-        Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]), usedIps);
 
-        String gateway = network.getGateway();
-        if ((gateway != null) && (allPossibleIps.contains(NetUtils.ip2Long(gateway))))
-            allPossibleIps.remove(NetUtils.ip2Long(gateway));
+        _networkMigrationManager.assignNicsToNewPhysicalNetwork(networkInOldPhysNet, networkInNewPhysicalNet);
+        //clean up the old copy of the network
+        _networkMigrationManager.deleteCopyOfNetwork(networkIdInOldPhysicalNet, networkInNewPhysicalNet.getId());
 
-        return allPossibleIps;
+        return getNetwork(network.getId());
     }
 
-    protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long newNetworkOfferingId) {
+    private NetworkCopy migrateNetworkInDb(Network network, NetworkOffering oldNtwkOff, NetworkOffering newNtwkOff, Long oldVpcId, Long newVpcId, long newPhysicalNetworkId) {
+        //The copy will be the network in the old physical network
+        //And we will use it to store tmp data while we upgrade or original network to the new physical network
+        Long networkIdInOldPhysicalNet = _networkMigrationManager.makeCopyOfNetwork(network, oldNtwkOff, oldVpcId);
+        Network networkInNewPhysicalNet = _networkMigrationManager.upgradeNetworkToNewNetworkOffering(network.getId(), newPhysicalNetworkId,newNtwkOff.getId(), newVpcId);
+        return new NetworkCopy(networkIdInOldPhysicalNet, networkInNewPhysicalNet);
+    }
+
+    @Override
+    public Vpc migrateVpcNetwork(long vpcId, long vpcOfferingId, Map<String, String> networkToOffering, Account account, User callerUser, boolean resume) {
+        //Check if a previous migration run failed and try to resume if resume = true
+        ResourceTag relatedVpc = _resourceTagDao.findByKey(vpcId, ResourceObjectType.Vpc, NetworkMigrationManager.MIGRATION);
+        long vpcCopyId = 0;
+
+        /*
+         * In the vpc migration process the newly created Vpc will be used as the new VPC (opposed to network tier migration).
+         * In case the copy of the vpc was already created. The uuid where already swapped and the id we receive here is the id of the Copy!
+         * The id stored in the resource tag table under the key "migration" is the id of the ORIGINAL vpc!
+         */
+        if (relatedVpc != null) {
+            if (resume) {
+                vpcCopyId = vpcId;
+                vpcId = Long.parseLong(relatedVpc.getValue());
+                //let's check if the user did not change the vpcoffering opposed to the last failed run.
+                verifyAlreadyMigratedTiers(vpcCopyId, vpcOfferingId, networkToOffering);
+            } else {
+                s_logger.warn("This vpc has a migration row in the resource details table. You might want to re-run migration with resume = true command.");
+                throw new CloudRuntimeException("Failed to migrate VPC as previous migration left this VPC in transient condition. Specify resume as true.");
+            }
+        }
+
+        Vpc vpc = _vpcDao.findById(vpcId);
+        _accountMgr.checkAccess(account, null, true, vpc);
+
+        if (vpc.getVpcOfferingId() == vpcOfferingId) {
+            return vpc;
+        }
+        //Try to fail fast, check networks in the VPC and if we can migrate them before proceeding.
+        List<NetworkVO> tiersInVpc = _networksDao.listByVpc(vpcId);
+        vpcTiersCanBeMigrated(tiersInVpc, account, networkToOffering, resume);
+
+        //In case this is the first time we try to migrate this vpc
+        if (relatedVpc == null) {
+            final long vpcIdFinal = vpcId;
+            vpcCopyId = Transaction.execute((TransactionCallback<Long>)(status) -> _networkMigrationManager.makeCopyOfVpc(vpcIdFinal, vpcOfferingId));
+        }
+
+        Vpc copyOfVpc = _vpcDao.findById(vpcCopyId);
+        _networkMigrationManager.startVpc(copyOfVpc);
+
+        for (Network tier : tiersInVpc) {
+            String networkOfferingUuid = networkToOffering.get(tier.getUuid());
+            //UUID may be swapped already with a new uuid due to previous migration failure.
+            //So we check the related network also in case we don't find the network offering
+            Long networkId = null;
+            if (resume && networkOfferingUuid == null) {
+                tier = _networksDao.findById(tier.getRelated());
+                networkOfferingUuid = networkToOffering.get(tier.getUuid());
+                //In this case the tier already exists so we need to get the id of the tier so we can validate correctly
+                networkId = tier.getId();
+            }
+            NetworkOfferingVO newNtwkOff = _networkOfferingDao.findByUuid(networkOfferingUuid);
+
+            Account networkAccount = _accountService.getActiveAccountById(tier.getAccountId());
+            try {
+                _vpcMgr.validateNtwkOffForNtwkInVpc(networkId, newNtwkOff.getId(), tier.getCidr(), tier.getNetworkDomain(), copyOfVpc, tier.getGateway(), networkAccount, tier.getNetworkACLId());
+            } catch (InvalidParameterValueException e) {
+                s_logger.error("Specified network offering can not be used in combination with specified vpc offering. Aborting migration. You can re-run with resume = true and the correct uuid.");
+                throw e;
+            }
+
+            long newPhysicalNetworkId = findPhysicalNetworkId(tier.getDataCenterId(), newNtwkOff.getTags(), newNtwkOff.getTrafficType());
+
+            final long oldNetworkOfferingId = tier.getNetworkOfferingId();
+            NetworkOffering oldNtwkOff = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+
+            if (networkNeedsMigration(tier, newPhysicalNetworkId, oldNtwkOff, newNtwkOff) || (resume && tier.getRelated() != tier.getId())) {
+                migrateNetworkToPhysicalNetwork(tier, oldNtwkOff, newNtwkOff, vpcId, vpcCopyId, newPhysicalNetworkId, account, callerUser);
+            }
+        }
+        _networkMigrationManager.deleteCopyOfVpc(vpcId, vpcCopyId);
+        return _vpcDao.findById(vpcCopyId);
+    }
+
+    private void vpcTiersCanBeMigrated(List<? extends Network> tiersInVpc, Account account, Map<String, String> networkToOffering, boolean resume) {
+        for (Network network : tiersInVpc) {
+            String networkOfferingUuid = networkToOffering.get(network.getUuid());
+
+            //offering uuid can be a tier where the uuid is previously already swapped in a previous migration
+            if (resume && networkOfferingUuid == null) {
+                NetworkVO oldVPCtier = _networksDao.findById(network.getRelated());
+                networkOfferingUuid = networkToOffering.get(oldVPCtier.getUuid());
+            }
+
+            if (networkOfferingUuid == null) {
+                throwInvalidIdException("Failed to migrate VPC as the specified tierNetworkOfferings is not complete",
+                                        String.valueOf(network.getUuid()), "networkUuid");
+            }
+
+            NetworkOfferingVO newNtwkOff = _networkOfferingDao.findByUuid(networkOfferingUuid);
+
+            if (newNtwkOff == null) {
+                throwInvalidIdException("Failed to migrate VPC as at least one network offering in tierNetworkOfferings does not exist", networkOfferingUuid, "networkOfferingUuid");
+            }
+
+            if (!_configMgr.isOfferingForVpc(newNtwkOff)) {
+                throw new InvalidParameterValueException("Network offering " + newNtwkOff.getName() + " ("+ newNtwkOff.getUuid() +") can't be used for VPC networks for network " + network.getName() + "(" + network.getUuid() + ")");
+            }
+
+            verifyNetworkCanBeMigrated(account, network);
+            long newPhysicalNetworkId = findPhysicalNetworkId(network.getDataCenterId(), newNtwkOff.getTags(), newNtwkOff.getTrafficType());
+
+            final long oldNetworkOfferingId = network.getNetworkOfferingId();
+            NetworkOffering oldNtwkOff = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+            networkNeedsMigration(network, newPhysicalNetworkId, oldNtwkOff, newNtwkOff);
+        }
+    }
+
+    private void verifyAlreadyMigratedTiers(long migratedVpcId, long vpcOfferingId, Map<String, String> networkToOffering) {
+        Vpc migratedVpc = _vpcDao.findById(migratedVpcId);
+        if (migratedVpc.getVpcOfferingId() != vpcOfferingId) {
+            s_logger.error("The vpc is already partially migrated in a previous run. The provided vpc offering is not the same as the one used during the first migration process.");
+            throw new InvalidParameterValueException("Failed to resume migrating VPC as VPC offering does not match previously specified VPC offering (" + migratedVpc.getVpcOfferingId() + ")");
+        }
+
+        List<NetworkVO> migratedTiers = _networksDao.listByVpc(migratedVpcId);
+        for (Network tier : migratedTiers) {
+            String tierNetworkOfferingUuid = networkToOffering.get(tier.getUuid());
+
+            if (!StringUtils.isNotBlank(tierNetworkOfferingUuid)) {
+                throwInvalidIdException("Failed to resume migrating VPC as the specified tierNetworkOfferings is not complete",
+                                        String.valueOf(tier.getUuid()), "networkUuid");
+            }
+
+            NetworkOfferingVO newNetworkOffering = _networkOfferingDao.findByUuid(tierNetworkOfferingUuid);
+            if (newNetworkOffering == null) {
+                throw new InvalidParameterValueException("Failed to migrate VPC as at least one tier offering in tierNetworkOfferings does not exist.");
+            }
+
+            if (newNetworkOffering.getId() != tier.getNetworkOfferingId()) {
+                NetworkOfferingVO tierNetworkOffering = _networkOfferingDao.findById(tier.getNetworkOfferingId());
+                throw new InvalidParameterValueException("Failed to resume migrating VPC as at least one network offering in tierNetworkOfferings does not match previously specified network offering (network uuid=" + tier.getUuid() + " was previously specified with offering uuid=" + tierNetworkOffering.getUuid() + ")");
+            }
+        }
+    }
+
+
+    private void throwInvalidIdException(String message, String uuid, String description) {
+        InvalidParameterValueException ex = new InvalidParameterValueException(message);
+        ex.addProxyObject(uuid, description);
+        throw ex;
+    }
+
+    private boolean networkNeedsMigration(Network network, long newPhysicalNetworkId, NetworkOffering oldNtwkOff, NetworkOffering newNtwkOff) {
+
+        if (newNtwkOff == null || newNtwkOff.isSystemOnly()) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering.");
+            if (newNtwkOff != null) {
+                ex.addProxyObject(String.valueOf(newNtwkOff.getId()), "networkOfferingId");
+            }
+            throw ex;
+        }
+
+        if (newNtwkOff.getId() != oldNtwkOff.getId() || network.getId() != network.getRelated()) {
+            Collection<String> newProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(newNtwkOff, newPhysicalNetworkId)
+                                                         .values();
+            Collection<String> oldProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(oldNtwkOff, network.getPhysicalNetworkId())
+                                                         .values();
+
+            if (providersConfiguredForExternalNetworking(newProviders) != providersConfiguredForExternalNetworking(oldProviders)) {
+                throw new InvalidParameterValueException("Updating network failed since guest CIDR needs to be changed!");
+            }
+
+            // check if the network is moveable
+            if (!canMoveToPhysicalNetwork(network, oldNtwkOff.getId(), newNtwkOff.getId())) {
+                throw new InvalidParameterValueException(
+                        "Can't upgrade from network offering " + oldNtwkOff.getUuid() + " to " + newNtwkOff.getUuid() + "; check logs for more information");
+            }
+
+            List<VMInstanceVO> vmInstances = _vmDao.listNonRemovedVmsByTypeAndNetwork(network.getId(), null);
+            boolean vmStateIsNotTransitioning = vmInstances.stream()
+                                   .anyMatch(vm -> vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Running);
+            if (vmStateIsNotTransitioning) {
+                throw new CloudRuntimeException("Failed to migrate network as at least one VM is not in running or stopped state.");
+            }
+        } else {
+            return false;
+        }
+
+        // network offering should be in Enabled state
+        if (newNtwkOff.getState() != NetworkOffering.State.Enabled) {
+            throw new InvalidParameterValueException("Failed to migrate network as the specified network offering is not enabled.");
+        }
+        return true;
+    }
+
+    private void verifyNetworkCanBeMigrated(Account callerAccount, Network network) {
+        // Don't allow to update system network
+        NetworkOffering oldOffering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
+        if (oldOffering.isSystemOnly()) {
+            throw new InvalidParameterValueException("Failed to migrate network as the specified network is a system network.");
+        }
+
+        // allow to upgrade only Guest networks
+        if (network.getTrafficType() != TrafficType.Guest) {
+            throw new InvalidParameterValueException("Can't allow networks which traffic type is not " + TrafficType.Guest);
+        }
+
+        _accountMgr.checkAccess(callerAccount, null, true, network);
+
+        boolean validateNetworkReadyToMigrate = (network.getState() == Network.State.Implemented
+                || network.getState() == Network.State.Setup
+                || network.getState() == Network.State.Allocated);
+        if (!validateNetworkReadyToMigrate) {
+            s_logger.error("Failed to migrate network as it is in invalid state.");
+            CloudRuntimeException ex = new CloudRuntimeException("Failed to migrate network as it is in invalid state.");
+            ex.addProxyObject(network.getUuid(), "networkId");
+            throw ex;
+        }
+    }
+
+    private boolean canMoveToPhysicalNetwork(Network network, long oldNetworkOfferingId, long newNetworkOfferingId) {
         NetworkOffering oldNetworkOffering = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
         NetworkOffering newNetworkOffering = _networkOfferingDao.findById(newNetworkOfferingId);
 
-        // can upgrade only Isolated networks
+        // can move only Isolated networks for now
         if (oldNetworkOffering.getGuestType() != GuestType.Isolated) {
             throw new InvalidParameterValueException("NetworkOfferingId can be upgraded only for the network of type " + GuestType.Isolated);
         }
 
-        // security group service should be the same
-        if (areServicesSupportedByNetworkOffering(oldNetworkOfferingId, Service.SecurityGroup) != areServicesSupportedByNetworkOffering(newNetworkOfferingId, Service.SecurityGroup)) {
-            s_logger.debug("Offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different securityGroupProperty, can't upgrade");
-            return false;
-        }
-
         // Type of the network should be the same
         if (oldNetworkOffering.getGuestType() != newNetworkOffering.getGuestType()) {
             s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " are of different types, can't upgrade");
             return false;
         }
 
-        // tags should be the same
-        if (newNetworkOffering.getTags() != null) {
-            if (oldNetworkOffering.getTags() == null) {
-                s_logger.debug("New network offering id=" + newNetworkOfferingId + " has tags and old network offering id=" + oldNetworkOfferingId + " doesn't, can't upgrade");
-                return false;
-            }
-
-            if (!StringUtils.areTagsEqual(oldNetworkOffering.getTags(), newNetworkOffering.getTags())) {
-                s_logger.debug("Network offerings " + newNetworkOffering.getUuid() + " and " + oldNetworkOffering.getUuid() + " have different tags, can't upgrade");
-                return false;
-            }
-        }
-
         // Traffic types should be the same
         if (oldNetworkOffering.getTrafficType() != newNetworkOffering.getTrafficType()) {
             s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different traffic types, can't upgrade");
             return false;
         }
 
-        // specify vlan should be the same
-        if (oldNetworkOffering.getSpecifyVlan() != newNetworkOffering.getSpecifyVlan()) {
-            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different values for specifyVlan, can't upgrade");
-            return false;
-        }
-
         // specify ipRanges should be the same
         if (oldNetworkOffering.getSpecifyIpRanges() != newNetworkOffering.getSpecifyIpRanges()) {
             s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different values for specifyIpRangess, can't upgrade");
@@ -2525,6 +2758,38 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         return canIpsUseOffering(publicIps, newNetworkOfferingId);
     }
 
+    protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long newNetworkOfferingId) {
+        NetworkOffering oldNetworkOffering = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+        NetworkOffering newNetworkOffering = _networkOfferingDao.findById(newNetworkOfferingId);
+
+        // security group service should be the same
+        if (areServicesSupportedByNetworkOffering(oldNetworkOfferingId, Service.SecurityGroup) != areServicesSupportedByNetworkOffering(newNetworkOfferingId, Service.SecurityGroup)) {
+            s_logger.debug("Offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different securityGroupProperty, can't upgrade");
+            return false;
+        }
+
+        // tags should be the same
+        if (newNetworkOffering.getTags() != null) {
+            if (oldNetworkOffering.getTags() == null) {
+                s_logger.debug("New network offering id=" + newNetworkOfferingId + " has tags and old network offering id=" + oldNetworkOfferingId + " doesn't, can't upgrade");
+                return false;
+            }
+
+            if (!StringUtils.areTagsEqual(oldNetworkOffering.getTags(), newNetworkOffering.getTags())) {
+                s_logger.debug("Network offerings " + newNetworkOffering.getUuid() + " and " + oldNetworkOffering.getUuid() + " have different tags, can't upgrade");
+                return false;
+            }
+        }
+
+        // specify vlan should be the same
+        if (oldNetworkOffering.getSpecifyVlan() != newNetworkOffering.getSpecifyVlan()) {
+            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different values for specifyVlan, can't upgrade");
+            return false;
+        }
+
+        return  canMoveToPhysicalNetwork(network, oldNetworkOfferingId, newNetworkOfferingId);
+    }
+
     @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_PHYSICAL_NETWORK_CREATE, eventDescription = "Creating Physical Network", create = true)
@@ -2668,17 +2933,13 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // verify input parameters
         PhysicalNetworkVO network = _physicalNetworkDao.findById(id);
         if (network == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Physical Network with specified id doesn't exist in the system");
-            ex.addProxyObject(id.toString(), "physicalNetworkId");
-            throw ex;
+            throwInvalidIdException("Physical Network with specified id doesn't exist in the system", id.toString(), "physicalNetworkId");
         }
 
         // if zone is of Basic type, don't allow to add vnet range
         DataCenter zone = _dcDao.findById(network.getDataCenterId());
         if (zone == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Zone with id=" + network.getDataCenterId() + " doesn't exist in the system");
-            ex.addProxyObject(String.valueOf(network.getDataCenterId()), "dataCenterId");
-            throw ex;
+            throwInvalidIdException("Zone with id=" + network.getDataCenterId() + " doesn't exist in the system", String.valueOf(network.getDataCenterId()), "dataCenterId");
         }
         if (newVnetRange != null) {
             if (zone.getNetworkType() == NetworkType.Basic || (zone.getNetworkType() == NetworkType.Advanced && zone.isSecurityGroupEnabled())) {
@@ -2948,9 +3209,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // verify input parameters
         PhysicalNetworkVO pNetwork = _physicalNetworkDao.findById(physicalNetworkId);
         if (pNetwork == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Physical Network with specified id doesn't exist in the system");
-            ex.addProxyObject(physicalNetworkId.toString(), "physicalNetworkId");
-            throw ex;
+            throwInvalidIdException("Physical Network with specified id doesn't exist in the system", physicalNetworkId.toString(), "physicalNetworkId");
         }
 
         checkIfPhysicalNetworkIsDeletable(physicalNetworkId);
@@ -3277,9 +3536,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         if (projectId != null) {
             Project project = _projectMgr.getProject(projectId);
             if (project == null) {
-                InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find project by id " + projectId);
-                ex.addProxyObject(projectId.toString(), "projectId");
-                throw ex;
+                throwInvalidIdException("Unable to find project by id " + projectId, projectId.toString(), "projectId");
             }
             accountId = project.getProjectAccountId();
         }
@@ -3371,18 +3628,15 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // verify input parameters
         PhysicalNetworkVO network = _physicalNetworkDao.findById(physicalNetworkId);
         if (network == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Physical Network with specified id doesn't exist in the system");
-            ex.addProxyObject(physicalNetworkId.toString(), "physicalNetworkId");
-            throw ex;
+            throwInvalidIdException("Physical Network with specified id doesn't exist in the system", physicalNetworkId.toString(), "physicalNetworkId");
         }
 
         // verify input parameters
         if (destinationPhysicalNetworkId != null) {
             PhysicalNetworkVO destNetwork = _physicalNetworkDao.findById(destinationPhysicalNetworkId);
             if (destNetwork == null) {
-                InvalidParameterValueException ex = new InvalidParameterValueException("Destination Physical Network with specified id doesn't exist in the system");
-                ex.addProxyObject(destinationPhysicalNetworkId.toString(), "destinationPhysicalNetworkId");
-                throw ex;
+                throwInvalidIdException("Destination Physical Network with specified id doesn't exist in the system", destinationPhysicalNetworkId.toString(),
+                                        "destinationPhysicalNetworkId");
             }
         }
 
@@ -3836,9 +4090,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     public Pair<List<? extends PhysicalNetworkTrafficType>, Integer> listTrafficTypes(Long physicalNetworkId) {
         PhysicalNetworkVO network = _physicalNetworkDao.findById(physicalNetworkId);
         if (network == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Physical Network with specified id doesn't exist in the system");
-            ex.addProxyObject(physicalNetworkId.toString(), "physicalNetworkId");
-            throw ex;
+            throwInvalidIdException("Physical Network with specified id doesn't exist in the system", physicalNetworkId.toString(), "physicalNetworkId");
         }
 
         Pair<List<PhysicalNetworkTrafficTypeVO>, Integer> result = _pNTrafficTypeDao.listAndCountBy(physicalNetworkId);
@@ -4038,9 +4290,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         // Validate physical network
         final PhysicalNetwork pNtwk = _physicalNetworkDao.findById(physicalNetworkId);
         if (pNtwk == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find a physical network" + " having the given id");
-            ex.addProxyObject(String.valueOf(physicalNetworkId), "physicalNetworkId");
-            throw ex;
+            throwInvalidIdException("Unable to find a physical network" + " having the given id", String.valueOf(physicalNetworkId), "physicalNetworkId");
         }
 
         // VALIDATE IP INFO
@@ -4152,9 +4402,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         UserVmVO  userVm = _userVmDao.findById(vmId);
 
         if (userVm == null || (!userVm.isDisplayVm() && caller.getType() == Account.ACCOUNT_TYPE_NORMAL)) {
-                InvalidParameterValueException ex = new InvalidParameterValueException("Virtual mahine id does not exist");
-            ex.addProxyObject(Long.valueOf(vmId).toString(), "vmId");
-                throw ex;
+            throwInvalidIdException("Virtual machine id does not exist", Long.valueOf(vmId).toString(), "vmId");
             }
 
         _accountMgr.checkAccess(caller, null, true, userVm);
@@ -4171,9 +4419,7 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         UserVmVO  userVm = _userVmDao.findById(vmId);
 
         if (userVm == null || (!userVm.isDisplayVm() && caller.getType() == Account.ACCOUNT_TYPE_NORMAL)) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Virtual mahine id does not exist");
-            ex.addProxyObject(Long.valueOf(vmId).toString(), "vmId");
-            throw ex;
+            throwInvalidIdException("Virtual machine id does not exist", Long.valueOf(vmId).toString(), "vmId");
         }
 
         _accountMgr.checkAccess(caller, null, true, userVm);
diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
index a7791c3..445aaef 100644
--- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
@@ -867,6 +867,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
 
         // verify permissions
         _accountMgr.checkAccess(ctx.getCallingAccount(), null, false, vpc);
+        _resourceTagDao.removeByIdAndType(vpcId, ResourceObjectType.Vpc);
 
         return destroyVpc(vpc, ctx.getCallingAccount(), ctx.getCallingUserId());
     }
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 6062820..177342b 100644
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -125,6 +125,8 @@ import org.apache.cloudstack.api.command.admin.network.ListNetworksCmdByAdmin;
 import org.apache.cloudstack.api.command.admin.network.ListPhysicalNetworksCmd;
 import org.apache.cloudstack.api.command.admin.network.ListStorageNetworkIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.network.ListSupportedNetworkServicesCmd;
+import org.apache.cloudstack.api.command.admin.network.MigrateNetworkCmd;
+import org.apache.cloudstack.api.command.admin.network.MigrateVPCCmd;
 import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedGuestVlanRangeCmd;
 import org.apache.cloudstack.api.command.admin.network.UpdateNetworkCmdByAdmin;
 import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
@@ -3012,6 +3014,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(UpdateLBHealthCheckPolicyCmd.class);
         cmdList.add(GetUploadParamsForTemplateCmd.class);
         cmdList.add(GetUploadParamsForVolumeCmd.class);
+        cmdList.add(MigrateNetworkCmd.class);
+        cmdList.add(MigrateVPCCmd.class);
         cmdList.add(AcquirePodIpCmdByAdmin.class);
         cmdList.add(ReleasePodIpCmdByAdmin.class);
         cmdList.add(CreateManagementNetworkIpRangeCmd.class);
diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
index 08ed3dd..7528d68 100644
--- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
+++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
@@ -24,6 +24,8 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.network.vpc.VpcOfferingVO;
+import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.storage.SnapshotPolicyVO;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -127,7 +129,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
         s_typeMap.put(ResourceObjectType.LBStickinessPolicy, LBStickinessPolicyVO.class);
         s_typeMap.put(ResourceObjectType.LBHealthCheckPolicy, LBHealthCheckPolicyVO.class);
         s_typeMap.put(ResourceObjectType.SnapshotPolicy, SnapshotPolicyVO.class);
-
+        s_typeMap.put(ResourceObjectType.NetworkOffering, NetworkOfferingVO.class);
+        s_typeMap.put(ResourceObjectType.VpcOffering, VpcOfferingVO.class);
     }
 
     @Inject
diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
index 81f06bc..cdf7180 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -24,6 +24,9 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.api.command.admin.address.ReleasePodIpCmdByAdmin;
 import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
@@ -35,8 +38,6 @@ import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
 import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
 import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
 
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.deploy.DeployDestination;
@@ -68,6 +69,7 @@ import com.cloud.network.element.StaticNatServiceProvider;
 import com.cloud.network.element.UserDataServiceProvider;
 import com.cloud.network.guru.NetworkGuru;
 import com.cloud.network.rules.LoadBalancerContainer.Scheme;
+import com.cloud.network.vpc.Vpc;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.user.Account;
@@ -256,9 +258,18 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
         return null;
     }
 
+    @Override
+    public Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume) {
+        return null;
+    }
+
+    @Override public Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map<String, String> networkToOffering, Account account, User callerUser, boolean resume) {
+        return null;
+    }
+
     /* (non-Javadoc)
-     * @see com.cloud.network.NetworkService#createPhysicalNetwork(java.lang.Long, java.lang.String, java.lang.String, java.util.List, java.lang.String, java.lang.Long, java.util.List, java.lang.String)
-     */
+             * @see com.cloud.network.NetworkService#createPhysicalNetwork(java.lang.Long, java.lang.String, java.lang.String, java.util.List, java.lang.String, java.lang.Long, java.util.List, java.lang.String)
+             */
     @Override
     public PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List<String> isolationMethods, String broadcastDomainRange,
         Long domainId, List<String> tags, String name) {
@@ -899,6 +910,10 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
         return 0;
     }
 
+    @Override public List<NetworkGuru> getNetworkGurus() {
+        return null;
+    }
+
     @Override
     public void finalizeUpdateInSequence(Network network, boolean success) {
         return;
diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py
index 121921b..aaeb97a 100644
--- a/test/integration/plugins/nuagevsp/nuageTestCase.py
+++ b/test/integration/plugins/nuagevsp/nuageTestCase.py
@@ -35,6 +35,7 @@ from marvin.lib.base import (Domain,
                              Router,
                              ServiceOffering,
                              StaticNATRule,
+                             ResourceDetails,
                              VirtualMachine,
                              VPC,
                              VpcOffering,
@@ -42,15 +43,16 @@ from marvin.lib.base import (Domain,
 from marvin.lib.common import (get_domain,
                                get_template,
                                get_zone)
-from marvin.cloudstackAPI import restartVPC, listNuageUnderlayVlanIpRanges
+from marvin.cloudstackAPI import (restartVPC,
+                                  listNuageUnderlayVlanIpRanges)
 # Import System Modules
+from retry import retry
 import importlib
 import functools
 import logging
 import socket
-import sys
 import time
-from retry import retry
+import sys
 from nuage_vsp_statistics import VsdDataCollector
 
 
@@ -112,6 +114,7 @@ class nuageTestCase(cloudstackTestCase):
     @classmethod
     def setUpClass(cls):
         cls.debug("setUpClass nuageTestCase")
+        cls._cleanup = []
 
         # We want to fail quicker, if it's a failure
         socket.setdefaulttimeout(60)
@@ -139,8 +142,7 @@ class nuageTestCase(cloudstackTestCase):
             cls.api_client,
             cls.test_data["service_offering"]
         )
-        cls._cleanup = [cls.service_offering]
-
+        cls._cleanup.append(cls.service_offering)
         cls.debug("setUpClass nuageTestCase [DONE]")
 
     @classmethod
@@ -385,7 +387,7 @@ class nuageTestCase(cloudstackTestCase):
     @needscleanup
     def create_Network(cls, nw_off, gateway="10.1.1.1",
                        netmask="255.255.255.0", vpc=None, acl_list=None,
-                       testdata=None, account=None):
+                       testdata=None, account=None, vlan=None):
         if not account:
             account = cls.account
         cls.debug("Creating a network in the account - %s" % account.name)
@@ -401,6 +403,7 @@ class nuageTestCase(cloudstackTestCase):
                                  networkofferingid=nw_off.id,
                                  zoneid=cls.zone.id,
                                  gateway=gateway,
+                                 vlan=vlan,
                                  vpcid=vpc.id if vpc else cls.vpc.id
                                  if hasattr(cls, "vpc") else None,
                                  aclid=acl_list.id if acl_list else None
@@ -987,6 +990,23 @@ class nuageTestCase(cloudstackTestCase):
         self.debug("Successfully verified the creation and state of Network "
                    "- %s in VSD" % network.name)
 
+    def verify_vsd_network_not_present(self, network, vpc=None):
+        self.debug("Verifying the creation and state of Network - %s in VSD" %
+                   network.name)
+        ext_network_filter = self.get_externalID_filter(vpc.id) if vpc \
+            else self.get_externalID_filter(network.id)
+
+        vsd_domain = self.vsd.get_domain(filter=ext_network_filter)
+        if vsd_domain is None:
+            return
+
+        vsd_zone = self.vsd.get_zone(filter=ext_network_filter)
+        if vsd_zone is None:
+            return
+        vsd_subnet = self.vsd.get_subnet(
+            filter=self.get_externalID_filter(network.id))
+        self.assertEqual(vsd_subnet, None, "Network is present on the vsd.")
+
     # get_subnet_id - Calculates and returns the subnet ID in VSD with the
     # given CloudStack network ID and subnet gateway
     def get_subnet_id(self, network_id, gateway):
@@ -1300,3 +1320,21 @@ class nuageTestCase(cloudstackTestCase):
         self.debug("Successfully verified the creation and state of Network "
                    "Firewall (Ingress/Egress ACL) rule with ID - %s in VSD" %
                    firewall_rule.id)
+
+    def add_resource_tag(self, resource_id, resource_type, key, value,
+                         fordisplay=False):
+        details = {key: value}
+        return ResourceDetails.create(self.api_client, resourceid=resource_id,
+                                      resourcetype=resource_type,
+                                      details=details, fordisplay=fordisplay)
+
+    def list_resource_tag(self, resource_id, resource_type, key,
+                          fordisplay=False):
+        return ResourceDetails.list(self.api_client, resourceid=resource_id,
+                                    resourcetype=resource_type, key=key,
+                                    fordisplay=fordisplay)
+
+    def delete_resource_tag(self, resource_id, resource_type):
+        return ResourceDetails.delete(self.api_client,
+                                      resourceid=resource_id,
+                                      resourcetype=resource_type)
diff --git a/test/integration/plugins/nuagevsp/nuage_test_data.py b/test/integration/plugins/nuagevsp/nuage_test_data.py
index 7f3f3a2..691e103 100644
--- a/test/integration/plugins/nuagevsp/nuage_test_data.py
+++ b/test/integration/plugins/nuagevsp/nuage_test_data.py
@@ -1,4 +1,4 @@
-#t	 Licensed to the Apache Software Foundation (ASF) under one
+# Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
 # regarding copyright ownership.  The ASF licenses this file
diff --git a/test/integration/plugins/nuagevsp/test_nuage_extra_dhcp.py b/test/integration/plugins/nuagevsp/test_nuage_extra_dhcp.py
index cc52e66..cabba0c 100644
--- a/test/integration/plugins/nuagevsp/test_nuage_extra_dhcp.py
+++ b/test/integration/plugins/nuagevsp/test_nuage_extra_dhcp.py
@@ -1241,7 +1241,8 @@ class TestNuageExtraDhcp(nuageTestCase):
 
         for number in options_to_verify:
             vm1 = self.when_i_create_a_vm(
-                isolated_network2, None, "vm1", dhcp_options=None, is_shared_network=False)
+                isolated_network2, None, "vm1", dhcp_options=None,
+                is_shared_network=False)
             result = self.when_i_add_an_extra_nic_to_a_vm(vm1, network, None)
             dhcp_options_network = self.get_extra_dhcp_options_starting_with(
                 number, network)
diff --git a/test/integration/plugins/nuagevsp/test_nuage_internal_dns.py b/test/integration/plugins/nuagevsp/test_nuage_internal_dns.py
index 1e774a3..b0026d7 100644
--- a/test/integration/plugins/nuagevsp/test_nuage_internal_dns.py
+++ b/test/integration/plugins/nuagevsp/test_nuage_internal_dns.py
@@ -23,6 +23,7 @@ from marvin.cloudstackAPI import updateZone
 from marvin.lib.base import Account, Network
 # Import System Modules
 from nose.plugins.attrib import attr
+import time
 
 
 class TestNuageInternalDns(nuageTestCase):
@@ -293,6 +294,7 @@ class TestNuageInternalDns(nuageTestCase):
         except Exception as e:
             self.fail("SSH into VM failed with exception %s" % e)
 
+        time.sleep(30)
         cmd = 'ping -c 2 vm2'
         self.debug("ping vm2 by hostname with command: " + cmd)
         outputlist = ssh.execute(cmd)
diff --git a/test/integration/plugins/nuagevsp/test_nuage_network_migration.py b/test/integration/plugins/nuagevsp/test_nuage_network_migration.py
new file mode 100644
index 0000000..d346a9a
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/test_nuage_network_migration.py
@@ -0,0 +1,2002 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+""" Network migration test with Nuage VSP SDN plugin
+"""
+# Import Local Modules
+from nuageTestCase import nuageTestCase
+from marvin.lib.base import (Account, Host)
+from marvin.lib.utils import is_server_ssh_ready
+from marvin.cloudstackAPI import updateZone
+
+# Import System Modules
+from nose.plugins.attrib import attr
+import time
+import base64
+import unittest
+import re
+
+
+class TestNuageMigration(nuageTestCase):
+    """Test Native to Nuage Migration
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestNuageMigration, cls).setUpClass()
+
+        if not hasattr(cls.vsp_physical_network, "tags") \
+                or cls.vsp_physical_network.tags != 'nuage':
+            raise unittest.SkipTest("Require migrateACS configuration - skip")
+
+        # create a native vpc offering
+        cls.native_vpc_offering = cls.create_VpcOffering(cls.test_data
+                                                         ["vpc_offering"])
+        # create a nuage vpc offering
+        cls.nuage_vpc_offering = \
+            cls.create_VpcOffering(cls.test_data["nuagevsp"]["vpc_offering"])
+
+        # tier network offerings
+        cls.nuage_vpc_network_offering = \
+            cls.create_NetworkOffering(cls.test_data["nuagevsp"]
+                                       ["vpc_network_offering"])
+        cls.native_vpc_network_offering = \
+            cls.create_NetworkOffering(cls.test_data
+                                       ["nw_offering_isolated_vpc"])
+
+        # create a Nuage isolated network offering with vr
+        cls.nuage_isolated_network_offering = cls.create_NetworkOffering(
+            cls.test_data["nuagevsp"]["isolated_network_offering"], True)
+
+        # create a Nuage isolated network offering with vr and persistent
+        cls.nuage_isolated_network_offering_persistent = \
+            cls.create_NetworkOffering(
+                cls.test_data["nuagevsp"]
+                ["isolated_network_offering_persistent"],
+                True)
+
+        # create a Nuage isolated network offering without vr
+        cls.nuage_isolated_network_offering_without_vr = \
+            cls.create_NetworkOffering(
+                cls.test_data["nuagevsp"]
+                ["isolated_network_offering_without_vr"],
+                True)
+
+        # create a Nuage isolated network offering without vr but persistent
+        cls.nuage_isolated_network_offering_without_vr_persistent = \
+            cls.create_NetworkOffering(
+                cls.test_data["nuagevsp"]
+                ["isolated_network_offering_without_vr_persistent"],
+                True)
+
+        # create a native isolated network offering
+        cls.native_isolated_network_offering = cls.create_NetworkOffering(
+            cls.test_data["isolated_network_offering"], True)
+
+        # create a native persistent isolated network offering
+        cls.native_isolated_network_offering_persistent = \
+            cls.create_NetworkOffering(
+                cls.test_data["nw_off_isolated_persistent"], True)
+
+        # create a native persistent staticNat isolated network offering
+        cls.native_isolated_network_staticnat_offering_persistent = \
+            cls.create_NetworkOffering(
+                cls.test_data["isolated_staticnat_network_offering"], True)
+
+        # create a Native shared network offering
+        cls.native_shared_network_offering = cls.create_NetworkOffering(
+            cls.test_data["shared_network_offering"], False)
+
+        # create a Nuage shared network offering
+        cls.nuage_shared_network_offering = cls.create_NetworkOffering(
+            cls.test_data["nuagevsp"]["shared_nuage_network_offering"],
+            False)
+
+        cls._cleanup = [
+            cls.nuage_isolated_network_offering,
+            cls.nuage_isolated_network_offering_persistent,
+            cls.nuage_isolated_network_offering_without_vr,
+            cls.nuage_isolated_network_offering_without_vr_persistent,
+            cls.native_isolated_network_offering,
+            cls.native_isolated_network_offering_persistent,
+            cls.native_vpc_offering,
+            cls.nuage_vpc_offering,
+            cls.nuage_vpc_network_offering,
+            cls.native_vpc_network_offering,
+            cls.native_shared_network_offering,
+            cls.nuage_shared_network_offering
+        ]
+        return
+
+    def setUp(self):
+        # Create an account
+        self.account = Account.create(self.api_client,
+                                      self.test_data["account"],
+                                      admin=True,
+                                      domainid=self.domain.id
+                                      )
+        self.cleanup = [self.account]
+        return
+
+    def migrate_network(self, nw_off, network, resume=False):
+        return network.migrate(self.api_client, nw_off.id, resume)
+
+    def migrate_vpc(self, vpc, vpc_offering,
+                    network_offering_map, resume=False):
+        return vpc.migrate(self.api_client,
+                           vpc_offering.id,
+                           network_offering_map, resume)
+
+    def verify_pingtovmipaddress(self, ssh, pingtovmipaddress):
+        """verify ping to ipaddress of the vm and retry 3 times"""
+        successfull_ping = False
+        nbr_retries = 0
+        max_retries = 5
+        cmd = 'ping -c 2 ' + pingtovmipaddress
+
+        while not successfull_ping and nbr_retries < max_retries:
+            self.debug("ping vm by ipaddress with command: " + cmd)
+            outputlist = ssh.execute(cmd)
+            self.debug("command is executed properly " + cmd)
+            completeoutput = str(outputlist).strip('[]')
+            self.debug("complete output is " + completeoutput)
+            if '2 received' in completeoutput:
+                self.debug("PASS as vm is pingeable: " + completeoutput)
+                successfull_ping = True
+            else:
+                self.debug("FAIL as vm is not pingeable: " + completeoutput)
+                time.sleep(3)
+                nbr_retries = nbr_retries + 1
+
+        if not successfull_ping:
+            self.fail("FAILED TEST as excepted value not found in vm")
+
+    def verify_pingtovmhostname(self, ssh, pingtovmhostname):
+        """verify ping to hostname of the vm and retry 3 times"""
+        successfull_ping = False
+        nbr_retries = 0
+        max_retries = 5
+        cmd = 'ping -c 2 ' + pingtovmhostname
+
+        while not successfull_ping and nbr_retries < max_retries:
+            self.debug("ping vm by hostname with command: " + cmd)
+            outputlist = ssh.execute(cmd)
+            self.debug("command is executed properly " + cmd)
+            completeoutput = str(outputlist).strip('[]')
+            self.debug("complete output is " + completeoutput)
+            if '2 received' in completeoutput:
+                self.debug("PASS as vm is pingeable: " + completeoutput)
+                successfull_ping = True
+            else:
+                self.debug("FAIL as vm is not pingeable: " + completeoutput)
+                time.sleep(3)
+                nbr_retries = nbr_retries + 1
+
+        if not successfull_ping:
+            self.fail("FAILED TEST as excepted value not found in vm")
+
+    def update_userdata(self, vm, expected_user_data):
+        updated_user_data = base64.b64encode(expected_user_data)
+        vm.update(self.api_client, userdata=updated_user_data)
+        return expected_user_data
+
+    def get_userdata_url(self, vm):
+        self.debug("Getting user data url")
+        nic = vm.nic[0]
+        gateway = str(nic.gateway)
+        self.debug("Gateway: " + gateway)
+        user_data_url = 'curl "http://' + gateway + ':80/latest/user-data"'
+        return user_data_url
+
+    def define_cloudstack_managementip(self):
+        # get cloudstack managementips from cfg file
+        config = self.getClsConfig()
+        return [config.mgtSvr[0].mgtSvrIp, config.mgtSvr[1].mgtSvrIp]
+
+    def cloudstack_connection_vsd(self, connection="up",
+                                  cscip=["csc-1", "csc-2"]):
+        self.debug("SSH into cloudstack management server(s), setting "
+                   "connection to VSD as %s " % connection)
+        try:
+            for ip in cscip:
+                csc_ssh_client = is_server_ssh_ready(
+                        ipaddress=ip,
+                        port=22,
+                        username="root",
+                        password="tigris",
+                        retries=2
+                )
+                self.debug("SSH is successful for cloudstack management "
+                           "server with IP %s" % ip)
+                if connection == "down":
+                    cmd = "iptables -A OUTPUT -p tcp --dport 8443 -j DROP"
+                else:
+                    cmd = "iptables -D OUTPUT -p tcp --dport 8443 -j DROP"
+                self.execute_cmd(csc_ssh_client, cmd)
+        except Exception as e:
+            self.debug("Setting cloudstack management server(s) connection %s "
+                       "to VSD fails with exception %s" % (connection, e))
+
+    def verify_cloudstack_host_state_up(self, state):
+        nbr_retries = 0
+        max_retries = 30
+        self.debug("Verify state by list hosts type=L2Networking")
+        result = Host.list(self.api_client, type="L2Networking")
+        while result[0].state != state and nbr_retries < max_retries:
+            time.sleep(5)
+            result = Host.list(self.api_client, type="L2Networking")
+            nbr_retries = nbr_retries + 1
+
+        if nbr_retries == max_retries:
+            self.debug("TIMEOUT - state of list hosts unchanged")
+
+    def verifymigrationerrortext(self, errortext, expectstr):
+        if expectstr in errortext:
+            self.debug("Migrate_network fails with expected errortext %s",
+                       errortext)
+        else:
+            self.fail("Migrate_network fails but test expects "
+                      "other errortext %s", expectstr)
+
+    @attr(tags=["migrateACS", "novms"],
+          required_hardware="false")
+    def test_01_native_to_nuage_network_migration_novms(self):
+        """
+        Verify Migration for an isolated network without VMs
+        1. create multiple native non-persistent isolated network
+        2. move to nuage non-persistent isolated network
+        3. move to native persistent network, check VR state
+        4. move to nuage persistent network, check VR state
+        """
+        isolated_network = self.create_Network(
+            self.native_isolated_network_offering, gateway="10.0.0.1",
+            netmask="255.255.255.0")
+
+        isolated_network2 = self.create_Network(
+            self.native_isolated_network_offering, gateway="10.1.0.1",
+            netmask="255.255.255.0")
+
+        shared_network = self.create_Network(
+            self.native_shared_network_offering, gateway="10.3.0.1",
+            netmask="255.255.255.0", vlan=1201)
+
+        try:
+            self.migrate_network(
+                    self.nuage_shared_network_offering,
+                    shared_network, resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "NetworkOfferingId can be upgraded only for the " \
+                    "network of type Isolated"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        try:
+            self.migrate_network(
+                    self.nuage_shared_network_offering,
+                    isolated_network, resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Can't upgrade from network offering"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        self.nuage_isolated_network_offering.update(self.api_client,
+                                                    state="Disabled")
+        self.validate_NetworkOffering(
+                self.nuage_isolated_network_offering, state="Disabled")
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering,
+                    isolated_network, resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate network as the specified network " \
+                    "offering is not enabled."
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        self.nuage_isolated_network_offering.update(self.api_client,
+                                                    state="Enabled")
+        self.validate_NetworkOffering(
+                self.nuage_isolated_network_offering, state="Enabled")
+
+        self.migrate_network(
+            self.nuage_isolated_network_offering, isolated_network,
+            resume=True)
+
+        self.verify_vsd_network_not_present(isolated_network, None)
+
+        self.migrate_network(
+            self.native_isolated_network_offering_persistent, isolated_network)
+        self.verify_vsd_network_not_present(isolated_network, None)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        try:
+            self.migrate_network(
+                    self.nuage_vpc_offering, isolated_network, resume=False)
+        except Exception as e:
+            self.debug("Migration fails with %s" % e)
+
+        try:
+            self.migrate_network(
+                    self.nuage_vpc_network_offering, isolated_network,
+                    resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate network as the specified network " \
+                    "offering is a VPC offering"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        self.migrate_network(
+             self.nuage_isolated_network_offering_persistent, isolated_network)
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+        self.verify_vsd_router(vr)
+        with self.assertRaises(Exception):
+            self.verify_vsd_network(self.domain.id, isolated_network2, None)
+
+        self.add_resource_tag(
+                self.native_isolated_network_offering_persistent.id,
+                "NetworkOffering", "RelatedNetworkOffering",
+                self.native_isolated_network_offering.id)
+        result = self.list_resource_tag(
+                self.native_isolated_network_offering_persistent.id,
+                "NetworkOffering", "RelatedNetworkOffering")
+        if result[0].value != self.native_isolated_network_offering.id:
+            self.fail("Listed resource value does not match with stored"
+                      " resource value!")
+        self.delete_resource_tag(
+                self.native_isolated_network_offering_persistent.id,
+                "NetworkOffering")
+        empty = self.list_resource_tag(
+                self.native_isolated_network_offering_persistent.id,
+                "NetworkOffering", "RelatedNetworkOffering")
+        if empty:
+            self.fail("clean up of resource values did was not successful!")
+
+    @attr(tags=["migrateACS", "stoppedvms"],
+          required_hardware="false")
+    def test_02_native_to_nuage_network_migration_stoppedvms(self):
+        """
+        Verify Migration for an isolated network with stopped VMs
+        1. create multiple native non-persistent isolated network
+        2. deploy vm and stop vm
+        3. move to nuage non-persistent isolated network
+        4. deploy vm and stop vm
+        5. move to native persistent network, check VR state
+        6. deploy vm and stop vm
+        7. move to nuage persistent network, check VR state
+        """
+
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering, gateway="10.0.0.1",
+                netmask="255.255.255.0")
+
+        vm_1 = self.create_VM(isolated_network)
+        vm_1.stop(self.api_client)
+
+        self.migrate_network(
+            self.nuage_isolated_network_offering, isolated_network)
+
+        vm_1.delete(self.api_client, expunge=True)
+        vm_2 = self.create_VM(isolated_network)
+        vm_2.stop(self.api_client)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+
+        self.migrate_network(
+            self.native_isolated_network_offering_persistent, isolated_network)
+
+        self.verify_vsd_network_not_present(isolated_network, None)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        vm_2.delete(self.api_client, expunge=True)
+        vm_3 = self.create_VM(isolated_network)
+        vm_3.stop(self.api_client)
+
+        self.migrate_network(
+            self.nuage_isolated_network_offering_persistent, isolated_network)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+        vr2 = self.get_Router(isolated_network)
+        self.check_Router_state(vr2, "Running")
+        self.verify_vsd_router(vr2)
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+
+    @attr(tags=["migrateACS", "nonpersist"],
+          required_hardware="false")
+    def test_03_migrate_native_nonpersistent_network_to_nuage_traffic(self):
+        """
+        Verify traffic after Migration of a non-persistent isolated network
+        1. create native non-persistent isolated network
+        2. move to nuage non-persistent isolated network
+        3. Spin VM's and verify traffic provided by Nuage
+        """
+        for i in range(1, 3):
+            isolated_network = self.create_Network(
+                    self.native_isolated_network_offering, gateway="10.1.0.1",
+                    netmask="255.255.255.0", account=self.account)
+
+            try:
+                self.migrate_network(
+                    self.nuage_vpc_network_offering,
+                    isolated_network, resume=False)
+            except Exception as e:
+                errortext = re.search(".*errortext\s*:\s*u?'([^']+)'.*",
+                                      e.message).group(1)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "Failed to migrate network as the specified network " \
+                        "offering is a VPC offering"
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr,
+                    isolated_network, resume=True)
+
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr,
+                    isolated_network, resume=False)
+
+            self.verify_vsd_network_not_present(isolated_network, None)
+
+            self.debug("Deploying a VM in the created Isolated network...")
+            vm_1 = self.create_VM(isolated_network)
+            self.validate_Network(isolated_network, state="Implemented")
+            self.check_VM_state(vm_1, state="Running")
+            vm_2 = self.create_VM(isolated_network)
+            self.check_VM_state(vm_2, state="Running")
+
+            # VSD verification
+            self.verify_vsd_network(self.domain.id, isolated_network)
+            # self.verify_vsd_router(vr_1)
+            self.verify_vsd_vm(vm_1)
+            self.verify_vsd_vm(vm_2)
+
+            # Creating Static NAT rule
+            self.debug("Creating Static NAT rule for the deployed VM in the "
+                       "created Isolated network...")
+            public_ip = self.acquire_PublicIPAddress(isolated_network)
+            self.validate_PublicIPAddress(public_ip, isolated_network)
+            self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+            self.validate_PublicIPAddress(
+                    public_ip, isolated_network, static_nat=True, vm=vm_1)
+            fw_rule = self.create_FirewallRule(
+                    public_ip, self.test_data["ingress_rule"])
+
+            # VSD verification for Static NAT functionality
+            self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                        public_ip.ipaddress)
+            self.verify_vsd_firewall_rule(fw_rule)
+
+            # Ssh into the VM via floating ip
+            vm_public_ip = public_ip.ipaddress.ipaddress
+            try:
+                vm_1.ssh_ip = vm_public_ip
+                vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+                vm_1.username = self.test_data["virtual_machine"]["username"]
+                vm_1.password = self.test_data["virtual_machine"]["password"]
+                self.debug("SSHing into VM: %s with %s" %
+                           (vm_1.ssh_ip, vm_1.password))
+
+                ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip)
+
+            except Exception as e:
+                self.fail("SSH into VM failed with exception %s" % e)
+
+            self.verify_pingtovmipaddress(ssh, vm_2.ipaddress)
+
+            vm_1.delete(self.api_client, expunge=True)
+            vm_2.delete(self.api_client, expunge=True)
+            isolated_network.delete(self.api_client)
+            self.debug("Number of loops %s" % i)
+
+    @attr(tags=["migrateACS", "persist"],
+          required_hardware="false")
+    def test_04_migrate_native_persistentnetwork_to_nuage_traffic(self):
+        """
+        Verify traffic after Migration of a persistent isolated network
+        1. create native persistent isolated network
+        2. move to nuage persistent isolated network without VR
+        3. Spin VM's and verify traffic provided by Nuage
+        """
+        for i in range(1, 3):
+            isolated_network = self.create_Network(
+                self.native_isolated_network_offering_persistent,
+                gateway="10.2.0.1",
+                netmask="255.255.255.0", account=self.account)
+            self.verify_vsd_network_not_present(isolated_network, None)
+            vr = self.get_Router(isolated_network)
+            self.check_Router_state(vr, "Running")
+
+            csc_ips = self.define_cloudstack_managementip()
+            self.cloudstack_connection_vsd(connection="down", cscip=csc_ips)
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.debug("Migrate_network fails if connection ACS VSD is down")
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.verify_cloudstack_host_state_up("Alert")
+            try:
+                self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr_persistent,
+                    isolated_network, resume=False)
+            except Exception as e:
+                errortext = re.search(".*errortext\s*:\s*u?'([^']+)'.*",
+                                      e.message).group(1)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "Failed to implement network (with specified id) " \
+                        "elements and resources as a part of network update"
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            self.cloudstack_connection_vsd(connection="up", cscip=csc_ips)
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.debug("Migrate_network resumes if connection ACS VSD is up")
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.verify_cloudstack_host_state_up("Up")
+            try:
+                self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr_persistent,
+                    isolated_network, resume=False)
+            except Exception as e:
+                errortext = \
+                    re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                              e.message).group(2)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "Failed to migrate network as previous migration " \
+                        "left this network in transient condition. " \
+                        "Specify resume as true."
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr_persistent,
+                isolated_network, resume=True)
+
+            self.verify_vsd_network(self.domain.id, isolated_network, None)
+            with self.assertRaises(Exception):
+                self.get_Router(isolated_network)
+            self.debug("Deploying a VM in the created Isolated network...")
+            vm_1 = self.create_VM(isolated_network)
+            self.validate_Network(isolated_network, state="Implemented")
+            with self.assertRaises(Exception):
+                self.get_Router(isolated_network)
+            self.check_VM_state(vm_1, state="Running")
+            vm_2 = self.create_VM(isolated_network)
+            self.check_VM_state(vm_2, state="Running")
+
+            # VSD verification
+            self.verify_vsd_network(self.domain.id, isolated_network)
+            self.verify_vsd_vm(vm_1)
+            self.verify_vsd_vm(vm_2)
+
+            # Creating Static NAT rule
+            self.debug("Creating Static NAT rule for the deployed VM in the "
+                       "created Isolated network...")
+            public_ip = self.acquire_PublicIPAddress(isolated_network)
+            self.validate_PublicIPAddress(public_ip, isolated_network)
+            self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+            self.validate_PublicIPAddress(
+                    public_ip, isolated_network, static_nat=True, vm=vm_1)
+            fw_rule = self.create_FirewallRule(
+                    public_ip, self.test_data["ingress_rule"])
+
+            # VSD verification for Static NAT functionality
+            self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                        public_ip.ipaddress)
+            self.verify_vsd_firewall_rule(fw_rule)
+
+            # Ssh into the VM via floating ip
+            vm_public_ip = public_ip.ipaddress.ipaddress
+            try:
+                vm_1.ssh_ip = vm_public_ip
+                vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+                vm_1.username = self.test_data["virtual_machine"]["username"]
+                vm_1.password = self.test_data["virtual_machine"]["password"]
+                self.debug("SSHing into VM: %s with %s" %
+                           (vm_1.ssh_ip, vm_1.password))
+
+                ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip)
+
+            except Exception as e:
+                self.fail("SSH into VM failed with exception %s" % e)
+
+            self.verify_pingtovmipaddress(ssh, vm_2.ipaddress)
+
+            vm_1.delete(self.api_client, expunge=True)
+            vm_2.delete(self.api_client, expunge=True)
+            isolated_network.delete(self.api_client)
+            self.debug("Number of loops %s" % i)
+
+    @attr(tags=["migrateACS", "nicmigration"],
+          required_hardware="false")
+    def test_05_native_to_nuage_nic_migration(self):
+        """
+        Verify Nic migration of GuestVm in an isolated network
+        1. create multiple native non-persistent isolated network
+        2. populate network with 2 vm's
+        3. enable static nat + create FW rule
+        4. move to nuage non-persistent isolated network, check:
+            - public ip
+            - FW rules
+            - VR
+            - VM's
+        """
+        isolated_network = self.create_Network(
+            self.native_isolated_network_offering, gateway="10.0.0.1",
+            netmask="255.255.255.0")
+
+        isolated_network2 = self.create_Network(
+            self.native_isolated_network_offering, gateway="10.1.0.1",
+            netmask="255.255.255.0")
+
+        vm1 = self.create_VM(isolated_network)
+        public_ip = self.acquire_PublicIPAddress(isolated_network)
+        self.create_StaticNatRule_For_VM(vm1, public_ip, isolated_network)
+        firewall_rule = self.create_FirewallRule(public_ip)
+
+        vm2 = self.create_VM(isolated_network)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        self.migrate_network(
+            self.nuage_isolated_network_offering, isolated_network)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+        self.verify_vsd_vm(vm1)
+        self.verify_vsd_floating_ip(isolated_network, vm1, public_ip.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule)
+        self.verify_vsd_vm(vm2)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+        self.verify_vsd_router(vr)
+        with self.assertRaises(Exception):
+            self.verify_vsd_network(self.domain.id, isolated_network2, None)
+
+    @attr(tags=["migrateACS", "nonpersistnic"],
+          required_hardware="false")
+    def test_06_migrate_native_nonpersistent_nic_to_nuage_traffic(self):
+        """
+        Verify Nic migration of GuestVm in a non-persistent isolated network
+        1. create two native non-persistent isolated networks
+        2. Deploy 2 vm's in first network
+        3. enable static nat + create FW rule
+        4. move first network to nuage non-persistent isolated network,
+            check:
+                - public ip
+                - FW rules
+                - VR
+                - VM's
+        5. Destroy and expunge 1 VM in first network
+        6. Deploy a new VM in first network and check traffic
+        7. Move second network to nuage non-persistent isolated network,
+            check:
+                - public ip
+                - FW rules
+                - VR
+                - VM's
+        8. Deploy 2 vm in second network , move it and check
+        9. Cleanup
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering, gateway="10.3.0.1",
+                netmask="255.255.255.0")
+
+        isolated_network2 = self.create_Network(
+                self.native_isolated_network_offering, gateway="10.4.0.1",
+                netmask="255.255.255.0")
+
+        vm_1 = self.create_VM(isolated_network)
+        public_ip = self.acquire_PublicIPAddress(isolated_network)
+        self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+        firewall_rule = self.create_FirewallRule(public_ip)
+
+        vm_2 = self.create_VM(isolated_network)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering, isolated_network)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+        self.verify_vsd_vm(vm_1)
+        self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                    public_ip.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule)
+        self.verify_vsd_vm(vm_2)
+        vr_3 = self.get_Router(isolated_network)
+        self.check_Router_state(vr_3, "Running")
+        self.verify_vsd_router(vr_3)
+
+        # VSD verification for Static NAT functionality
+        self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                    public_ip.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip = public_ip.ipaddress.ipaddress
+        try:
+            vm_1.ssh_ip = vm_public_ip
+            vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_1.username = self.test_data["virtual_machine"]["username"]
+            vm_1.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_1.ssh_ip, vm_1.password))
+
+            ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        self.verify_pingtovmipaddress(ssh, vm_2.ipaddress)
+
+        vm_2.delete(self.api_client, expunge=True)
+        with self.assertRaises(Exception):
+            self.verify_vsd_vm(vm_2)
+        vm_4 = self.create_VM(isolated_network)
+        self.verify_vsd_vm(vm_4)
+        with self.assertRaises(Exception):
+            self.verify_vsd_network(self.domain.id, isolated_network2, None)
+
+        vm_3 = self.create_VM(isolated_network2)
+        vr_2 = self.get_Router(isolated_network2)
+        self.check_Router_state(vr_2, "Running")
+
+        # Ssh into the VM via floating ip
+        vm_public_ip = public_ip.ipaddress.ipaddress
+        try:
+            vm_1.ssh_ip = vm_public_ip
+            vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_1.username = self.test_data["virtual_machine"]["username"]
+            vm_1.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_1.ssh_ip, vm_1.password))
+
+            ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        self.verify_pingtovmipaddress(ssh, vm_4.ipaddress)
+
+        vm_1.delete(self.api_client, expunge=True)
+        vm_4.delete(self.api_client, expunge=True)
+        isolated_network.delete(self.api_client)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr,
+                isolated_network2)
+
+        public_ip_2 = self.acquire_PublicIPAddress(isolated_network2)
+        self.create_StaticNatRule_For_VM(vm_3, public_ip_2, isolated_network2)
+        firewall_rule_2 = self.create_FirewallRule(public_ip_2)
+        self.verify_vsd_floating_ip(isolated_network2, vm_3,
+                                    public_ip_2.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule_2)
+
+        self.verify_vsd_network(self.domain.id, isolated_network2, None)
+        self.verify_vsd_vm(vm_3)
+        self.verify_vsd_floating_ip(isolated_network2, vm_3,
+                                    public_ip_2.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule_2)
+
+        with self.assertRaises(Exception):
+            self.get_Router(isolated_network2)
+        vm_5 = self.create_VM(isolated_network2)
+        self.verify_vsd_vm(vm_5)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+        try:
+            vm_3.ssh_ip = vm_public_ip_2
+            vm_3.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_3.username = self.test_data["virtual_machine"]["username"]
+            vm_3.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_3.ssh_ip, vm_3.password))
+
+            ssh = vm_3.get_ssh_client(ipaddress=vm_public_ip_2)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        self.verify_pingtovmipaddress(ssh, vm_5.ipaddress)
+
+    @attr(tags=["migrateACS", "persistnic"],
+          required_hardware="false")
+    def test_07_migrate_native_persistent_nic_to_nuage_traffic(self):
+        """
+        Verify Nic migration of GuestVm in a persistent isolated network
+        1. create two native persistent isolated networks
+        2. deploy 2 vm's in this network
+        3. move to nuage non-persistent isolated network,
+        4. enable static nat + create FW rule
+        check:
+            - public ip
+            - FW rules
+            - VR
+            - VM's
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering_persistent,
+                gateway="10.5.0.1",
+                netmask="255.255.255.0")
+
+        isolated_network2 = self.create_Network(
+                self.native_isolated_network_offering_persistent,
+                gateway="10.6.0.1",
+                netmask="255.255.255.0")
+
+        vm_1 = self.create_VM(isolated_network)
+        vm_2 = self.create_VM(isolated_network)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+        vm_3 = self.create_VM(isolated_network2)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr_persistent,
+                isolated_network)
+
+        public_ip = self.acquire_PublicIPAddress(isolated_network)
+        self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+        firewall_rule = self.create_FirewallRule(public_ip)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+        self.verify_vsd_vm(vm_1)
+        self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                    public_ip.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule)
+        self.verify_vsd_vm(vm_2)
+        with self.assertRaises(Exception):
+            self.get_Router(isolated_network)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip = public_ip.ipaddress.ipaddress
+        try:
+            vm_1.ssh_ip = vm_public_ip
+            vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_1.username = self.test_data["virtual_machine"]["username"]
+            vm_1.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_1.ssh_ip, vm_1.password))
+
+            ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        self.verify_pingtovmipaddress(ssh, vm_2.ipaddress)
+
+        vm_1.delete(self.api_client, expunge=True)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr_persistent,
+                isolated_network2)
+
+        vm_2.delete(self.api_client, expunge=True)
+        isolated_network.delete(self.api_client)
+
+        self.verify_vsd_network(self.domain.id, isolated_network2, None)
+        self.verify_vsd_vm(vm_3)
+        public_ip_2 = self.acquire_PublicIPAddress(isolated_network2)
+        self.create_StaticNatRule_For_VM(vm_3, public_ip_2, isolated_network2)
+        firewall_rule_2 = self.create_FirewallRule(public_ip_2)
+        vm_4 = self.create_VM(isolated_network2)
+        self.verify_vsd_floating_ip(isolated_network2, vm_3,
+                                    public_ip_2.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule_2)
+        self.verify_vsd_vm(vm_4)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+        try:
+            vm_3.ssh_ip = vm_public_ip_2
+            vm_3.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_3.username = self.test_data["virtual_machine"]["username"]
+            vm_3.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_3.ssh_ip, vm_3.password))
+
+            ssh = vm_3.get_ssh_client(ipaddress=vm_public_ip_2)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        self.verify_pingtovmipaddress(ssh, vm_4.ipaddress)
+
+    @attr(tags=["migrateACS", "isomultinic"],
+          required_hardware="false")
+    def test_08_migrate_native_multinic_to_nuage_traffic(self):
+        """
+        Verify MultiNic migration of GuestVm with multiple isolated networks
+        1. create one native non-persistent isolated network
+        2. create one native persistent isolated network
+        3. deploy 2 vm's in both these network
+        4. move non-persist to nuage non-persistent isolated network,
+        5. move persist to nuage persistent isolated network
+        6. enable static nat + create FW rule
+        check:
+            - public ip
+            - FW rules
+            - VR
+            - VM's
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering,
+                gateway="10.7.0.1",
+                netmask="255.255.255.0")
+
+        isolated_network2 = self.create_Network(
+                self.native_isolated_network_offering_persistent,
+                gateway="10.8.0.1",
+                netmask="255.255.255.0")
+
+        vm_1 = self.create_VM([isolated_network, isolated_network2])
+        vm_2 = self.create_VM([isolated_network2, isolated_network])
+        vr = self.get_Router(isolated_network2)
+        self.check_Router_state(vr, "Running")
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr,
+                isolated_network)
+
+        vm_3 = self.create_VM(isolated_network)
+
+        public_ip = self.acquire_PublicIPAddress(isolated_network)
+        self.create_StaticNatRule_For_VM(vm_3, public_ip, isolated_network)
+        firewall_rule = self.create_FirewallRule(public_ip)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+
+        self.verify_vsd_vm(vm_3)
+        self.verify_vsd_floating_ip(isolated_network, vm_3,
+                                    public_ip.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip = public_ip.ipaddress.ipaddress
+        try:
+            vm_3.ssh_ip = vm_public_ip
+            vm_3.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_3.username = self.test_data["virtual_machine"]["username"]
+            vm_3.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_3.ssh_ip, vm_3.password))
+
+            ssh = vm_3.get_ssh_client(ipaddress=vm_public_ip)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        defaultipaddress = \
+            [nic.ipaddress for nic in vm_1.nic if nic.isdefault][0]
+
+        self.verify_pingtovmipaddress(ssh, defaultipaddress)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr_persistent,
+                isolated_network2)
+
+        vm_3.delete(self.api_client, expunge=True)
+        public_ip.delete(self.api_client)
+        vm_4 = self.create_VM(isolated_network2)
+
+        public_ip_2 = self.acquire_PublicIPAddress(isolated_network2)
+        self.create_StaticNatRule_For_VM(vm_4, public_ip_2, isolated_network2)
+        firewall_rule_2 = self.create_FirewallRule(public_ip_2)
+
+        self.verify_vsd_floating_ip(isolated_network2, vm_4,
+                                    public_ip_2.ipaddress)
+        self.verify_vsd_firewall_rule(firewall_rule_2)
+        self.verify_vsd_vm(vm_4)
+
+        # Ssh into the VM via floating ip
+        vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+        try:
+            vm_4.ssh_ip = vm_public_ip_2
+            vm_4.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_4.username = self.test_data["virtual_machine"]["username"]
+            vm_4.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_4.ssh_ip, vm_4.password))
+
+            ssh = vm_4.get_ssh_client(ipaddress=vm_public_ip_2)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        defaultipaddress2 = \
+            [nic.ipaddress for nic in vm_2.nic if nic.isdefault][0]
+
+        self.verify_pingtovmipaddress(ssh, defaultipaddress2)
+
+    @attr(tags=["migrateACS", "persiststaticnat"],
+          required_hardware="false")
+    def test_09_migrate_native_persist_staticnat_to_nuage_traffic(self):
+        """
+        Verify StaticNat migration of GuestVm in a persistent isolated network
+        1. create one native persistent isolated network offering
+        2. with Dhcp,SourceNat,StaticNat,Dns,Userdata and Firewall
+        3. create one native persistent isolated network with above
+        4. deploy 2 vm's in this network
+        5. In a loop
+              enable staticnat on first vm and open port 22 for ssh
+              login to vm1 and ping vm2
+              verify userdata in Native
+              move to nuage persistent isolated network,
+              deploy 2 new vm's in this network
+              enable staticnat on new vm and open port 22 for ssh
+              check:
+               - public ips
+               - FW rules
+               - VR
+               - VM's ping old and new VM's
+               - verify userdata in Nuage
+               - Release public ips
+              move back to native persistent isolated network,
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_staticnat_offering_persistent,
+                gateway="10.9.0.1",
+                netmask="255.255.255.0", account=self.account)
+
+        vm_1 = self.create_VM(isolated_network)
+        vm_2 = self.create_VM(isolated_network)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        for i in range(1, 3):
+            self.debug("+++++Starting again as Native in Loop+++++")
+            public_ip = self.acquire_PublicIPAddress(isolated_network)
+            self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+            firewall_rule = self.create_FirewallRule(public_ip)
+
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_persistent,
+                    isolated_network)
+
+            self.verify_vsd_network(self.domain.id, isolated_network, None)
+            self.verify_vsd_vm(vm_1)
+            self.verify_vsd_floating_ip(isolated_network, vm_1,
+                                        public_ip.ipaddress)
+            self.verify_vsd_firewall_rule(firewall_rule)
+            self.verify_vsd_vm(vm_2)
+
+            vm_3 = self.create_VM(isolated_network)
+            public_ip_2 = self.acquire_PublicIPAddress(isolated_network)
+            self.create_StaticNatRule_For_VM(vm_3,
+                                             public_ip_2,
+                                             isolated_network)
+            firewall_rule_2 = self.create_FirewallRule(public_ip_2)
+            vm_4 = self.create_VM(isolated_network)
+            self.verify_vsd_floating_ip(isolated_network, vm_3,
+                                        public_ip_2.ipaddress)
+            self.verify_vsd_firewall_rule(firewall_rule_2)
+            self.verify_vsd_vm(vm_3)
+            self.verify_vsd_vm(vm_4)
+
+            # Ssh into the VM via floating ip
+            vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+            try:
+                vm_3.ssh_ip = vm_public_ip_2
+                vm_3.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+                vm_3.username = self.test_data["virtual_machine"]["username"]
+                vm_3.password = self.test_data["virtual_machine"]["password"]
+                self.debug("SSHing into VM: %s with %s" %
+                           (vm_3.ssh_ip, vm_3.password))
+
+                ssh2 = vm_3.get_ssh_client(ipaddress=vm_public_ip_2)
+
+            except Exception as e:
+                self.fail("SSH into VM failed with exception %s" % e)
+
+            self.verify_pingtovmipaddress(ssh2, vm_1.ipaddress)
+
+            self.verify_pingtovmipaddress(ssh2, vm_4.ipaddress)
+
+            self.verify_pingtovmipaddress(ssh2, vm_2.ipaddress)
+
+            self.debug("Updating the running vm_3 with new user data...")
+            expected_user_data2 = self.update_userdata(vm_3, "hellonuage vm3")
+            self.debug("SSHing into the vm_3 for verifying its user data...")
+            user_data_cmd = self.get_userdata_url(vm_3)
+            self.debug("Getting user data with command: " + user_data_cmd)
+            actual_user_data2 = self.execute_cmd(ssh2, user_data_cmd)
+            self.debug("Actual user data - " + actual_user_data2 +
+                       ", Expected user data - " + expected_user_data2)
+            self.assertEqual(actual_user_data2, expected_user_data2,
+                             "Un-expected VM (VM_3) user data")
+
+            vm_3.delete(self.api_client, expunge=True)
+            vm_4.delete(self.api_client, expunge=True)
+            public_ip_2.delete(self.api_client)
+
+            # ReleaseIP as get_ssh_client fails when migrating back to native
+            public_ip.delete(self.api_client)
+
+            self.debug("++++++++Migrating network back to native+++++++")
+            self.migrate_network(
+                    self.native_isolated_network_staticnat_offering_persistent,
+                    isolated_network)
+
+    @attr(tags=["migrateACS", "vpcnovms"],
+          required_hardware="false")
+    def test_10_migrate_native_vpc(self):
+        vpc = self.create_Vpc(self.native_vpc_offering)
+        network = self.create_Network(self.native_vpc_network_offering,
+                                      vpc=vpc)
+        self.create_VM(network)
+
+        network_offering_map = \
+            [{"networkid": network.id,
+              "networkofferingid":
+              self.nuage_isolated_network_offering_without_vr.id}]
+
+        try:
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map, resume=False)
+        except Exception as e:
+            errortext = re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                                  e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "can't be used for VPC networks"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        network_offering_map = \
+            [{"networkid": network.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id}]
+        self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                         network_offering_map)
+        self.verify_vsd_network(self.domain.id, network, vpc)
+
+    @attr(tags=["migrateACS", "vpcstaticnat"],
+          required_hardware="false")
+    def test_11_migrate_native_vpc_staticnat_to_nuage_traffic(self):
+        """
+        Verify StaticNat migration of GuestVm in a vpc network
+        1. create one native vpc network offering
+        2. create one native vpc tier network offering
+        3. with Dhcp,SourceNat,StaticNat,Dns,Userdata and NetworkACL
+        4. create one vpc with above native vpc network offering
+        5. create one native vpc tier network in above vpc
+        6. deploy 2 vm's in this tier network
+        7. In a loop
+              enable staticnat on first vm and ssh into vm
+              login to vm1 and ping vm2
+              verify userdata in Native
+              move to nuage vpc tier networkoffering,
+              deploy 2 new vm's in this network
+              enable staticnat on new vm and ssh into vm
+              check:
+               - public ips
+               - NetworkACL rules
+               - VR
+               - VM's ping old and new VM's
+               - verify userdata in Nuage
+               - Release public ips
+              move back to native vpc tier network offering,
+        """
+        cmd = updateZone.updateZoneCmd()
+        cmd.id = self.zone.id
+        cmd.domain = "vpc.com"
+        self.api_client.updateZone(cmd)
+
+        self.debug("Creating Native VSP VPC offering with Static NAT service "
+                   "provider as VPCVR...")
+        native_vpc_off = self.create_VpcOffering(
+                self.test_data["vpc_offering_native"])
+        self.validate_VpcOffering(native_vpc_off, state="Enabled")
+
+        self.debug("Creating a VPC with Static NAT service provider as "
+                   "VpcVirtualRouter")
+        vpc = self.create_Vpc(native_vpc_off, cidr='10.1.0.0/16')
+        self.validate_Vpc(vpc, state="Enabled")
+
+        self.debug("Creating native VPC Network Tier offering "
+                   "with Static NAT service provider as VPCVR")
+        native_tiernet_off = self.create_NetworkOffering(
+                self.test_data["vpc_network_offering_native"])
+        self.validate_NetworkOffering(native_tiernet_off, state="Enabled")
+
+        acl_list = self.create_NetworkAclList(
+                name="acl", description="acl", vpc=vpc)
+
+        acl_item = self.create_NetworkAclRule(
+                self.test_data["ingress_rule"], acl_list=acl_list)
+        self.create_NetworkAclRule(
+                self.test_data["icmprule"], acl_list=acl_list)
+
+        self.debug("Creating a VPC tier network with Static NAT service")
+        vpc_tier = self.create_Network(native_tiernet_off,
+                                       gateway='10.1.0.1',
+                                       vpc=vpc,
+                                       acl_list=acl_list)
+        self.validate_Network(vpc_tier, state="Implemented")
+
+        self.debug("Creating 2nd VPC tier network with Static NAT service")
+        vpc_2ndtier = self.create_Network(native_tiernet_off,
+                                          gateway='10.1.128.1',
+                                          vpc=vpc,
+                                          acl_list=acl_list)
+        self.validate_Network(vpc_2ndtier, state="Implemented")
+
+        vpc_vr = self.get_Router(vpc_tier)
+        self.check_Router_state(vpc_vr, state="Running")
+
+        self.debug("Deploying a VM in the created VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm1"
+        self.test_data["virtual_machine"]["name"] = "vpcvm1"
+        vpc_vm_1 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_1, state="Running")
+
+        self.debug("Deploying another VM in the created VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm2"
+        self.test_data["virtual_machine"]["name"] = "vpcvm2"
+        vpc_vm_2 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_2, state="Running")
+
+        self.debug("Deploying a VM in the 2nd VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm12"
+        self.test_data["virtual_machine"]["name"] = "vpcvm12"
+        vpc_vm_12 = self.create_VM(vpc_2ndtier)
+        self.check_VM_state(vpc_vm_2, state="Running")
+        self.test_data["virtual_machine"]["displayname"] = None
+        self.test_data["virtual_machine"]["name"] = None
+
+        for i in range(1, 3):
+            self.debug("+++++Starting again as Native in Loop+++++")
+            self.debug("Creating Static NAT rule for the deployed VM "
+                       "in the created VPC network...")
+            public_ip_1 = self.acquire_PublicIPAddress(vpc_tier, vpc=vpc)
+            self.validate_PublicIPAddress(public_ip_1, vpc_tier)
+            self.create_StaticNatRule_For_VM(vpc_vm_1, public_ip_1, vpc_tier)
+            self.validate_PublicIPAddress(
+                    public_ip_1, vpc_tier, static_nat=True, vm=vpc_vm_1)
+
+            network_offering_map = \
+                [{"networkid": vpc_tier.id,
+                  "networkofferingid": self.nuage_vpc_network_offering.id},
+                 {"networkid": vpc_2ndtier.id,
+                  "networkofferingid": self.nuage_vpc_network_offering.id}]
+
+            csc_ips = self.define_cloudstack_managementip()
+            self.cloudstack_connection_vsd(connection="down",
+                                           cscip=csc_ips)
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.debug("Migrate_vpc fails when connection ACS VSD is down")
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.verify_cloudstack_host_state_up("Alert")
+            try:
+                self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                                 network_offering_map, resume=False)
+            except Exception as e:
+                errortext = \
+                    re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                              e.message).group(2)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "Failed to implement network (with specified id) " \
+                        "elements and resources as a part of network update"
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            self.cloudstack_connection_vsd(connection="up",
+                                           cscip=csc_ips)
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.debug("Migrate_vpc resumes when connection ACS VSD is up")
+            self.debug("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=")
+            self.verify_cloudstack_host_state_up("Up")
+            try:
+                self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                                 network_offering_map, resume=False)
+            except Exception as e:
+                errortext = \
+                    re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                              e.message).group(2)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "Failed to migrate VPC as previous migration " \
+                        "left this VPC in transient condition. " \
+                        "Specify resume as true."
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            network_offering_map = \
+                [{"networkid": vpc_tier.id,
+                  "networkofferingid": self.nuage_vpc_network_offering.id},
+                 {"networkid": vpc_2ndtier.id,
+                  "networkofferingid":
+                      self.nuage_isolated_network_offering.id}]
+            try:
+                self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                                 network_offering_map, resume=True)
+            except Exception as e:
+                errortext = \
+                    re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                              e.message).group(2)
+                self.debug("Migration fails with %s" % errortext)
+
+            expectstr = "can't be used for VPC networks for network"
+            self.verifymigrationerrortext(errortext, expectstr)
+
+            network_offering_map = \
+                [{"networkid": vpc_tier.id,
+                  "networkofferingid": self.nuage_vpc_network_offering.id},
+                 {"networkid": vpc_2ndtier.id,
+                  "networkofferingid": self.nuage_vpc_network_offering.id}]
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map, resume=True)
+            # checking after successful migrate vpc, migrate still succeeds
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map, resume=True)
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map, resume=False)
+
+            # VSD verification after VPC migration functionality
+            self.verify_vsd_network(self.domain.id, vpc_tier, vpc)
+            self.verify_vsd_vm(vpc_vm_1)
+            self.verify_vsd_vm(vpc_vm_2)
+            self.verify_vsd_floating_ip(
+                    vpc_tier, vpc_vm_1, public_ip_1.ipaddress, vpc=vpc)
+            self.verify_vsd_firewall_rule(acl_item)
+            # self.verify_vsd_firewall_rule(acl_item2)
+            self.verify_vsd_vm(vpc_vm_12)
+
+            self.test_data["virtual_machine"]["displayname"] = "vpcvm3"
+            self.test_data["virtual_machine"]["name"] = "vpcvm3"
+            vpc_vm_3 = self.create_VM(vpc_tier)
+
+            public_ip_2 = self.acquire_PublicIPAddress(vpc_tier, vpc=vpc)
+            self.create_StaticNatRule_For_VM(vpc_vm_3,
+                                             public_ip_2,
+                                             vpc_tier)
+
+            self.test_data["virtual_machine"]["displayname"] = "vpcvm4"
+            self.test_data["virtual_machine"]["name"] = "vpcvm4"
+            vpc_vm_4 = self.create_VM(vpc_tier)
+            self.verify_vsd_floating_ip(vpc_tier, vpc_vm_3,
+                                        public_ip_2.ipaddress, vpc=vpc)
+            self.verify_vsd_vm(vpc_vm_3)
+            self.verify_vsd_vm(vpc_vm_4)
+            self.test_data["virtual_machine"]["displayname"] = None
+            self.test_data["virtual_machine"]["name"] = None
+
+            vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+            try:
+                vpc_vm_3.ssh_ip = vm_public_ip_2
+                vpc_vm_3.ssh_port = \
+                    self.test_data["virtual_machine"]["ssh_port"]
+                vpc_vm_3.username = \
+                    self.test_data["virtual_machine"]["username"]
+                vpc_vm_3.password = \
+                    self.test_data["virtual_machine"]["password"]
+                self.debug("SSHing into VM: %s with %s" %
+                           (vpc_vm_3.ssh_ip, vpc_vm_3.password))
+
+                ssh2 = vpc_vm_3.get_ssh_client(ipaddress=vm_public_ip_2)
+
+            except Exception as e:
+                self.fail("SSH into VM failed with exception %s" % e)
+
+            self.verify_pingtovmipaddress(ssh2, vpc_vm_1.ipaddress)
+            self.verify_pingtovmhostname(ssh2, "vpcvm1")
+
+            self.verify_pingtovmipaddress(ssh2, vpc_vm_4.ipaddress)
+            self.verify_pingtovmhostname(ssh2, "vpcvm4")
+
+            self.verify_pingtovmipaddress(ssh2, vpc_vm_2.ipaddress)
+            self.verify_pingtovmhostname(ssh2, "vpcvm2")
+
+            self.debug("Updating the running vm_3 with new user data...")
+            expected_user_data2 = self.update_userdata(vpc_vm_3,
+                                                       "hellonuage vm3")
+            self.debug("SSHing into the vm_3 for verifying its user data...")
+            user_data_cmd = self.get_userdata_url(vpc_vm_3)
+            self.debug("Getting user data with command: " + user_data_cmd)
+            actual_user_data2 = self.execute_cmd(ssh2, user_data_cmd)
+            self.debug("Actual user data - " + actual_user_data2 +
+                       ", Expected user data - " + expected_user_data2)
+            self.assertEqual(actual_user_data2, expected_user_data2,
+                             "Un-expected VM (VM_3) user data")
+
+            self.verify_pingtovmipaddress(ssh2, vpc_vm_12.ipaddress)
+            self.verify_pingtovmhostname(ssh2, "vpcvm12")
+
+            vpc_vm_3.delete(self.api_client, expunge=True)
+            vpc_vm_4.delete(self.api_client, expunge=True)
+            public_ip_2.delete(self.api_client)
+
+            # ReleaseIP as get_ssh_client fails when migrating back to native
+            public_ip_1.delete(self.api_client)
+
+            self.debug("++++++++Migrating network back to native+++++++")
+            network_offering_map = \
+                [{"networkid": vpc_tier.id,
+                  "networkofferingid": native_tiernet_off.id},
+                 {"networkid": vpc_2ndtier.id,
+                  "networkofferingid": native_tiernet_off.id}]
+
+            self.migrate_vpc(vpc, native_vpc_off,
+                             network_offering_map)
+
+    @attr(tags=["migrateACS", "vpcmultinic"],
+          required_hardware="false")
+    def test_12_migrate_native_vpc_multinic_to_nuage_traffic(self):
+        """
+        Verify MultiNic migration of GuestVm in multiple networks
+        1. create one native vpc network offering
+        2. create one native vpc tier network offering
+        3. with Dhcp,SourceNat,StaticNat,Dns,Userdata and NetworkACL
+        4. create one vpc with above native vpc network offering
+        5. create one native vpc tier network in above vpc
+        6. create 2nd isolated network
+        7. deploy 2 vm's  in both networks
+        8. move to nuage vpc tier networkoffering,
+        9. deploy vm3 in vpc tier network
+        10. enable staticnat on first vm and ssh into vm
+        11. login to vm3 and ping vm1 nic1
+        12. move isolated network to nuage networkoffering,
+        13. deploy vm4 in 2nd vpc tier network
+        14. enable staticnat on new vm4 and ssh into vm
+        15. login to vm4 and ping vm2 nic1
+        """
+        cmd = updateZone.updateZoneCmd()
+        cmd.id = self.zone.id
+        cmd.domain = "vpc.com"
+        self.api_client.updateZone(cmd)
+
+        self.debug("Creating Native VSP VPC offering with Static NAT service "
+                   "provider as VPCVR...")
+        native_vpc_off = self.create_VpcOffering(
+                self.test_data["vpc_offering_native"])
+        self.validate_VpcOffering(native_vpc_off, state="Enabled")
+
+        self.debug("Creating a VPC with Static NAT service provider as "
+                   "VpcVirtualRouter")
+        vpc = self.create_Vpc(native_vpc_off, cidr='10.1.0.0/16')
+        self.validate_Vpc(vpc, state="Enabled")
+
+        self.debug("Creating native VPC Network Tier offering "
+                   "with Static NAT service provider as VPCVR")
+        native_tiernet_off = self.create_NetworkOffering(
+                self.test_data["vpc_network_offering_native"])
+        self.validate_NetworkOffering(native_tiernet_off, state="Enabled")
+
+        acl_list = self.create_NetworkAclList(
+                name="acl", description="acl", vpc=vpc)
+
+        acl_item = self.create_NetworkAclRule(
+                self.test_data["ingress_rule"], acl_list=acl_list)
+        self.create_NetworkAclRule(
+                self.test_data["icmprule"], acl_list=acl_list)
+
+        self.debug("Creating a VPC tier network with Static NAT service")
+        vpc_tier = self.create_Network(native_tiernet_off,
+                                       gateway='10.1.0.1',
+                                       vpc=vpc,
+                                       acl_list=acl_list)
+        self.validate_Network(vpc_tier, state="Implemented")
+
+        self.debug("Creating 2nd VPC tier network with Static NAT service")
+        vpc_2ndtier = self.create_Network(native_tiernet_off,
+                                          gateway='10.1.128.1',
+                                          vpc=vpc,
+                                          acl_list=acl_list)
+        self.validate_Network(vpc_2ndtier, state="Implemented")
+
+        vpc_vr = self.get_Router(vpc_tier)
+        self.check_Router_state(vpc_vr, state="Running")
+
+        isolated_network = self.create_Network(
+                self.native_isolated_network_staticnat_offering_persistent,
+                gateway="10.10.0.1",
+                netmask="255.255.255.0", account=self.account)
+        self.debug("Creating isolated network with Static NAT service")
+
+        self.debug("Deploying a multinic VM in both networks")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm1"
+        self.test_data["virtual_machine"]["name"] = "vpcvm1"
+        vpc_vm_1 = self.create_VM([vpc_tier, isolated_network])
+        self.check_VM_state(vpc_vm_1, state="Running")
+
+        self.debug("Deploying another VM in both networks other defaultnic")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm2"
+        self.test_data["virtual_machine"]["name"] = "vpcvm2"
+        vpc_vm_2 = self.create_VM([isolated_network, vpc_tier])
+        self.check_VM_state(vpc_vm_2, state="Running")
+        self.test_data["virtual_machine"]["displayname"] = None
+        self.test_data["virtual_machine"]["name"] = None
+        network_offering_map_fault = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id}]
+
+        try:
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map_fault, resume=False)
+        except Exception as e:
+            errortext = re.search(".*errortext\s*:\s*u?'([^']+)'.*",
+                                  e.message).group(1)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate VPC as the specified " \
+                    "tierNetworkOfferings is not complete"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        try:
+            self.migrate_network(self.nuage_isolated_network_offering,
+                                 vpc_tier, resume=False)
+        except Exception as e:
+            errortext = re.search(".*errortext\s*:\s*u?'([^']+)'.*",
+                                  e.message).group(1)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate network as the specified " \
+                    "network is a vpc tier. Use migrateVpc."
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        network_offering_map_fault2 = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id},
+             {"networkid": vpc_2ndtier.id,
+              "networkofferingid": self.nuage_isolated_network_offering.id}]
+
+        try:
+            self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                             network_offering_map_fault2, resume=True)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "can't be used for VPC networks for network"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        network_offering_map = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id},
+             {"networkid": vpc_2ndtier.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id}]
+
+        self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                         network_offering_map, resume=True)
+
+        self.debug("Deploying another VM in the created VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm3"
+        self.test_data["virtual_machine"]["name"] = "vpcvm3"
+        vpc_vm_3 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_3, state="Running")
+        self.test_data["virtual_machine"]["displayname"] = None
+        self.test_data["virtual_machine"]["name"] = None
+        self.debug("Creating Static NAT rule for the deployed VM "
+                   "in the created VPC network...")
+        public_ip_1 = self.acquire_PublicIPAddress(vpc_tier, vpc=vpc)
+        self.validate_PublicIPAddress(public_ip_1, vpc_tier)
+        self.create_StaticNatRule_For_VM(vpc_vm_3, public_ip_1, vpc_tier)
+        self.validate_PublicIPAddress(
+                public_ip_1, vpc_tier, static_nat=True, vm=vpc_vm_3)
+
+        # VSD verification after VPC migration functionality
+        self.verify_vsd_network(self.domain.id, vpc_tier, vpc)
+        self.verify_vsd_vm(vpc_vm_3)
+        self.verify_vsd_floating_ip(
+            vpc_tier, vpc_vm_3, public_ip_1.ipaddress, vpc=vpc)
+        self.verify_vsd_firewall_rule(acl_item)
+        # self.verify_vsd_vm(vpc_vm_1)
+
+        vm_public_ip_1 = public_ip_1.ipaddress.ipaddress
+        try:
+            vpc_vm_3.ssh_ip = vm_public_ip_1
+            vpc_vm_3.ssh_port = \
+                self.test_data["virtual_machine"]["ssh_port"]
+            vpc_vm_3.username = \
+                self.test_data["virtual_machine"]["username"]
+            vpc_vm_3.password = \
+                self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vpc_vm_3.ssh_ip, vpc_vm_1.password))
+
+            ssh = vpc_vm_3.get_ssh_client(ipaddress=vm_public_ip_1)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        defaultipaddress = \
+            [nic.ipaddress for nic in vpc_vm_1.nic if nic.isdefault][0]
+
+        self.verify_pingtovmipaddress(ssh, defaultipaddress)
+
+        vpc_vm_3.delete(self.api_client, expunge=True)
+        public_ip_1.delete(self.api_client)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_without_vr,
+                isolated_network)
+
+        self.test_data["virtual_machine"]["displayname"] = "vm4"
+        self.test_data["virtual_machine"]["name"] = "vm4"
+        vm_4 = self.create_VM(isolated_network)
+        self.test_data["virtual_machine"]["displayname"] = None
+        self.test_data["virtual_machine"]["name"] = None
+        self.debug("Creating Static NAT rule for the deployed VM "
+                   "in the created VPC network...")
+        public_ip_2 = self.acquire_PublicIPAddress(isolated_network)
+        self.validate_PublicIPAddress(public_ip_1, isolated_network)
+        self.create_StaticNatRule_For_VM(vm_4, public_ip_2, isolated_network)
+        self.validate_PublicIPAddress(
+                public_ip_2, isolated_network, static_nat=True, vm=vm_4)
+        firewall_rule_2 = self.create_FirewallRule(public_ip_2)
+        self.verify_vsd_network(self.domain.id, isolated_network)
+        self.verify_vsd_floating_ip(isolated_network, vm_4,
+                                    public_ip_2.ipaddress)
+        self.verify_vsd_vm(vm_4)
+        self.verify_vsd_firewall_rule(firewall_rule_2)
+        # self.verify_vsd_vm(vpc_vm_2)
+
+        vm_public_ip_2 = public_ip_2.ipaddress.ipaddress
+        try:
+            vm_4.ssh_ip = vm_public_ip_2
+            vm_4.ssh_port = self.test_data["virtual_machine"]["ssh_port"]
+            vm_4.username = self.test_data["virtual_machine"]["username"]
+            vm_4.password = self.test_data["virtual_machine"]["password"]
+            self.debug("SSHing into VM: %s with %s" %
+                       (vm_4.ssh_ip, vm_4.password))
+
+            ssh2 = vm_4.get_ssh_client(ipaddress=vm_public_ip_2)
+
+        except Exception as e:
+            self.fail("SSH into VM failed with exception %s" % e)
+
+        defaultipaddress2 = \
+            [nic.ipaddress for nic in vpc_vm_2.nic if nic.isdefault][0]
+
+        self.verify_pingtovmipaddress(ssh2, defaultipaddress2)
+
+    @attr(tags=["migrateACS", "guestvmip2"],
+          required_hardware="false")
+    def test_13_verify_guestvmip2_when_migrating_to_nuage(self):
+        """
+        Verify migration of GuestVm with ip .2 still works
+        when migrating isolated or vpc tier networks
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering,
+                gateway="10.13.0.1",
+                netmask="255.255.255.248", account=self.account)
+
+        self.test_data["virtual_machine"]["ipaddress"] = "10.13.0.2"
+        vm_11 = self.create_VM(isolated_network)
+        self.test_data["virtual_machine"]["ipaddress"] = "10.13.0.3"
+        vm_12 = self.create_VM(isolated_network)
+        self.test_data["virtual_machine"]["ipaddress"] = "10.13.0.4"
+        vm_13 = self.create_VM(isolated_network)
+        self.test_data["virtual_machine"]["ipaddress"] = "10.13.0.5"
+        vm_14 = self.create_VM(isolated_network)
+        self.test_data["virtual_machine"]["ipaddress"] = None
+        vm_15 = self.create_VM(isolated_network)
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_persistent,
+                    isolated_network, resume=False)
+        except Exception as e:
+            errortext = re.search(".*errortext\s*:\s*u?'([^']+)'.*",
+                                  e.message).group(1)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to implement network (with specified id) " \
+                    "elements and resources as a part of network update"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr,
+                    isolated_network, resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate network as previous migration " \
+                    "left this network in transient condition. " \
+                    "Specify resume as true."
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr,
+                    isolated_network, resume=True)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to resume migrating network as network offering " \
+                    "does not match previously specified network offering"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        vm_13.delete(self.api_client, expunge=True)
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_without_vr,
+                    isolated_network, resume=True)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to resume migrating network as network offering " \
+                    "does not match previously specified network offering"
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        try:
+            self.migrate_network(
+                    self.nuage_isolated_network_offering_persistent,
+                    isolated_network, resume=False)
+        except Exception as e:
+            errortext = \
+                re.search(".*errortext\s*:\s*u?(['\"])([^\\1]+)\\1.*",
+                          e.message).group(2)
+            self.debug("Migration fails with %s" % errortext)
+
+        expectstr = "Failed to migrate network as previous migration " \
+                    "left this network in transient condition. " \
+                    "Specify resume as true."
+        self.verifymigrationerrortext(errortext, expectstr)
+
+        self.migrate_network(
+                self.nuage_isolated_network_offering_persistent,
+                isolated_network, resume=True)
+
+        self.verify_vsd_network(self.domain.id, isolated_network, None)
+        self.verify_vsd_vm(vm_11)
+        self.verify_vsd_vm(vm_12)
+        self.verify_vsd_vm(vm_14)
+        self.verify_vsd_vm(vm_15)
+
+        cmd = updateZone.updateZoneCmd()
+        cmd.id = self.zone.id
+        cmd.domain = "vpc.com"
+        self.api_client.updateZone(cmd)
+
+        self.debug("Creating Native VSP VPC offering with Static NAT service "
+                   "provider as VPCVR...")
+        native_vpc_off = self.create_VpcOffering(
+                self.test_data["vpc_offering_native"])
+        self.validate_VpcOffering(native_vpc_off, state="Enabled")
+
+        self.debug("Creating a VPC with Static NAT service provider as "
+                   "VpcVirtualRouter")
+        vpc = self.create_Vpc(native_vpc_off, cidr='10.1.0.0/16')
+        self.validate_Vpc(vpc, state="Enabled")
+
+        self.debug("Creating native VPC Network Tier offering "
+                   "with Static NAT service provider as VPCVR")
+        native_tiernet_off = self.create_NetworkOffering(
+                self.test_data["vpc_network_offering_native"])
+        self.validate_NetworkOffering(native_tiernet_off, state="Enabled")
+
+        acl_list = self.create_NetworkAclList(
+                name="acl", description="acl", vpc=vpc)
+
+        self.create_NetworkAclRule(
+                self.test_data["ingress_rule"], acl_list=acl_list)
+        self.create_NetworkAclRule(
+                self.test_data["icmprule"], acl_list=acl_list)
+
+        self.debug("Creating a VPC tier network with Static NAT service")
+        vpc_tier = self.create_Network(native_tiernet_off,
+                                       gateway='10.1.1.1',
+                                       vpc=vpc,
+                                       acl_list=acl_list)
+        self.validate_Network(vpc_tier, state="Implemented")
+
+        vpc_vr = self.get_Router(vpc_tier)
+        self.check_Router_state(vpc_vr, state="Running")
+
+        self.debug("Deploying a VM in a vpc tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm1"
+        self.test_data["virtual_machine"]["name"] = "vpcvm1"
+        self.test_data["virtual_machine"]["ipaddress"] = "10.1.1.2"
+        vpc_vm_1 = self.create_VM(vpc_tier)
+        self.test_data["virtual_machine"]["ipaddress"] = None
+        self.check_VM_state(vpc_vm_1, state="Running")
+
+        self.debug("Deploying another VM in vpc tier")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm2"
+        self.test_data["virtual_machine"]["name"] = "vpcvm2"
+        vpc_vm_2 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_2, state="Running")
+
+        network_offering_map = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.nuage_vpc_network_offering.id}]
+
+        self.migrate_vpc(vpc, self.nuage_vpc_offering,
+                         network_offering_map, resume=False)
+
+        self.verify_vsd_network(self.domain.id, vpc_tier, vpc)
+        self.verify_vsd_vm(vpc_vm_1)
+        self.verify_vsd_vm(vpc_vm_2)
+
+    @attr(tags=["migrateACS", "nativeisoonly"],
+          required_hardware="false")
+    def test_14_native_to_native_network_migration(self):
+        """
+        Verify Migration for an isolated network nativeOnly
+        1. create native non-persistent isolated network
+        2. migrate to native persistent isolated network, check VR state
+        3. migrate back to native non-persistent network
+        4. deploy VM in non-persistent isolated network
+        5. acquire ip and enable staticnat
+        6. migrate to native persistent isolated network
+        7. migrate back to native non-persistent network
+        """
+        isolated_network = self.create_Network(
+                self.native_isolated_network_offering, gateway="10.0.0.1",
+                netmask="255.255.255.0")
+
+        self.migrate_network(
+                self.native_isolated_network_offering_persistent,
+                isolated_network, resume=False)
+
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+
+        self.migrate_network(
+                self.native_isolated_network_offering,
+                isolated_network, resume=False)
+
+        vm_1 = self.create_VM(isolated_network)
+        vr = self.get_Router(isolated_network)
+        self.check_Router_state(vr, "Running")
+        public_ip = self.acquire_PublicIPAddress(isolated_network)
+        self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network)
+        self.create_FirewallRule(public_ip)
+
+        self.migrate_network(
+                self.native_isolated_network_offering_persistent,
+                isolated_network, resume=False)
+
+        self.migrate_network(
+                self.native_isolated_network_offering,
+                isolated_network, resume=False)
+
+    @attr(tags=["migrateACS", "nativevpconly"],
+          required_hardware="false")
+    def test_15_native_to_native_vpc_migration(self):
+        """
+        Verify Migration for a vpc network nativeOnly
+        1. create native vpc with 2 tier networks
+        2. migrate to native vpc, check VR state
+        3. deploy VM in vpc tier network
+        4. acquire ip and enable staticnat
+        5. migrate to native vpc network
+        """
+
+        cmd = updateZone.updateZoneCmd()
+        cmd.id = self.zone.id
+        cmd.domain = "vpc.com"
+        self.api_client.updateZone(cmd)
+
+        self.debug("Creating Native VSP VPC offering with Static NAT service "
+                   "provider as VPCVR...")
+        native_vpc_off = self.create_VpcOffering(
+                self.test_data["vpc_offering_native"])
+        self.validate_VpcOffering(native_vpc_off, state="Enabled")
+
+        self.debug("Creating a VPC with Static NAT service provider as "
+                   "VpcVirtualRouter")
+        vpc = self.create_Vpc(native_vpc_off, cidr='10.1.0.0/16')
+        self.validate_Vpc(vpc, state="Enabled")
+
+        self.debug("Creating native VPC Network Tier offering "
+                   "with Static NAT service provider as VPCVR")
+        native_tiernet_off = self.create_NetworkOffering(
+                self.test_data["vpc_network_offering_native"])
+        self.validate_NetworkOffering(native_tiernet_off, state="Enabled")
+
+        acl_list = self.create_NetworkAclList(
+                name="acl", description="acl", vpc=vpc)
+
+        self.create_NetworkAclRule(
+                self.test_data["ingress_rule"], acl_list=acl_list)
+        self.create_NetworkAclRule(
+                self.test_data["icmprule"], acl_list=acl_list)
+
+        self.debug("Creating a VPC tier network with Static NAT service")
+        vpc_tier = self.create_Network(native_tiernet_off,
+                                       gateway='10.1.0.1',
+                                       vpc=vpc,
+                                       acl_list=acl_list)
+        self.validate_Network(vpc_tier, state="Implemented")
+
+        self.debug("Creating 2nd VPC tier network with Static NAT service")
+        vpc_2ndtier = self.create_Network(native_tiernet_off,
+                                          gateway='10.1.128.1',
+                                          vpc=vpc,
+                                          acl_list=acl_list)
+        self.validate_Network(vpc_2ndtier, state="Implemented")
+
+        vpc_vr = self.get_Router(vpc_tier)
+        self.check_Router_state(vpc_vr, state="Running")
+
+        network_offering_map = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.native_vpc_network_offering.id},
+             {"networkid": vpc_2ndtier.id,
+              "networkofferingid": self.native_vpc_network_offering.id}]
+
+        self.migrate_vpc(vpc, self.native_vpc_offering,
+                         network_offering_map, resume=False)
+
+        self.debug("Deploying a VM in the created VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm1"
+        self.test_data["virtual_machine"]["name"] = "vpcvm1"
+        vpc_vm_1 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_1, state="Running")
+
+        self.debug("Deploying another VM in the created VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm2"
+        self.test_data["virtual_machine"]["name"] = "vpcvm2"
+        vpc_vm_2 = self.create_VM(vpc_tier)
+        self.check_VM_state(vpc_vm_2, state="Running")
+
+        self.debug("Deploying a VM in the 2nd VPC tier network")
+        self.test_data["virtual_machine"]["displayname"] = "vpcvm12"
+        self.test_data["virtual_machine"]["name"] = "vpcvm12"
+        self.create_VM(vpc_2ndtier)
+        self.check_VM_state(vpc_vm_2, state="Running")
+        self.test_data["virtual_machine"]["displayname"] = None
+        self.test_data["virtual_machine"]["name"] = None
+
+        self.debug("Creating Static NAT rule for the deployed VM "
+                   "in the created VPC network...")
+        public_ip_1 = self.acquire_PublicIPAddress(vpc_tier, vpc=vpc)
+        self.validate_PublicIPAddress(public_ip_1, vpc_tier)
+        self.create_StaticNatRule_For_VM(vpc_vm_1, public_ip_1, vpc_tier)
+        self.validate_PublicIPAddress(
+                public_ip_1, vpc_tier, static_nat=True, vm=vpc_vm_1)
+
+        network_offering_map = \
+            [{"networkid": vpc_tier.id,
+              "networkofferingid": self.native_vpc_network_offering.id},
+             {"networkid": vpc_2ndtier.id,
+              "networkofferingid": self.native_vpc_network_offering.id}]
+        self.migrate_vpc(vpc, self.native_vpc_offering,
+                         network_offering_map, resume=False)
diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py
index 8a2ea4f..3e7080b 100644
--- a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py
+++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py
@@ -29,6 +29,7 @@ from marvin.cloudstackAPI import (listInternalLoadBalancerVMs,
                                   startInternalLoadBalancerVM)
 # Import System Modules
 from nose.plugins.attrib import attr
+from unittest import skip
 import copy
 import time
 
@@ -2268,6 +2269,8 @@ class TestNuageInternalLb(nuageTestCase):
         self.verify_lb_wget_file(
             wget_file, [internal_vm, internal_vm_1, internal_vm_2])
 
+    @skip
+    # Skip until CLOUDSTACK-9837 is fixed
     @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
     def test_08_nuage_internallb_appliance_operations_traffic(self):
         """Test Nuage VSP VPC Internal LB functionality with InternalLbVm
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index 07450cf..668dd33 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -133,6 +133,7 @@ known_categories = {
     'Pool': 'Pool',
     'VPC': 'VPC',
     'PrivateGateway': 'VPC',
+    'migrateVpc': 'VPC',
     'Simulator': 'simulator',
     'StaticRoute': 'VPC',
     'Tags': 'Resource tags',
diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py
index ece3e32..e99c8ba 100644
--- a/tools/marvin/marvin/config/test_data.py
+++ b/tools/marvin/marvin/config/test_data.py
@@ -1,4 +1,4 @@
-#t	 Licensed to the Apache Software Foundation (ASF) under one
+# Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
 # regarding copyright ownership.  The ASF licenses this file
@@ -253,6 +253,7 @@ test_data = {
         "traffictype": 'GUEST',
         "ispersistent": 'True',
         "availability": 'Optional',
+        "tags": 'native',
         "serviceProviderList": {
             "Dhcp": 'VirtualRouter',
             "Dns": 'VirtualRouter',
@@ -284,6 +285,7 @@ test_data = {
             "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat",
         "traffictype": "GUEST",
         "availability": "Optional'",
+        "tags": "native",
         "serviceProviderList": {
             "Dhcp": "VirtualRouter",
             "Dns": "VirtualRouter",
@@ -324,6 +326,24 @@ test_data = {
     "UserData": 'VirtualRouter',
     },
     },
+    "isolated_staticnat_network_offering": {
+        "name": 'isolated_staticnat_net_off_marvin',
+        "displaytext": 'isolated_staticnat_net_off_marvin',
+        "guestiptype": 'Isolated',
+        "supportedservices": 'Dhcp,SourceNat,StaticNat,UserData,Firewall,Dns',
+        "traffictype": 'GUEST',
+        "ispersistent": 'True',
+        "availability": 'Optional',
+        "tags": 'native',
+        "serviceProviderList": {
+            "Dhcp": 'VirtualRouter',
+            "StaticNat": 'VirtualRouter',
+            "SourceNat": 'VirtualRouter',
+            "Firewall": 'VirtualRouter',
+            "UserData": 'VirtualRouter',
+            "Dns": 'VirtualRouter'
+        }
+    },
     "isolated_network": {
         "name": "Isolated Network",
         "displaytext": "Isolated Network"
@@ -399,9 +419,10 @@ test_data = {
         "displaytext": "MySharedOffering",
         "guestiptype": "Shared",
         "supportedservices": "Dhcp,Dns,UserData",
-        "specifyVlan": "False",
-        "specifyIpRanges": "False",
+        "specifyVlan": "True",
+        "specifyIpRanges": "True",
         "traffictype": "GUEST",
+        "tags": "native",
         "serviceProviderList": {
             "Dhcp": "VirtualRouter",
             "Dns": "VirtualRouter",
@@ -478,6 +499,12 @@ test_data = {
             "NetworkACL": 'VpcVirtualRouter'
         }
     },
+    "vpc_offering_native": {
+        "name": "VPC native off",
+        "displaytext": "VPC native off",
+        "supportedservices":
+            "Dhcp,Dns,SourceNat,UserData,StaticNat,NetworkACL"
+    },
     "vpc": {
         "name": "TestVPC",
         "displaytext": "TestVPC",
@@ -614,6 +641,7 @@ test_data = {
         "availability": "Optional",
         "ispersistent": "False",
         "useVpc": "on",
+        "tags": 'native',
         "serviceProviderList": {
             "Dhcp": "VpcVirtualRouter",
             "Dns": "VpcVirtualRouter",
@@ -687,6 +715,25 @@ test_data = {
             "StaticNat": "VirtualRouter"
         }
     },
+    "vpc_network_offering_native": {
+        "name": 'vpc_net_off_marvin_native',
+        "displaytext": 'vpc_net_off_marvin_native',
+        "guestiptype": 'Isolated',
+        "supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,UserData,Dns',
+        "traffictype": 'GUEST',
+        "availability": 'Optional',
+        "tags": "native",
+        "useVpc": 'on',
+        "ispersistent": 'True',
+        "serviceProviderList": {
+            "Dhcp": "VpcVirtualRouter",
+            "StaticNat": "VpcVirtualRouter",
+            "SourceNat": "VpcVirtualRouter",
+            "NetworkACL": "VpcVirtualRouter",
+            "UserData": "VpcVirtualRouter",
+            "Dns": "VpcVirtualRouter"
+        }
+    },
     "fwrule": {
         "startport": 22,
         "endport": 22,
@@ -1881,6 +1928,7 @@ test_data = {
             "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall,Dns',
             "traffictype": 'GUEST',
             "availability": 'Optional',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": 'NuageVsp',
                 "StaticNat": 'NuageVsp',
@@ -1894,6 +1942,70 @@ test_data = {
                     "SourceNat": {"SupportedSourceNatTypes": "perzone"}
             }
         },
+        # Persistent services supported by the Nuage VSP plugin for Isolated networks
+        "isolated_network_offering_persistent": {
+            "name": 'nuage_marvin',
+            "displaytext": 'nuage_marvin',
+            "guestiptype": 'Isolated',
+            "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall,Dns',
+            "traffictype": 'GUEST',
+            "availability": 'Optional',
+            "ispersistent": 'True',
+            "tags": "nuage",
+            "serviceProviderList": {
+                "Dhcp": 'NuageVsp',
+                "StaticNat": 'NuageVsp',
+                "SourceNat": 'NuageVsp',
+                "Firewall": 'NuageVsp',
+                "Connectivity": 'NuageVsp',
+                "UserData": 'VirtualRouter',
+                "Dns": 'VirtualRouter'
+            },
+            "serviceCapabilityList": {
+                "SourceNat": {"SupportedSourceNatTypes": "perzone"}
+            }
+        },
+        # Purely nuage network offering
+        "isolated_network_offering_without_vr": {
+            "name": 'nuage_marvin',
+            "displaytext": 'nuage_marvin',
+            "guestiptype": 'Isolated',
+            "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,Firewall',
+            "traffictype": 'GUEST',
+            "availabiliy": 'Optional',
+            "tags": "nuage",
+            "serviceProviderList": {
+                "Dhcp": 'NuageVsp',
+                "StaticNat": 'NuageVsp',
+                "SourceNat": 'NuageVsp',
+                "Firewall": 'NuageVsp',
+                "Connectivity": 'NuageVsp'
+            },
+            "serviceCapabilityList": {
+                "SourceNat": {"SupportedSourceNatTypes": "perzone"}
+            }
+        },
+        # Purely persistent nuage network offering
+        "isolated_network_offering_without_vr_persistent": {
+            "name": 'nuage_marvin',
+            "displaytext": 'nuage_marvin',
+            "guestiptype": 'Isolated',
+            "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,Firewall',
+            "traffictype": 'GUEST',
+            "availability": 'Optional',
+            "tags": "nuage",
+            "ispersistent": 'True',
+            "serviceProviderList": {
+                "Dhcp": 'NuageVsp',
+                "StaticNat": 'NuageVsp',
+                "SourceNat": 'NuageVsp',
+                "Firewall": 'NuageVsp',
+                "Connectivity": 'NuageVsp'
+            },
+            "serviceCapabilityList": {
+                "SourceNat": {"SupportedSourceNatTypes": "perzone"}
+            }
+        },
         # Services supported by the Nuage VSP plugin for VPC networks
         "vpc_network_offering": {
             "name": 'nuage_vpc_marvin',
@@ -1904,6 +2016,7 @@ test_data = {
             "availability": 'Optional',
             "useVpc": 'on',
             "ispersistent": 'True',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": "NuageVsp",
                 "StaticNat": "NuageVsp",
@@ -1924,6 +2037,7 @@ test_data = {
             "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData,Dns',
             "traffictype": 'GUEST',
             "availability": 'Optional',
+            "tags": "nuage",
             "useVpc": 'on',
             "ispersistent": 'True',
             "serviceProviderList": {
@@ -2016,6 +2130,7 @@ test_data = {
             "specifyVlan": "False",
             "specifyIpRanges": "True",
             "availability": 'Optional',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": "NuageVsp",
                 "Connectivity": "NuageVsp"
@@ -2030,6 +2145,7 @@ test_data = {
             "specifyVlan": "False",
             "specifyIpRanges": "True",
             "availability": 'Optional',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": "NuageVsp",
                 "Connectivity": "NuageVsp"
diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py
index 2413328..8d553c8 100644
--- a/tools/marvin/marvin/deployDataCenter.py
+++ b/tools/marvin/marvin/deployDataCenter.py
@@ -456,6 +456,9 @@ class DeployDataCenters(object):
             phynet.zoneid = zoneid
             phynet.name = net.name
             phynet.isolationmethods = net.isolationmethods
+            if net.tags:
+                phynet.tags = net.tags
+
             phynetwrk = self.__apiClient.createPhysicalNetwork(phynet)
             if phynetwrk.id:
                 self.__tcRunLogger.\
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 340419a..d8fcb59 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -2240,6 +2240,8 @@ class NetworkOffering:
             cmd.ispersistent = services["ispersistent"]
         if "egress_policy" in services:
             cmd.egressdefaultpolicy = services["egress_policy"]
+        if "tags" in services:
+            cmd.tags = services["tags"]
         cmd.details = [{}]
         if "servicepackageuuid" in services:
             cmd.details[0]["servicepackageuuid"] = services["servicepackageuuid"]
@@ -2979,6 +2981,13 @@ class Network:
             cmd.cleanup = cleanup
         return(apiclient.restartNetwork(cmd))
 
+    def migrate(self, apiclient, network_offering_id, resume=False):
+        cmd = migrateNetwork.migrateNetworkCmd()
+        cmd.networkid = self.id
+        cmd.networkofferingid = network_offering_id
+        cmd.resume = resume
+        return(apiclient.migrateNetwork(cmd))
+
     @classmethod
     def list(cls, apiclient, **kwargs):
         """List all Networks matching criteria"""
@@ -4405,6 +4414,15 @@ class VPC:
             cmd.displaytext = displaytext
         return (apiclient.updateVPC(cmd))
 
+    def migrate(self, apiclient, vpc_offering_id, vpc_network_offering_ids, resume=False):
+        cmd = migrateVPC.migrateVPCCmd()
+        cmd.vpcid = self.id
+        cmd.vpcofferingid = vpc_offering_id
+        cmd.tiernetworkofferings = vpc_network_offering_ids
+        cmd.resume = resume
+        return(apiclient.migrateVPC(cmd))
+
+
     def delete(self, apiclient):
         """Delete VPC network"""
 
@@ -5250,3 +5268,34 @@ class RegisteredServicePackage:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.listRegisteredServicePackages(cmd))
 
+
+class ResourceDetails:
+
+    @classmethod
+    def create(cls, apiclient, resourceid, resourcetype, details, fordisplay):
+        """Create resource detail"""
+
+        cmd = addResourceDetail.addResourceDetailCmd()
+        cmd.resourceid = resourceid
+        cmd.resourcetype = resourcetype
+        cmd.fordisplay = fordisplay
+        cmd.details = []
+        for key, value in details.items():
+            cmd.details.append({
+                'key': key,
+                'value': value
+            })
+        return Tag(apiclient.createTags(cmd).__dict__)
+
+    @classmethod
+    def list(self, apiclient, **kwargs):
+        cmd = listResourceDetails.listResourceDetailsCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return (apiclient.listResourceDetails(cmd))
+
+    @classmethod
+    def delete(self, apiclient, resourceid, resourcetype):
+        cmd = removeResourceDetail.removeResourceDetailCmd()
+        cmd.resourceid = resourceid
+        cmd.resourcetype = resourcetype
+        return (apiclient.removeResourceDetail(cmd))
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java
index dddab4d..bb7f3c5 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java
@@ -29,6 +29,8 @@ import java.util.List;
 import java.util.Random;
 import java.util.UUID;
 
+import javax.annotation.Nonnull;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 
@@ -88,32 +90,48 @@ public class VmwareHelper {
         return deviceNumber == 7;
     }
 
-    public static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEthernetCardType deviceType, String portGroupName,
-            String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
-
-        assert(vmMo.getRunningHost().hasOpaqueNSXNetwork());
+    @Nonnull
+    private static VirtualDeviceConnectInfo getVirtualDeviceConnectInfo(boolean connected, boolean connectOnStart) {
+        VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
+        connectInfo.setAllowGuestControl(true);
+        connectInfo.setConnected(connected);
+        connectInfo.setStartConnected(connectOnStart);
+        return connectInfo;
+    }
 
+    @Nonnull
+    private static VirtualEthernetCard createVirtualEthernetCard(VirtualEthernetCardType deviceType) {
         VirtualEthernetCard nic;
         switch (deviceType) {
-        case E1000:
-            nic = new VirtualE1000();
-            break;
+            case E1000:
+                nic = new VirtualE1000();
+                break;
 
-        case PCNet32:
-            nic = new VirtualPCNet32();
-            break;
+            case PCNet32:
+                nic = new VirtualPCNet32();
+                break;
 
-        case Vmxnet2:
-            nic = new VirtualVmxnet2();
-            break;
+            case Vmxnet2:
+                nic = new VirtualVmxnet2();
+                break;
 
-        case Vmxnet3:
-            nic = new VirtualVmxnet3();
-            break;
+            case Vmxnet3:
+                nic = new VirtualVmxnet3();
+                break;
 
-        default:
-            nic = new VirtualE1000();
+            default:
+                assert (false);
+                nic = new VirtualE1000();
         }
+        return nic;
+    }
+
+    public static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEthernetCardType deviceType, String portGroupName,
+            String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
+
+        assert(vmMo.getRunningHost().hasOpaqueNSXNetwork());
+
+        VirtualEthernetCard nic = createVirtualEthernetCard(deviceType);
 
         VirtualEthernetCardOpaqueNetworkBackingInfo nicBacking = new VirtualEthernetCardOpaqueNetworkBackingInfo();
         nicBacking.setOpaqueNetworkId("br-int");
@@ -121,54 +139,42 @@ public class VmwareHelper {
 
         nic.setBacking(nicBacking);
 
-        VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
-        connectInfo.setAllowGuestControl(true);
-        connectInfo.setConnected(connected);
-        connectInfo.setStartConnected(connectOnStart);
         nic.setAddressType("Manual");
-        nic.setConnectable(connectInfo);
+        nic.setConnectable(getVirtualDeviceConnectInfo(connected, connectOnStart));
         nic.setMacAddress(macAddress);
         nic.setKey(-contextNumber);
         return nic;
     }
 
-    public static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String portGroupName,
-            String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
-
-        VirtualEthernetCard nic;
-        switch (deviceType) {
-        case E1000:
-            nic = new VirtualE1000();
-            break;
+    public static void updateNicDevice(VirtualDevice nic, ManagedObjectReference morNetwork, String portGroupName) throws Exception {
+        VirtualEthernetCardNetworkBackingInfo nicBacking = new VirtualEthernetCardNetworkBackingInfo();
+        nicBacking.setDeviceName(portGroupName);
+        nicBacking.setNetwork(morNetwork);
+        nic.setBacking(nicBacking);
+    }
 
-        case PCNet32:
-            nic = new VirtualPCNet32();
-            break;
+    public static void updateDvNicDevice(VirtualDevice nic, ManagedObjectReference morNetwork, String dvSwitchUuid) throws Exception {
+        final VirtualEthernetCardDistributedVirtualPortBackingInfo dvPortBacking = new VirtualEthernetCardDistributedVirtualPortBackingInfo();
+        final DistributedVirtualSwitchPortConnection dvPortConnection = new DistributedVirtualSwitchPortConnection();
 
-        case Vmxnet2:
-            nic = new VirtualVmxnet2();
-            break;
+        dvPortConnection.setSwitchUuid(dvSwitchUuid);
+        dvPortConnection.setPortgroupKey(morNetwork.getValue());
+        dvPortBacking.setPort(dvPortConnection);
+        nic.setBacking(dvPortBacking);
+    }
 
-        case Vmxnet3:
-            nic = new VirtualVmxnet3();
-            break;
+    public static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String portGroupName,
+            String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
 
-        default:
-            assert (false);
-            nic = new VirtualE1000();
-        }
+        VirtualEthernetCard nic = createVirtualEthernetCard(deviceType);
 
         VirtualEthernetCardNetworkBackingInfo nicBacking = new VirtualEthernetCardNetworkBackingInfo();
         nicBacking.setDeviceName(portGroupName);
         nicBacking.setNetwork(morNetwork);
         nic.setBacking(nicBacking);
 
-        VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
-        connectInfo.setAllowGuestControl(true);
-        connectInfo.setConnected(connected);
-        connectInfo.setStartConnected(connectOnStart);
         nic.setAddressType("Manual");
-        nic.setConnectable(connectInfo);
+        nic.setConnectable(getVirtualDeviceConnectInfo(connected, connectOnStart));
         nic.setMacAddress(macAddress);
         nic.setKey(-contextNumber);
         return nic;
@@ -177,43 +183,18 @@ public class VmwareHelper {
     public static VirtualDevice prepareDvNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String dvPortGroupName,
             String dvSwitchUuid, String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
 
-        VirtualEthernetCard nic;
-        switch (deviceType) {
-        case E1000:
-            nic = new VirtualE1000();
-            break;
-
-        case PCNet32:
-            nic = new VirtualPCNet32();
-            break;
-
-        case Vmxnet2:
-            nic = new VirtualVmxnet2();
-            break;
-
-        case Vmxnet3:
-            nic = new VirtualVmxnet3();
-            break;
-
-        default:
-            assert (false);
-            nic = new VirtualE1000();
-        }
+        VirtualEthernetCard nic = createVirtualEthernetCard(deviceType);
 
         final VirtualEthernetCardDistributedVirtualPortBackingInfo dvPortBacking = new VirtualEthernetCardDistributedVirtualPortBackingInfo();
         final DistributedVirtualSwitchPortConnection dvPortConnection = new DistributedVirtualSwitchPortConnection();
-        final VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
 
         dvPortConnection.setSwitchUuid(dvSwitchUuid);
         dvPortConnection.setPortgroupKey(morNetwork.getValue());
         dvPortBacking.setPort(dvPortConnection);
         nic.setBacking(dvPortBacking);
 
-        connectInfo.setAllowGuestControl(true);
-        connectInfo.setConnected(connected);
-        connectInfo.setStartConnected(connectOnStart);
         nic.setAddressType("Manual");
-        nic.setConnectable(connectInfo);
+        nic.setConnectable(getVirtualDeviceConnectInfo(connected, connectOnStart));
         nic.setMacAddress(macAddress);
         nic.setKey(-contextNumber);
         return nic;

-- 
To stop receiving notification emails like this one, please contact
['"commits@cloudstack.apache.org" <co...@cloudstack.apache.org>'].