cloudstack-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ASF GitHub Bot (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (CLOUDSTACK-10024) Physical Networking Migration
Date Thu, 21 Dec 2017 10:26:04 GMT

    [ https://issues.apache.org/jira/browse/CLOUDSTACK-10024?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16299840#comment-16299840 ] 

ASF GitHub Bot commented on CLOUDSTACK-10024:
---------------------------------------------

fmaximus closed pull request #2259: CLOUDSTACK-10024: Network migration support
URL: https://github.com/apache/cloudstack/pull/2259
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index d5d11e87702..ce410a6795d 100644
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -130,6 +130,7 @@
     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 0ad42b5acdd..2559cfa97fb 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.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 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne
     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 37746f0d0f7..06f4236eb7a 100644
--- a/api/src/com/cloud/network/Networks.java
+++ b/api/src/com/cloud/network/Networks.java
@@ -246,6 +246,7 @@ public static String getValue(String uriString) throws URISyntaxException {
          * 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 3532010f1fa..0c8378908e6 100644
--- a/api/src/com/cloud/offering/NetworkOffering.java
+++ b/api/src/com/cloud/offering/NetworkOffering.java
@@ -38,7 +38,7 @@
     }
 
     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 3bed77d6d02..067cb973e2f 100644
--- a/api/src/com/cloud/server/ResourceTag.java
+++ b/api/src/com/cloud/server/ResourceTag.java
@@ -58,7 +58,9 @@
         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 b7d3668c3e2..2856e0aea75 100644
--- a/api/src/com/cloud/vm/NicSecondaryIp.java
+++ b/api/src/com/cloud/vm/NicSecondaryIp.java
@@ -32,6 +32,8 @@
 
     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 a5bd95f83c5..64cdb23674e 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -332,6 +332,7 @@
     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 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 00000000000..651fce87fd3
--- /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 00000000000..6cf115742a8
--- /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 411da4fd36b..5c58530fe1f 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 @@
                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 Boolean getKeepAliveEnabled() {
         return keepAliveEnabled;
     }
 
+    public String getTags() {
+        return tags;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/core/src/com/cloud/agent/api/ReplugNicAnswer.java b/core/src/com/cloud/agent/api/ReplugNicAnswer.java
new file mode 100644
index 00000000000..7de39c3fa33
--- /dev/null
+++ b/core/src/com/cloud/agent/api/ReplugNicAnswer.java
@@ -0,0 +1,29 @@
+//
+// 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;
+
+public class ReplugNicAnswer extends Answer {
+    public ReplugNicAnswer() {
+    }
+
+    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 00000000000..1c61f0a649e
--- /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 14fead7a057..a20fc7b88d7 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -193,6 +193,9 @@ NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile request
      */
     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 e2a471fef6a..86a8fe91a36 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
@@ -129,6 +129,11 @@ void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationC
 
     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
      *
@@ -275,4 +280,6 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon
     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 74927b9d465..da13b7ac20a 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -38,8 +38,8 @@
 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.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.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.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 @@ private void orchestrateMigrateForScale(final String vmUuid, final long srcHostI
         }
     }
 
+    @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 boolean plugNic(final Network network, final NicTO nic, final VirtualMach
                 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 boolean unplugNic(final Network network, final NicTO nic, final VirtualMa
                 _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 1ddff84f991..e819248f3e9 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 @@
 
     List<NetworkGuru> networkGurus;
 
-
+    @Override
     public List<NetworkGuru> getNetworkGurus() {
         return networkGurus;
     }
@@ -1156,7 +1156,7 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f
                 }
 
                 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 boolean destroyNetwork(final long networkId, final ReservationContext con
                     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 08a326a0e1e..f8717880773 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 long getRelated() {
         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 db86cfa26b0..5808af3a3e8 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 long getNetworkId() {
         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 b6ed5cbd2cb..fb6a239c58d 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 void setDisplay(boolean display) {
         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 23568b49230..9919ba3bf7f 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 long getNetworkACLId() {
     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 5e2a6f50c9c..37ba3471ce8 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 00bb1d87c02..d21df1244f6 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 @@
 
 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 a2a449b9930..e6a72c870b0 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 @@
     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 284fd8884c1..39d33192a09 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 Long getNetworkAclIdForPrivateIp(long vpcId, long networkId, String ipadd
         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 9679c3af7d8..9e14bb5348f 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 boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Ser
     @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 c16c5ac4bf1..d28e150da7c 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.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 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 long getId() {
         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 String getValue() {
         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 f6451fb72c9..e31714356e6 100644
--- a/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java
+++ b/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java
@@ -223,6 +223,10 @@ public String getTags() {
         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 6af9c91c122..94e5006a708 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 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 ea476709c2e..786b71c17c4 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 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 NetworkOfferingDetailsDaoImpl() {
     @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 NetworkOfferingDetailsDaoImpl() {
     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 String getDetail(long offeringId, Detail detailName) {
         }
     }
 
+    @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 b7884342a53..bacb09b9879 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 @@
 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 d5578a8fded..cc9d99e6ab1 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 ResourceTagsDaoImpl() {
         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 boolean removeByIdAndType(long resourceId, ResourceTag.ResourceObjectType
         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 boolean removeByIdAndType(long resourceId, ResourceTag.ResourceObjectType
         }
         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 b79c101b828..40e7e407241 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 @@
 
     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 48cc6621b44..d1453aa4630 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 Integer countAliasIps(long id) {
         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 ef8df516e9f..96b80b84dd7 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 @@
     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 50733de002d..01f53bc99fb 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 Long countByNicId(long nicId) {
         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 23e45e8a235..d60ac9298fc 100644
--- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java
+++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java
@@ -97,6 +97,11 @@ public long getNicId() {
         return nicId;
     }
 
+    @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 2fab9a83cf7..11b22c494f4 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 void configure(Map<String, Object> params) throws ConfigurationException
 
         super.configure(params);
 
+        getPifs();
+
         // Set the domr scripts directory
         params.put("domr.scripts.dir", "scripts/network/domr/kvm");
 
@@ -80,12 +85,125 @@ public void configure(Map<String, Object> params) throws ConfigurationException
         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 void configure(Map<String, Object> params) throws ConfigurationException
         if (nic.getPxeDisable() == true) {
             intf.setPxeDisable(true);
         }
+
         return intf;
     }
 
@@ -169,6 +288,16 @@ public void unplug(LibvirtVMDef.InterfaceDef iface) {
         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 @@ private void deleteVnetBr(String brName) {
         }
     }
 
-    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 @@ private void deleteExistingLinkLocalRouteTable(String linkLocalBr) {
         }
     }
 
-    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 3cc8839176c..b8763fa8da7 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 void unplug(LibvirtVMDef.InterfaceDef iface) {
         // 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 1aae2b58933..8e73d859039 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 void configure(Map<String, Object> params) throws ConfigurationException
         if (libvirtVersion == null) {
             libvirtVersion = 0L;
         }
-
-        createControlNetwork(_bridges.get("linklocal"));
     }
 
     @Override
@@ -145,6 +143,17 @@ public InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter) throw
     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 @@ private void deleteExitingLinkLocalRouteTable(String linkLocalBr) {
         }
     }
 
-    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 51b9737312e..9c97b3ed23f 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.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.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.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 boolean configure(final String name, final Map<String, Object> params) th
             }
         }
 
+        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 boolean configure(final String name, final Map<String, Object> params) th
             getPifs();
             break;
         }
+        */
 
         if (_pifs.get("private") == null) {
             s_logger.debug("Failed to get private nic name");
@@ -1027,19 +1042,13 @@ public boolean configure(final String name, final Map<String, Object> params) th
             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 VifDriver getVifDriver(final TrafficType trafficType) {
         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 @@ private void getPifs() {
         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 @@ private void getPifs() {
         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 @@ private void getOvsPifs() {
             // 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 @@ private void getOvsPifs() {
         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 @@ boolean isInterface(final String fname) {
         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 synchronized boolean destroyTunnelNetwork(final String bridge) {
 
     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 @@ private void createVif(final LibvirtVMDef vm, final NicTO nic, final String nicA
             }
         }
 
-        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 847d77553f4..d979d553f48 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.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.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 boolean parseDomainXML(String domXML) {
                 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 boolean parseDomainXML(String domXML) {
                     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 0f34a92d6d6..0196c85bb58 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 String toString() {
             }
         }
 
-        enum NicModel {
+        public enum NicModel {
             E1000("e1000"), VIRTIO("virtio"), RTL8139("rtl8139"), NE2KPCI("ne2k_pci"), VMXNET3("vmxnet3");
             String _model;
 
@@ -925,6 +926,8 @@ public String toString() {
         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 String getDevName() {
             return _networkName;
         }
 
+        public void setDevName(String networkName) {
+            _networkName = networkName;
+        }
+
         public String getMacAddress() {
             return _macAddr;
         }
@@ -1044,6 +1051,22 @@ public int getVlanTag() {
             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 String toString() {
             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 6462df7cf30..06cd1617b78 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 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 void configure(Map<String, Object> params) throws ConfigurationException
 
         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 void unplug(InterfaceDef iface) {
         // 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 @@ private void deleteExitingLinkLocalRouteTable(String linkLocalBr) {
         }
     }
 
-    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 5cd2d6151a4..387a552b55e 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 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 2baec276a0f..dad73f28c16 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 void configure(Map<String, Object> params) throws ConfigurationException
             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 0d3df1f274c..1ce491cd16c 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.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 Answer execute(final CheckNetworkCommand command, final LibvirtComputingR
         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 018d6a784c3..2ee9b953d84 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.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 Answer execute(final PlugNicCommand command, final LibvirtComputingResour
                 }
                 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 2dfca5d6fc4..940a0a727ef 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.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 Answer execute(final PrepareForMigrationCommand command, final LibvirtCom
 
             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 00000000000..8c20a33e608
--- /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 b3f85300321..2fd7692df58 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.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.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.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 void testPrepareForMigrationCommand() {
         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 void testPrepareForMigrationCommandMigration() {
         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 void testPrepareForMigrationCommandURISyntaxException() {
         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 void testPrepareForMigrationCommandInternalErrorException() {
         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 void testCheckNetworkCommand() {
 
         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 void testCheckNetworkCommand() {
         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 void testCheckNetworkCommandFail1() {
 
         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 void testCheckNetworkCommandFail1() {
         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 void testCheckNetworkCommandFail2() {
 
         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 void testCheckNetworkCommandFail2() {
         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 void testCheckNetworkCommandFail3() {
 
         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 void testCheckNetworkCommandFail3() {
         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 void testPlugNicCommandNoMatchMack() {
         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 void testPlugNicCommandNoMatchMack() {
         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 void testPlugNicCommandInternalError() {
             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 void testPlugNicCommandInternalError() {
         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 78c4e868f2c..9197013af20 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 void testDomainXMLParser() {
         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 e758dece166..006562c213e 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 void testInterfaceEtehrnet() {
         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 void testInterfaceDirectNet() {
         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 00000000000..86e455be271
--- /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 e7a7a956fd0..c44a1235627 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.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 @@
 
     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 0251c0c9073..41f9ce24585 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.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,13 +136,24 @@ public PlugNicAnswer plugNic(PlugNicCommand cmd) {
     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];
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 ae06a12ad70..38c2a8e004b 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 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.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.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.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 Answer simulate(final Command cmd, final String hostGuid) {
                     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 40ffdf490d4..7aac8ce52bb 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.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.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 Answer executeRequest(Command cmd) {
                 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 @@ private PlugNicAnswer execute(PlugNicCommand cmd) {
         }
     }
 
+    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 fe51c8b0d51..bea8cb924a0 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 16cbc9dbfa7..e91901a2c8e 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.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.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.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.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.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 @@
     @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 @@
     @Inject
     NicDao _nicDao;
     @Inject
-    VpcDao _vpcDao;
-    @Inject
     VpcOfferingServiceMapDao _vpcOfferingSrvcDao;
     @Inject
-    NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
-    @Inject
     AgentManager _agentMgr;
     @Inject
     NetworkOfferingDao _ntwkOfferingDao;
@@ -212,15 +190,10 @@
     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 String apply(@Nullable DomainRouterVO input) {
                 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 String apply(@Nullable DomainRouterVO input) {
                 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 b1577de0b39..f43e350d4dc 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 Network implement(Network network, NetworkOffering offering, DeployDestin
                 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 @@ private boolean implement(Long vpcId, long physicalNetworkId, VspNetwork vspNetw
     }
 
     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 void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D
             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 boolean trash(Network network, NetworkOffering offering) {
             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 boolean trash(Network network, NetworkOffering offering) {
         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 5a0a5d12e0b..c024a7b6adb 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 VspDomainCleanUp buildVspDomainCleanUp(Domain domain) {
     }
 
     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 VspNetwork buildVspNetwork(long domainId, Network network) {
             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 @@ private boolean isVlanContainingIp(Vlan vlan, long ip) {
         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 @@ private String getVirtualRouterIP(Network network, List<Pair<String, String>> ip
             }
         }
 
+
+        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 @@ private String getVirtualRouterIP(Network network, List<Pair<String, String>> ip
             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 f5a0f400e41..fea759dccdf 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 void setUp() throws Exception {
         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 3805b13e528..43d465fb5f3 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.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 @@
     @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 94e8559120a..aacae264d1d 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 034111ef428..dfc7c372d48 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -5071,6 +5071,7 @@ public NetworkOffering updateNetworkOffering(final UpdateNetworkOfferingCmd cmd)
         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 NetworkOffering updateNetworkOffering(final UpdateNetworkOfferingCmd cmd)
             }
         }
 
+        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 f3aedefc9dd..c5006b4d5eb 100644
--- a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java
+++ b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java
@@ -23,6 +23,7 @@
 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 @@
     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 boolean configure(String name, Map<String, Object> params) throws Configu
         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 boolean deleteResourceMetaData(String resourceId, ResourceObjectType reso
         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 @@ private void removeDetail(long resourceId, String key) {
             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 00000000000..98bf849cc68
--- /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 00000000000..956f1fb61ed
--- /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 2efec9a0999..f93b4d6640e 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -33,13 +33,14 @@
 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;
@@ -99,7 +100,6 @@
 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;
@@ -145,23 +145,18 @@
     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 966c0e4475b..a2d0694dba8 100644
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -33,12 +33,12 @@
 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.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.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.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.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.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.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.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.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 @@
     @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 @@
     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 @@
     PhysicalNetworkDao _physicalNetworkDao;
     @Inject
     PhysicalNetworkServiceProviderDao _pNSPDao;
-
     @Inject
     PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
-
     @Inject
     NetworkServiceMapDao _ntwkSrvcDao;
     @Inject
@@ -292,17 +272,13 @@
     NetworkOrchestrationService _networkMgr;
     @Inject
     NetworkModel _networkModel;
-
     @Inject
     NicSecondaryIpDao _nicSecondaryIpDao;
-
     @Inject
     PortForwardingRulesDao _portForwardingDao;
     @Inject
     HostDao _hostDao;
     @Inject
-    HostPodDao _hostPodDao;
-    @Inject
     InternalLoadBalancerElementService _internalLbElementSvc;
     @Inject
     DataCenterVnetDao _datacneterVnet;
@@ -318,26 +294,20 @@
     IpAddressManager _ipAddrMgr;
     @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 @@ private boolean releaseIpAddressInternal(long ipAddressId) throws InsufficientAd
 
         // 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 Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac
 
         // 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 Network doInTransaction(TransactionStatus status) throws InsufficientCapa
                 }
                 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 boolean deleteNetwork(long networkId, boolean forced) {
         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 boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws Con
         // 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 Network updateGuestNetwork(final long networkId, String name, String disp
         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 Network updateGuestNetwork(final long networkId, String name, String disp
         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 Network updateGuestNetwork(final long networkId, String name, String disp
                 }
                 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 Network updateGuestNetwork(final long networkId, String name, String disp
             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 Network updateGuestNetwork(final long networkId, String name, String disp
                 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 Network updateGuestNetwork(final long networkId, String name, String disp
         // 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 Network updateGuestNetwork(final long networkId, String name, String disp
             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 void doInTransactionWithoutResult(TransactionStatus status) {
                     }
                 }
                 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 void doInTransactionWithoutResult(TransactionStatus status) {
         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 @@ protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long ne
         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 PhysicalNetwork updatePhysicalNetwork(Long id, String networkSpeed, List<
         // 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 boolean deletePhysicalNetwork(final Long physicalNetworkId) {
         // 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 int compare(AccountGuestVlanMapVO obj1, AccountGuestVlanMapVO obj2) {
         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 PhysicalNetworkServiceProvider addProviderToPhysicalNetwork(Long physical
         // 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 boolean deletePhysicalNetworkTrafficType(Long id) {
     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 Network createPrivateNetwork(final String networkName, final String displ
         // 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 Network getNetwork(String networkUuid) {
         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 Network getNetwork(String networkUuid) {
         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 5c35c15a1f8..f22786433c2 100644
--- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
@@ -867,6 +867,7 @@ public boolean deleteVpc(final long vpcId) throws ConcurrentOperationException,
 
         // 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 60628206e74..177342b0575 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.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 long getMemoryOrCpuCapacityByHost(final Long hostId, final short capacity
         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 08ed3dd1f71..7528d6861dc 100644
--- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
+++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
@@ -24,6 +24,8 @@
 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 @@
         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 81f06bccfae..cdf7180febe 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -24,6 +24,9 @@
 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.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.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 Network updateGuestNetwork(long networkId, String name, String displayTex
         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 int getResourceCount(Network network) {
         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 121921b3f82..aaeb97ad8d3 100644
--- a/test/integration/plugins/nuagevsp/nuageTestCase.py
+++ b/test/integration/plugins/nuagevsp/nuageTestCase.py
@@ -35,6 +35,7 @@
                              Router,
                              ServiceOffering,
                              StaticNATRule,
+                             ResourceDetails,
                              VirtualMachine,
                              VPC,
                              VpcOffering,
@@ -42,15 +43,16 @@
 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 @@ def setUpClass(cls):
             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 @@ def create_NetworkOffering(cls, net_offering, suffix=None,
     @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 @@ def create_Network(cls, nw_off, gateway="10.1.1.1",
                                  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 @@ def verify_vsd_network(self, domain_id, network, vpc=None,
         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 @@ def verify_vsd_firewall_rule(self, firewall_rule, traffic_type="Ingress"):
         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 7f3f3a2dfbf..691e10360b6 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 cc52e66d7b1..cabba0cf5f0 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 @@ def validate_all_extra_dhcp_for_remove_nic_from_vm(
 
         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 1e774a38db2..b0026d7c77c 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.lib.base import Account, Network
 # Import System Modules
 from nose.plugins.attrib import attr
+import time
 
 
 class TestNuageInternalDns(nuageTestCase):
@@ -293,6 +294,7 @@ def test_03_Isolated_Network_restarts(self):
         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 00000000000..d346a9a008a
--- /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 8a2ea4f179e..3e7080b0739 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 @@
                                   startInternalLoadBalancerVM)
 # Import System Modules
 from nose.plugins.attrib import attr
+from unittest import skip
 import copy
 import time
 
@@ -2268,6 +2269,8 @@ def test_07_nuage_internallb_vpc_network_restarts_traffic(self):
         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 07450cf85e0..668dd33cc00 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -133,6 +133,7 @@
     '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 da74cb52daa..4e59f52a8b3 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
@@ -241,6 +241,7 @@
         "traffictype": 'GUEST',
         "ispersistent": 'True',
         "availability": 'Optional',
+        "tags": 'native',
         "serviceProviderList": {
             "Dhcp": 'VirtualRouter',
             "Dns": 'VirtualRouter',
@@ -272,6 +273,7 @@
             "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat",
         "traffictype": "GUEST",
         "availability": "Optional'",
+        "tags": "native",
         "serviceProviderList": {
             "Dhcp": "VirtualRouter",
             "Dns": "VirtualRouter",
@@ -312,6 +314,24 @@
     "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"
@@ -387,9 +407,10 @@
         "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",
@@ -466,6 +487,12 @@
             "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",
@@ -602,6 +629,7 @@
         "availability": "Optional",
         "ispersistent": "False",
         "useVpc": "on",
+        "tags": 'native',
         "serviceProviderList": {
             "Dhcp": "VpcVirtualRouter",
             "Dns": "VpcVirtualRouter",
@@ -675,6 +703,25 @@
             "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,
@@ -1869,6 +1916,7 @@
             "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall,Dns',
             "traffictype": 'GUEST',
             "availability": 'Optional',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": 'NuageVsp',
                 "StaticNat": 'NuageVsp',
@@ -1882,6 +1930,70 @@
                     "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',
@@ -1892,6 +2004,7 @@
             "availability": 'Optional',
             "useVpc": 'on',
             "ispersistent": 'True',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": "NuageVsp",
                 "StaticNat": "NuageVsp",
@@ -1912,6 +2025,7 @@
             "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData,Dns',
             "traffictype": 'GUEST',
             "availability": 'Optional',
+            "tags": "nuage",
             "useVpc": 'on',
             "ispersistent": 'True',
             "serviceProviderList": {
@@ -2004,6 +2118,7 @@
             "specifyVlan": "False",
             "specifyIpRanges": "True",
             "availability": 'Optional',
+            "tags": "nuage",
             "serviceProviderList": {
                 "Dhcp": "NuageVsp",
                 "Connectivity": "NuageVsp"
@@ -2018,6 +2133,7 @@
             "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 24133289ed8..8d553c872e1 100644
--- a/tools/marvin/marvin/deployDataCenter.py
+++ b/tools/marvin/marvin/deployDataCenter.py
@@ -456,6 +456,9 @@ def createPhysicalNetwork(self, net, zoneid):
             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 340419a65d2..d8fcb595aa1 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -2240,6 +2240,8 @@ def create(cls, apiclient, services, **kwargs):
             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 @@ def restart(self, apiclient, cleanup=None):
             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 @@ def update(self, apiclient, name=None, displaytext=None):
             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 @@ def list(cls, apiclient, **kwargs):
         [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 dddab4de5ad..bb7f3c5a140 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.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 static boolean isReservedScsiDeviceNumber(int deviceNumber) {
         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 static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEther
 
         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 static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjec
     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;


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


> Physical Networking Migration
> -----------------------------
>
>                 Key: CLOUDSTACK-10024
>                 URL: https://issues.apache.org/jira/browse/CLOUDSTACK-10024
>             Project: CloudStack
>          Issue Type: New Feature
>      Security Level: Public(Anyone can view this level - this is the default.) 
>          Components: API, KVM, Management Server, VMware
>            Reporter: Frank Maximus
>            Assignee: Frank Maximus
>             Fix For: 4.11.0.0
>
>
> *As a* Cloud Owner
> *I want to* migrate my existing guest networks to another physical network infrastructure
> *In order to* leverage new network technologies, e.g. leverage SDN.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


Mime
View raw message