You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/09/07 00:38:37 UTC

[07/36] Moved NetworkManagerImpl to NetworkOrchestrator

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e5bb63f/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
new file mode 100755
index 0000000..1914521
--- /dev/null
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -0,0 +1,3155 @@
+// 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.engine.orchestration;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.lf5.viewer.configure.ConfigurationManager;
+
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.context.ServerContexts;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.DataCenterVnetVO;
+import com.cloud.dc.PodVlanMapVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.DataCenterVnetDao;
+import com.cloud.dc.dao.PodVlanMapDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.domain.Domain;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.ConnectionException;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.UnsupportedServiceException;
+import com.cloud.host.Host;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.IpAddress;
+import com.cloud.network.IpAddress.State;
+import com.cloud.network.IpAddressManager;
+import com.cloud.network.Network;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.Event;
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.NetworkMigrationResponder;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.NetworkProfile;
+import com.cloud.network.Networks.BroadcastDomainType;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.PhysicalNetwork;
+import com.cloud.network.PhysicalNetworkSetupInfo;
+import com.cloud.network.RemoteAccessVpn;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.network.dao.AccountGuestVlanMapDao;
+import com.cloud.network.dao.AccountGuestVlanMapVO;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.LoadBalancerDao;
+import com.cloud.network.dao.NetworkAccountDao;
+import com.cloud.network.dao.NetworkAccountVO;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDomainDao;
+import com.cloud.network.dao.NetworkDomainVO;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.NetworkServiceMapVO;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.dao.UserIpv6AddressDao;
+import com.cloud.network.element.DhcpServiceProvider;
+import com.cloud.network.element.IpDeployer;
+import com.cloud.network.element.LoadBalancingServiceProvider;
+import com.cloud.network.element.NetworkElement;
+import com.cloud.network.element.StaticNatServiceProvider;
+import com.cloud.network.element.UserDataServiceProvider;
+import com.cloud.network.guru.NetworkGuru;
+import com.cloud.network.lb.LoadBalancingRulesManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.rules.LoadBalancerContainer.Scheme;
+import com.cloud.network.rules.PortForwardingRuleVO;
+import com.cloud.network.rules.StaticNatRule;
+import com.cloud.network.rules.dao.PortForwardingRulesDao;
+import com.cloud.network.vpc.dao.PrivateIpDao;
+import com.cloud.network.vpn.RemoteAccessVpnService;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offering.NetworkOffering.Availability;
+import com.cloud.offerings.NetworkOfferingServiceMapVO;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.user.Account;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.User;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.JoinBuilder.JoinType;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.Nic;
+import com.cloud.vm.Nic.ReservationStrategy;
+import com.cloud.vm.NicIpAlias;
+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.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Type;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.NicIpAliasDao;
+import com.cloud.vm.dao.NicIpAliasVO;
+import com.cloud.vm.dao.NicSecondaryIpDao;
+import com.cloud.vm.dao.NicSecondaryIpVO;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+/**
+ * NetworkManagerImpl implements NetworkManager.
+ */
+@Local(value = { NetworkOrchestrationService.class})
+public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestrationService, Listener {
+    static final Logger s_logger = Logger.getLogger(NetworkOrchestrator.class);
+
+    @Inject
+    EntityManager _entityMgr = null;
+    @Inject
+    DataCenterDao _dcDao = null;
+    @Inject
+    VlanDao _vlanDao = null;
+    @Inject
+    IPAddressDao _ipAddressDao = null;
+    @Inject
+    AccountDao _accountDao = null;
+    @Inject
+    ConfigurationDao _configDao;
+    @Inject
+    UserVmDao _userVmDao = null;
+    @Inject
+    AlertManager _alertMgr;
+    @Inject
+    AccountManager _accountMgr;
+    @Inject
+    ConfigurationManager _configMgr;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao = null;
+    @Inject
+    NetworkDao _networksDao = null;
+    @Inject
+    NicDao _nicDao = null;
+    @Inject
+    RulesManager _rulesMgr;
+    @Inject
+    LoadBalancingRulesManager _lbMgr;
+    @Inject
+    RemoteAccessVpnService _vpnMgr;
+    @Inject
+    PodVlanMapDao _podVlanMapDao;
+    @Inject
+    NetworkOfferingDetailsDao _ntwkOffDetailsDao;
+    @Inject
+    ConfigurationServer _configServer;
+    @Inject
+    AccountGuestVlanMapDao _accountGuestVlanMapDao;
+    @Inject
+    DataCenterVnetDao _datacenterVnetDao;
+    @Inject
+    NetworkAccountDao _networkAccountDao;
+    @Inject
+    protected NicIpAliasDao _nicIpAliasDao;
+    @Inject
+    protected IPAddressDao _publicIpAddressDao;
+    @Inject
+    protected IpAddressManager _ipAddrMgr;
+
+    List<NetworkGuru> _networkGurus;
+    public List<NetworkGuru> getNetworkGurus() {
+		return _networkGurus;
+	}
+	public void setNetworkGurus(List<NetworkGuru> _networkGurus) {
+		this._networkGurus = _networkGurus;
+	}
+
+	List<NetworkElement> _networkElements;
+    public List<NetworkElement> getNetworkElements() {
+		return _networkElements;
+	}
+	public void setNetworkElements(List<NetworkElement> _networkElements) {
+		this._networkElements = _networkElements;
+	}
+
+	@Inject NetworkDomainDao _networkDomainDao;
+
+	List<IpDeployer> _ipDeployers;
+    public List<IpDeployer> getIpDeployers() {
+		return _ipDeployers;
+	}
+	public void setIpDeployers(List<IpDeployer> _ipDeployers) {
+		this._ipDeployers = _ipDeployers;
+	}
+
+	List<DhcpServiceProvider> _dhcpProviders;
+    public List<DhcpServiceProvider> getDhcpProviders() {
+		return _dhcpProviders;
+	}
+	public void setDhcpProviders(List<DhcpServiceProvider> _dhcpProviders) {
+		this._dhcpProviders = _dhcpProviders;
+	}
+
+	@Inject
+    VMInstanceDao _vmDao;
+    @Inject
+    FirewallManager _firewallMgr;
+    @Inject
+    FirewallRulesDao _firewallDao;
+    @Inject
+    ResourceLimitService _resourceLimitMgr;
+   
+    @Inject
+    NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    PhysicalNetworkServiceProviderDao _pNSPDao;
+    @Inject
+    PortForwardingRulesDao _portForwardingRulesDao;
+    @Inject
+    LoadBalancerDao _lbDao;
+    @Inject
+    PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
+    @Inject
+    AgentManager _agentMgr;
+    @Inject
+    HostDao _hostDao;
+    @Inject
+    NetworkServiceMapDao _ntwkSrvcDao;
+    @Inject
+    VpcManager _vpcMgr;
+    @Inject
+    PrivateIpDao _privateIpDao;
+    @Inject
+    NetworkACLManager _networkACLMgr;
+    @Inject
+    UsageEventDao _usageEventDao;
+    @Inject
+    NetworkModel _networkModel;
+   @Inject
+    NicSecondaryIpDao _nicSecondaryIpDao;
+    @Inject
+    UserIpv6AddressDao _ipv6Dao;
+    @Inject
+    Ipv6AddressManager _ipv6Mgr;
+    @Inject
+    PortableIpDao _portableIpDao;
+
+    protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
+    ScheduledExecutorService _executor;
+
+    SearchBuilder<IPAddressVO> AssignIpAddressSearch;
+    SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
+
+    int _networkGcWait;
+    int _networkGcInterval;
+    int _networkLockTimeout;
+
+    private Map<String, String> _configs;
+
+    HashMap<Long, Long> _lastNetworkIdsToFree = new HashMap<Long, Long>();
+
+
+
+
+    @Override
+    @DB
+    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
+        _configs = _configDao.getConfiguration("AgentManager", params);
+        _networkGcWait = NumbersUtil.parseInt(_configs.get(Config.NetworkGcWait.key()), 600);
+        _networkGcInterval = NumbersUtil.parseInt(_configs.get(Config.NetworkGcInterval.key()), 600);
+        
+        _configs = _configDao.getConfiguration("Network", params);
+
+        _networkLockTimeout = NumbersUtil.parseInt(_configs.get(Config.NetworkLockTimeout.key()), 600);
+
+        // populate providers
+        Map<Network.Service, Set<Network.Provider>> defaultSharedNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
+
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultSharedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultSharedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultSharedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultIsolatedNetworkOfferingProviders = defaultSharedNetworkOfferingProviders;
+        defaultIsolatedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Lb, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultSharedSGEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        Set<Provider> sgProviders = new HashSet<Provider>();
+        sgProviders.add(Provider.SecurityGroupProvider);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, sgProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultIsolatedSourceNatEnabledNetworkOfferingProviders =
+                new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultProviders.clear();
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Lb, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.SourceNat, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
+
+
+        Map<Network.Service, Set<Network.Provider>> defaultVPCOffProviders =
+                new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultProviders.clear();
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultVPCOffProviders.put(Service.Dhcp, defaultProviders);
+        defaultVPCOffProviders.put(Service.Dns, defaultProviders);
+        defaultVPCOffProviders.put(Service.UserData, defaultProviders);
+        defaultVPCOffProviders.put(Service.NetworkACL, defaultProviders);
+        defaultVPCOffProviders.put(Service.Gateway, defaultProviders);
+        defaultVPCOffProviders.put(Service.Lb, defaultProviders);
+        defaultVPCOffProviders.put(Service.SourceNat, defaultProviders);
+        defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
+        defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
+        defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        NetworkOfferingVO offering = null;
+        //#1 - quick cloud network offering
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) {
+            offering =
+                    _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices,
+                            "Offering for QuickCloud with no services", TrafficType.Guest, null, true,
+                            Availability.Optional, null, new HashMap<Network.Service, Set<Network.Provider>>(), true,
+                            Network.GuestType.Shared, false, null, true, null, true, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+        
+        //#2 - SG enabled network offering
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) {
+            offering =
+                    _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService,
+                            "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true,
+                            Availability.Optional, null, defaultSharedNetworkOfferingProviders, true,
+                            Network.GuestType.Shared, false, null, true, null, true, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        //#3 - shared network offering with no SG service
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null,
+                    defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+        
+
+        //#4 - default isolated offering with Source nat service
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService,
+                    "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest,
+                    null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders,
+                    true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null);
+
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        //#5 - default vpc offering with LB service
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks,
+                    "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest,
+                    null, false, Availability.Optional, null, defaultVPCOffProviders,
+                    true, Network.GuestType.Isolated, false, null, false, null, false, false, null,false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        //#6 - default vpc offering with no LB service
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB) == null) {
+            //remove LB service
+            defaultVPCOffProviders.remove(Service.Lb);
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB,
+                    "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest,
+                    null, false, Availability.Optional, null, defaultVPCOffProviders,
+                    true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        //#7 - isolated offering with source nat disabled
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering,
+                    "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true,
+                    Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated,
+                    false, null, true, null, true, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+        
+        //#8 - network offering with internal lb service
+        Map<Network.Service, Set<Network.Provider>> internalLbOffProviders =
+                new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> defaultVpcProvider = new HashSet<Network.Provider>();
+        defaultVpcProvider.add(Network.Provider.VPCVirtualRouter);
+        
+        Set<Network.Provider> defaultInternalLbProvider = new HashSet<Network.Provider>();
+        defaultInternalLbProvider.add(Network.Provider.InternalLbVm);
+
+        internalLbOffProviders.put(Service.Dhcp, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Dns, defaultVpcProvider);
+        internalLbOffProviders.put(Service.UserData, defaultVpcProvider);
+        internalLbOffProviders.put(Service.NetworkACL, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Gateway, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Lb, defaultInternalLbProvider);
+        internalLbOffProviders.put(Service.SourceNat, defaultVpcProvider);
+        
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB,
+                    "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest,
+                    null, false, Availability.Optional, null, internalLbOffProviders,
+                    true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            offering.setInternalLb(true);
+            offering.setPublicLb(false);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        Map<Network.Service, Set<Network.Provider>> netscalerServiceProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> vrProvider = new HashSet<Network.Provider>();
+        vrProvider.add(Provider.VirtualRouter);
+        Set<Network.Provider> sgProvider = new HashSet<Network.Provider>();
+        sgProvider.add(Provider.SecurityGroupProvider);
+        Set<Network.Provider> nsProvider = new HashSet<Network.Provider>();
+        nsProvider.add(Provider.Netscaler);
+        netscalerServiceProviders.put(Service.Dhcp, vrProvider);
+        netscalerServiceProviders.put(Service.Dns, vrProvider);
+        netscalerServiceProviders.put(Service.UserData, vrProvider);
+        netscalerServiceProviders.put(Service.SecurityGroup, sgProvider);
+        netscalerServiceProviders.put(Service.StaticNat, nsProvider);
+        netscalerServiceProviders.put(Service.Lb, nsProvider);
+
+        Map<Service, Map<Capability, String>> serviceCapabilityMap = new HashMap<Service, Map<Capability, String>>();
+        Map<Capability, String> elb = new HashMap<Capability, String>();
+        elb.put(Capability.ElasticLb, "true");
+        Map<Capability, String> eip = new HashMap<Capability, String>();
+        eip.put(Capability.ElasticIp, "true");
+        serviceCapabilityMap.put(Service.Lb, elb);
+        serviceCapabilityMap.put(Service.StaticNat, eip);
+
+        if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) {
+            offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true,
+                    Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null);
+            offering.setState(NetworkOffering.State.Enabled);
+            offering.setDedicatedLB(false);
+            _networkOfferingDao.update(offering.getId(), offering);
+        }
+
+        txn.commit();
+
+       
+        AssignIpAddressSearch = _ipAddressDao.createSearchBuilder();
+        AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
+        AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
+        AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
+        SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
+        vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
+        vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
+        AssignIpAddressSearch.join("vlan", vlanSearch, vlanSearch.entity().getId(), AssignIpAddressSearch.entity().getVlanId(), JoinType.INNER);
+        AssignIpAddressSearch.done();
+
+        AssignIpAddressFromPodVlanSearch = _ipAddressDao.createSearchBuilder();
+        AssignIpAddressFromPodVlanSearch.and("dc", AssignIpAddressFromPodVlanSearch.entity().getDataCenterId(), Op.EQ);
+        AssignIpAddressFromPodVlanSearch.and("allocated", AssignIpAddressFromPodVlanSearch.entity().getAllocatedTime(), Op.NULL);
+        AssignIpAddressFromPodVlanSearch.and("vlanId", AssignIpAddressFromPodVlanSearch.entity().getVlanId(), Op.IN);
+
+        SearchBuilder<VlanVO> podVlanSearch = _vlanDao.createSearchBuilder();
+        podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ);
+        podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ);
+        SearchBuilder<PodVlanMapVO> podVlanMapSB = _podVlanMapDao.createSearchBuilder();
+        podVlanMapSB.and("podId", podVlanMapSB.entity().getPodId(), Op.EQ);
+        AssignIpAddressFromPodVlanSearch.join("podVlanMapSB", podVlanMapSB, podVlanMapSB.entity().getVlanDbId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
+        AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
+        
+                       
+        AssignIpAddressFromPodVlanSearch.done();
+
+        _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Network-Scavenger"));
+
+        _agentMgr.registerForHostEvents(this, true, false, true);
+
+        Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao));
+
+        s_logger.info("Network Manager is configured.");
+
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        _executor.scheduleWithFixedDelay(new NetworkGarbageCollector(), _networkGcInterval, _networkGcInterval, TimeUnit.SECONDS);
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    protected NetworkOrchestrator() {
+        setStateMachine();
+    }
+
+    @Override
+    public List<? extends Network> setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name,
+            String displayText, boolean isDefault)
+            throws ConcurrentOperationException {
+        return setupNetwork(owner, offering, null, plan, name, displayText, false, null, null, null, null, true);
+    }
+
+    @Override
+    @DB
+    public List<? extends Network> setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan
+            plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId,
+            ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException {
+
+        Account locked = _accountDao.acquireInLockTable(owner.getId());
+        if (locked == null) {
+            throw new ConcurrentOperationException("Unable to acquire lock on " + owner);
+        }
+
+        try {
+            if (predefined == null
+                    || (offering.getTrafficType() != TrafficType.Guest && predefined.getCidr() == null && predefined.getBroadcastUri() == null &&
+                    !(predefined.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch))) {
+                List<NetworkVO> configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId());
+                if (configs.size() > 0) {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Found existing network configuration for offering " + offering + ": " + configs.get(0));
+                    }
+
+                    if (errorIfAlreadySetup) {
+                        InvalidParameterValueException ex = new InvalidParameterValueException("Found existing network configuration (with specified id) for offering (with specified id)");
+                        ex.addProxyObject(offering.getUuid(), "offeringId");
+                        ex.addProxyObject(configs.get(0).getUuid(), "networkConfigId");
+                        throw ex;
+                    } else {
+                        return configs;
+                    }
+                }
+            }
+
+            List<NetworkVO> networks = new ArrayList<NetworkVO>();
+
+            long related = -1;
+
+            for (NetworkGuru guru : _networkGurus) {
+                Network network = guru.design(offering, plan, predefined, owner);
+                if (network == null) {
+                    continue;
+                }
+
+                if (network.getId() != -1) {
+                    if (network instanceof NetworkVO) {
+                        networks.add((NetworkVO) network);
+                    } else {
+                        networks.add(_networksDao.findById(network.getId()));
+                    }
+                    continue;
+                }
+
+                long id = _networksDao.getNextInSequence(Long.class, "id");
+                if (related == -1) {
+                    related = id;
+                }
+
+                Transaction txn = Transaction.currentTxn();
+                txn.start();
+
+                NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(),
+                        related, name, displayText, predefined.getNetworkDomain(), offering.getGuestType(),
+                        plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.getSpecifyIpRanges(), vpcId);
+                vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled);
+                networks.add(_networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated,
+                        finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId())));
+
+                if (domainId != null && aclType == ACLType.Domain) {
+    		    if (subdomainAccess == null ) {
+                        subdomainAccess = true;
+         	    }
+                    _networksDao.addDomainToNetwork(id, domainId, subdomainAccess);
+                }
+
+                txn.commit();
+            }
+
+            if (networks.size() < 1) {
+                // see networkOfferingVO.java
+                CloudRuntimeException ex = new CloudRuntimeException("Unable to convert network offering with specified id to network profile");
+                ex.addProxyObject(offering.getUuid(), "offeringId");
+                throw ex;
+            }
+
+            return networks;
+        } finally {
+            s_logger.debug("Releasing lock for " + locked);
+            _accountDao.releaseFromLockTable(locked.getId());
+        }
+    }
+
+    
+
+    @Override
+    @DB
+    public void allocate(VirtualMachineProfile vm, LinkedHashMap<? extends Network, ? extends NicProfile> networks)
+            throws InsufficientCapacityException, ConcurrentOperationException {
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        int deviceId = 0;
+
+        boolean[] deviceIds = new boolean[networks.size()];
+        Arrays.fill(deviceIds, false);
+
+        List<NicProfile> nics = new ArrayList<NicProfile>(networks.size());
+        NicProfile defaultNic = null;
+
+        for (Map.Entry<? extends Network, ? extends NicProfile> network : networks.entrySet()) {
+            Network config = network.getKey();
+            NicProfile requested = network.getValue();
+
+            Boolean isDefaultNic = false;
+            if (vm != null && (requested != null && requested.isDefaultNic())) {
+                isDefaultNic = true;
+            }
+
+            while (deviceIds[deviceId] && deviceId < deviceIds.length) {
+                deviceId++;
+            }
+
+            Pair<NicProfile,Integer> vmNicPair = allocateNic(requested, config, isDefaultNic,
+                    deviceId, vm);
+
+            NicProfile vmNic = vmNicPair.first();
+            if (vmNic == null) {
+                continue;
+            }
+
+            deviceId = vmNicPair.second();
+
+            int devId = vmNic.getDeviceId();
+            if (devId > deviceIds.length) {
+                throw new IllegalArgumentException("Device id for nic is too large: " + vmNic);
+            }
+            if (deviceIds[devId]) {
+                throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic);
+            }
+
+            deviceIds[devId] = true;
+
+            if (vmNic.isDefaultNic()) {
+                if (defaultNic != null) {
+                    throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " +
+                defaultNic + "; nic 2 = " + vmNic);
+                }
+                defaultNic = vmNic;
+            }
+
+            nics.add(vmNic);
+            vm.addNic(vmNic);
+
+        }
+
+        if (nics.size() != networks.size()) {
+            s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size());
+            throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + networks.size());
+        }
+
+        if (nics.size() == 1) {
+            nics.get(0).setDefaultNic(true);
+        }
+
+        txn.commit();
+    }
+
+
+    @DB
+    @Override
+    public Pair<NicProfile,Integer> allocateNic(NicProfile requested, Network network, Boolean isDefaultNic,
+            int deviceId, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapcityException,
+            InsufficientAddressCapacityException, ConcurrentOperationException{
+
+        NetworkVO ntwkVO = _networksDao.findById(network.getId());
+        s_logger.debug("Allocating nic for vm " + vm.getVirtualMachine() + " in network " + network + " with requested profile " + requested);
+        NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, ntwkVO.getGuruName());
+
+        if (requested != null && requested.getMode() == null) {
+            requested.setMode(network.getMode());
+        }
+        NicProfile profile = guru.allocate(network, requested, vm);
+        if (isDefaultNic != null) {
+            profile.setDefaultNic(isDefaultNic);
+        }
+
+        if (profile == null) {
+            return null;
+        }
+
+        if (requested != null && requested.getMode() == null) {
+            profile.setMode(requested.getMode());
+        } else {
+            profile.setMode(network.getMode());
+        }
+
+        NicVO vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType());
+
+        deviceId = applyProfileToNic(vo, profile, deviceId);
+
+        vo = _nicDao.persist(vo);
+    
+        Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
+        NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate,
+                _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(),
+                network));
+
+        return new Pair<NicProfile,Integer>(vmNic, Integer.valueOf(deviceId));
+    }
+
+    protected Integer applyProfileToNic(NicVO vo, NicProfile profile, Integer deviceId) {
+        if (profile.getDeviceId() != null) {
+            vo.setDeviceId(profile.getDeviceId());
+        } else if (deviceId != null) {
+            vo.setDeviceId(deviceId++);
+        }
+
+        if (profile.getReservationStrategy() != null) {
+            vo.setReservationStrategy(profile.getReservationStrategy());
+        }
+
+        vo.setDefaultNic(profile.isDefaultNic());
+
+        vo.setIp4Address(profile.getIp4Address());
+        vo.setAddressFormat(profile.getFormat());
+
+        if (profile.getMacAddress() != null) {
+            vo.setMacAddress(profile.getMacAddress());
+        }
+
+        vo.setMode(profile.getMode());
+        vo.setNetmask(profile.getNetmask());
+        vo.setGateway(profile.getGateway());
+
+        if (profile.getBroadCastUri() != null) {
+            vo.setBroadcastUri(profile.getBroadCastUri());
+        }
+
+        if (profile.getIsolationUri() != null) {
+            vo.setIsolationUri(profile.getIsolationUri());
+        }
+
+        vo.setState(Nic.State.Allocated);
+        
+        vo.setIp6Address(profile.getIp6Address());
+        vo.setIp6Gateway(profile.getIp6Gateway());
+        vo.setIp6Cidr(profile.getIp6Cidr());
+        
+        return deviceId;
+    }
+
+    protected void applyProfileToNicForRelease(NicVO vo, NicProfile profile) {
+        vo.setGateway(profile.getGateway());
+        vo.setAddressFormat(profile.getFormat());
+        vo.setIp4Address(profile.getIp4Address());
+        vo.setIp6Address(profile.getIp6Address());
+        vo.setMacAddress(profile.getMacAddress());
+        if (profile.getReservationStrategy() != null) {
+            vo.setReservationStrategy(profile.getReservationStrategy());
+        }
+        vo.setBroadcastUri(profile.getBroadCastUri());
+        vo.setIsolationUri(profile.getIsolationUri());
+        vo.setNetmask(profile.getNetmask());
+    }
+
+    protected void applyProfileToNetwork(NetworkVO network, NetworkProfile profile) {
+        network.setBroadcastUri(profile.getBroadcastUri());
+        network.setDns1(profile.getDns1());
+        network.setDns2(profile.getDns2());
+        network.setPhysicalNetworkId(profile.getPhysicalNetworkId());
+    }
+
+    protected NicTO toNicTO(NicVO nic, NicProfile profile, NetworkVO config) {
+        NicTO to = new NicTO();
+        to.setDeviceId(nic.getDeviceId());
+        to.setBroadcastType(config.getBroadcastDomainType());
+        to.setType(config.getTrafficType());
+        to.setIp(nic.getIp4Address());
+        to.setNetmask(nic.getNetmask());
+        to.setMac(nic.getMacAddress());
+        to.setDns1(profile.getDns1());
+        to.setDns2(profile.getDns2());
+        if (nic.getGateway() != null) {
+            to.setGateway(nic.getGateway());
+        } else {
+            to.setGateway(config.getGateway());
+        }
+        to.setDefaultNic(nic.isDefaultNic());
+        to.setBroadcastUri(nic.getBroadcastUri());
+        to.setIsolationuri(nic.getIsolationUri());
+        if (profile != null) {
+            to.setDns1(profile.getDns1());
+            to.setDns2(profile.getDns2());
+        }
+
+        Integer networkRate = _networkModel.getNetworkRate(config.getId(), null);
+        to.setNetworkRateMbps(networkRate);
+
+        to.setUuid(config.getUuid());
+
+        return to;
+    }
+
+    boolean isNetworkImplemented(NetworkVO network) {
+        Network.State state = network.getState();
+        if (state == Network.State.Implemented || state == Network.State.Implementing) {
+            return true;
+        } else if (state == Network.State.Setup) {
+            DataCenterVO zone = _dcDao.findById(network.getDataCenterId());
+            if (!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) || (zone.getNetworkType() == NetworkType.Basic)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    @DB
+    public Pair<NetworkGuru, NetworkVO> implementNetwork(long networkId, DeployDestination dest, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException,
+            InsufficientCapacityException {
+        Transaction.currentTxn();
+        Pair<NetworkGuru, NetworkVO> implemented = new Pair<NetworkGuru, NetworkVO>(null, null);
+
+        NetworkVO network = _networksDao.findById(networkId);
+        NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+        if (isNetworkImplemented(network)) {
+            s_logger.debug("Network id=" + networkId + " is already implemented");
+            implemented.set(guru, network);
+            return implemented;
+        }
+
+        // Acquire lock only when network needs to be implemented
+        network = _networksDao.acquireInLockTable(networkId, _networkLockTimeout);
+        if (network == null) {
+            // see NetworkVO.java
+            ConcurrentOperationException ex = new ConcurrentOperationException("Unable to acquire network configuration");
+            ex.addProxyObject(ApiDBUtils.findNetworkById(networkId).getUuid());
+            throw ex;
+        }
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Lock is acquired for network id " + networkId + " as a part of network implement");
+        }
+
+        try {
+            if (isNetworkImplemented(network)) {
+                s_logger.debug("Network id=" + networkId + " is already implemented");
+                implemented.set(guru, network);
+                return implemented;
+            }
+
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Asking " + guru.getName() + " to implement " + network);
+            }
+
+            NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
+
+            network.setReservationId(context.getReservationId());
+            if (isSharedNetworkWithServices(network)) {
+                network.setState(Network.State.Implementing);
+            } else {
+                stateTransitTo(network, Event.ImplementNetwork);
+            }
+
+            Network result = guru.implement(network, offering, dest, context);
+            network.setCidr(result.getCidr());
+            network.setBroadcastUri(result.getBroadcastUri());
+            network.setGateway(result.getGateway());
+            network.setMode(result.getMode());
+            network.setPhysicalNetworkId(result.getPhysicalNetworkId());
+            _networksDao.update(networkId, network);
+
+            // implement network elements and re-apply all the network rules
+            implementNetworkElementsAndResources(dest, context, network, offering);
+
+            if (isSharedNetworkWithServices(network)) {
+                network.setState(Network.State.Implemented);
+            } else {
+                stateTransitTo(network,Event.OperationSucceeded);
+            }
+
+            network.setRestartRequired(false);
+            _networksDao.update(network.getId(), network);
+            implemented.set(guru, network);
+            return implemented;
+        } catch (NoTransitionException e) {
+            s_logger.error(e.getMessage());
+            return null;
+        } finally {
+            if (implemented.first() == null) {
+                s_logger.debug("Cleaning up because we're unable to implement the network " + network);
+                try {
+                    if (isSharedNetworkWithServices(network)) {
+                        network.setState(Network.State.Shutdown);
+                        _networksDao.update(networkId, network);
+                    } else {
+                        stateTransitTo(network,Event.OperationFailed);
+                    }
+                } catch (NoTransitionException e) {
+                    s_logger.error(e.getMessage());
+                }
+
+                shutdownNetwork(networkId, context, false);
+            }
+
+            _networksDao.releaseFromLockTable(networkId);
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Lock is released for network id " + networkId + " as a part of network implement");
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return super.equals(o);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void implementNetworkElementsAndResources(DeployDestination dest, ReservationContext context,
+ Network network, NetworkOffering offering)
+            throws ConcurrentOperationException, InsufficientAddressCapacityException, ResourceUnavailableException, InsufficientCapacityException {
+
+        // Associate a source NAT IP (if one isn't already associated with the network) if this is a
+        //     1) 'Isolated' or 'Shared' guest virtual network in the advance zone
+        //     2) network has sourceNat service
+        //     3) network offering does not support a shared source NAT rule
+
+        boolean sharedSourceNat = offering.getSharedSourceNat();
+        DataCenter zone = _dcDao.findById(network.getDataCenterId());
+
+        if (!sharedSourceNat && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat)
+                && (network.getGuestType() == Network.GuestType.Isolated ||
+                (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) {
+
+            List<IPAddressVO> ips = null;
+            if (network.getVpcId() != null) {
+                ips = _ipAddressDao.listByAssociatedVpc(network.getVpcId(), true);
+                if (ips.isEmpty()) {
+                    throw new CloudRuntimeException("Vpc is not implemented; there is no source nat ip");
+                }
+            } else {
+                ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true);
+            }
+
+            if (ips.isEmpty()) {
+                s_logger.debug("Creating a source nat ip for network " + network);
+                Account owner = _accountMgr.getAccount(network.getAccountId());
+                _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network);
+            }
+        }
+
+        // get providers to implement
+        List<Provider> providersToImplement = getNetworkProviders(network.getId());
+        for (NetworkElement element : _networkElements) {
+            if (providersToImplement.contains(element.getProvider())) {
+                if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                    // The physicalNetworkId will not get translated into a uuid by the reponse serializer,
+                    // because the serializer would look up the NetworkVO class's table and retrieve the
+                    // network id instead of the physical network id.
+                    // So just throw this exception as is. We may need to TBD by changing the serializer.
+                    throw new CloudRuntimeException("Service provider " + element.getProvider().getName() +
+                            " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Asking " + element.getName() + " to implemenet " + network);
+                }
+
+                if (!element.implement(network, offering, dest, context)) {
+                    CloudRuntimeException ex = new CloudRuntimeException("Failed to implement provider " + element.getProvider().getName() + " for network with specified id");
+                    ex.addProxyObject(network.getUuid(), "networkId");
+                    throw ex;
+                }
+            }
+        }
+
+        // reapply all the firewall/staticNat/lb rules
+        s_logger.debug("Reprogramming network " + network + " as a part of network implement");
+        if (!reprogramNetworkRules(network.getId(), CallContext.current().getCallingAccount(), network)) {
+            s_logger.warn("Failed to re-program the network as a part of network " + network + " implement");
+            // see DataCenterVO.java
+            ResourceUnavailableException ex = new ResourceUnavailableException("Unable to apply network rules as a part of network " + network + " implement", DataCenter.class, network.getDataCenterId());
+            ex.addProxyObject(ApiDBUtils.findZoneById(network.getDataCenterId()).getUuid());
+            throw ex;
+        }
+    }
+
+    // This method re-programs the rules/ips for existing network
+    protected boolean reprogramNetworkRules(long networkId, Account caller, Network network) throws ResourceUnavailableException {
+        boolean success = true;
+        // associate all ip addresses
+        if (!_ipAddrMgr.applyIpAssociations(network, false)) {
+            s_logger.warn("Failed to apply ip addresses as a part of network id" + networkId + " restart");
+            success = false;
+        }
+
+        // apply static nat
+        if (!_rulesMgr.applyStaticNatsForNetwork(networkId, false, caller)) {
+            s_logger.warn("Failed to apply static nats a part of network id" + networkId + " restart");
+            success = false;
+        }
+
+        // apply firewall rules
+        List<FirewallRuleVO> firewallIngressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Ingress);
+        if (!_firewallMgr.applyFirewallRules(firewallIngressRulesToApply, false, caller)) {
+            s_logger.warn("Failed to reapply Ingress firewall rule(s) as a part of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        List<FirewallRuleVO> firewallEgressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress);
+        if (firewallEgressRulesToApply.size() == 0) {
+            NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
+            //there are no egress rules then apply the default egress rule
+            DataCenter zone = _dcDao.findById(network.getDataCenterId());
+            if (offering.getEgressDefaultPolicy() && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.Firewall) &&
+                (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) {
+                // add default egress rule to accept the traffic
+                _firewallMgr.applyDefaultEgressFirewallRule(network.getId(), true);
+            }
+        } else {
+            if (!_firewallMgr.applyFirewallRules(firewallEgressRulesToApply, false, caller)) {
+                s_logger.warn("Failed to reapply firewall Egress rule(s) as a part of network id=" + networkId + " restart");
+                success = false;
+            }
+        }
+
+        // apply port forwarding rules
+        if (!_rulesMgr.applyPortForwardingRulesForNetwork(networkId, false, caller)) {
+            s_logger.warn("Failed to reapply port forwarding rule(s) as a part of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        // apply static nat rules
+        if (!_rulesMgr.applyStaticNatRulesForNetwork(networkId, false, caller)) {
+            s_logger.warn("Failed to reapply static nat rule(s) as a part of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        // apply public load balancer rules
+        if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) {
+            s_logger.warn("Failed to reapply Public load balancer rules as a part of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        // apply internal load balancer rules
+        if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Internal)) {
+            s_logger.warn("Failed to reapply internal load balancer rules as a part of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        // apply vpn rules
+        List<? extends RemoteAccessVpn> vpnsToReapply = _vpnMgr.listRemoteAccessVpns(networkId);
+        if (vpnsToReapply != null) {
+            for (RemoteAccessVpn vpn : vpnsToReapply) {
+                // Start remote access vpn per ip
+                if (_vpnMgr.startRemoteAccessVpn(vpn.getServerAddressId(), false) == null) {
+                    s_logger.warn("Failed to reapply vpn rules as a part of network id=" + networkId + " restart");
+                    success = false;
+                }
+            }
+        }
+
+        //apply network ACLs
+        if (!_networkACLMgr.applyACLToNetwork(networkId)) {
+            s_logger.warn("Failed to reapply network ACLs as a part of  of network id=" + networkId + " restart");
+            success = false;
+        }
+
+        return success;
+    }
+
+    protected boolean prepareElement(NetworkElement element, Network network,
+            NicProfile profile, VirtualMachineProfile vmProfile,
+            DeployDestination dest, ReservationContext context) throws InsufficientCapacityException,
+            ConcurrentOperationException, ResourceUnavailableException {
+        element.prepare(network, profile, vmProfile, dest, context);
+        if (vmProfile.getType() == Type.User && element.getProvider() != null) {
+            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) &&
+                    _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) &&
+                    element instanceof DhcpServiceProvider ) {
+                DhcpServiceProvider sp = (DhcpServiceProvider) element;
+                Map <Capability, String> dhcpCapabilities = element.getCapabilities().get(Service.Dhcp);
+                String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets);
+                if ((supportsMultipleSubnets != null && Boolean.valueOf(supportsMultipleSubnets)) && profile.getIp6Address() == null) {
+                    if (!sp.configDhcpSupportForSubnet(network, profile, vmProfile, dest, context)) {
+                        return false;
+                    }
+                }
+                sp.addDhcpEntry(network, profile, vmProfile, dest, context);
+            }
+            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData) &&
+                    _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) &&
+                    element instanceof UserDataServiceProvider) {
+                UserDataServiceProvider sp = (UserDataServiceProvider) element;
+                sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context);
+            }
+        }
+        return true;
+    }
+
+    @DB
+    protected void updateNic(NicVO nic, long networkId, int count) {
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        _nicDao.update(nic.getId(), nic);
+
+        if (nic.getVmType() == VirtualMachine.Type.User) {
+            s_logger.debug("Changing active number of nics for network id=" + networkId + " on " + count);
+            _networksDao.changeActiveNicsBy(networkId, count);
+        }
+
+        if (nic.getVmType() == VirtualMachine.Type.User || (nic.getVmType() == VirtualMachine.Type.DomainRouter && _networksDao.findById(networkId).getTrafficType() == TrafficType.Guest)) {
+            _networksDao.setCheckForGc(networkId);
+        }
+
+        txn.commit();
+    }
+
+    @Override
+    public void prepare(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException,
+            ConcurrentOperationException, ResourceUnavailableException {
+        List<NicVO> nics = _nicDao.listByVmId(vmProfile.getId());
+
+        // we have to implement default nics first - to ensure that default network elements start up first in multiple
+        //nics case
+        // (need for setting DNS on Dhcp to domR's Ip4 address)
+        Collections.sort(nics, new Comparator<NicVO>() {
+
+            @Override
+            public int compare(NicVO nic1, NicVO nic2) {
+                boolean isDefault1 = nic1.isDefaultNic();
+                boolean isDefault2 = nic2.isDefaultNic();
+
+                return (isDefault1 ^ isDefault2) ? ((isDefault1 ^ true) ? 1 : -1) : 0;
+            }
+        });
+
+        for (NicVO nic : nics) {
+            Pair<NetworkGuru, NetworkVO> implemented = implementNetwork(nic.getNetworkId(), dest, context);
+            if (implemented.first() == null) {
+                s_logger.warn("Failed to implement network id=" + nic.getNetworkId() + " as a part of preparing nic id=" + nic.getId());
+                throw new CloudRuntimeException("Failed to implement network id=" + nic.getNetworkId() + " as a part preparing nic id=" +nic.getId());
+            }
+
+            NetworkVO network = implemented.second();
+            NicProfile profile = prepareNic(vmProfile, dest, context, nic.getId(), network);
+            vmProfile.addNic(profile);
+        }
+    }
+
+    @Override
+    public NicProfile prepareNic(VirtualMachineProfile vmProfile, DeployDestination
+ dest, ReservationContext context, long nicId, Network network)
+            throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
+            ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
+        
+        Integer networkRate = _networkModel.getNetworkRate(network.getId(), vmProfile.getId());
+        NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+        NicVO nic = _nicDao.findById(nicId);
+
+        NicProfile profile = null;
+        if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
+            nic.setState(Nic.State.Reserving);
+            nic.setReservationId(context.getReservationId());
+            _nicDao.update(nic.getId(), nic);
+            URI broadcastUri = nic.getBroadcastUri();
+            if (broadcastUri == null) {
+                broadcastUri = network.getBroadcastUri();
+            }
+
+            URI isolationUri = nic.getIsolationUri();
+
+            profile = new NicProfile(nic, network, broadcastUri, isolationUri,
+
+            networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network));
+            guru.reserve(profile, network, vmProfile, dest, context);
+            nic.setIp4Address(profile.getIp4Address());
+            nic.setAddressFormat(profile.getFormat());
+            nic.setIp6Address(profile.getIp6Address());
+            nic.setMacAddress(profile.getMacAddress());
+            nic.setIsolationUri(profile.getIsolationUri());
+            nic.setBroadcastUri(profile.getBroadCastUri());
+            nic.setReserver(guru.getName());
+            nic.setState(Nic.State.Reserved);
+            nic.setNetmask(profile.getNetmask());
+            nic.setGateway(profile.getGateway());
+
+            if (profile.getStrategy() != null) {
+                nic.setReservationStrategy(profile.getStrategy());
+            }
+
+            updateNic(nic, network.getId(), 1);
+        } else {
+            profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(),
+                        networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network));
+            guru.updateNicProfile(profile, network);
+            nic.setState(Nic.State.Reserved);
+            updateNic(nic, network.getId(), 1);
+        }
+
+        List<Provider> providersToImplement = getNetworkProviders(network.getId());
+        for (NetworkElement element : _networkElements) {
+            if (providersToImplement.contains(element.getProvider())) {
+                if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                    throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                }
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Asking " + element.getName() + " to prepare for " + nic);
+                }
+                if(!prepareElement(element, network, profile, vmProfile, dest, context)) {
+                    throw new InsufficientAddressCapacityException("unable to configure the dhcp service, due to insufficiant address capacity",Network.class, network.getId());
+                }
+            }
+        }
+
+        profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network));
+        guru.updateNicProfile(profile, network);
+        return profile;
+    }
+
+    @Override
+    public void prepareNicForMigration(VirtualMachineProfile vm, DeployDestination dest) {
+        List<NicVO> nics = _nicDao.listByVmId(vm.getId());
+        ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), null, null);
+        for (NicVO nic : nics) {
+            NetworkVO network = _networksDao.findById(nic.getNetworkId());
+            Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
+
+            NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+            NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate,
+                    _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network));
+            if(guru instanceof NetworkMigrationResponder){
+                if(!((NetworkMigrationResponder) guru).prepareMigration(profile, network, vm, dest, context)){
+                    s_logger.error("NetworkGuru "+guru+" prepareForMigration failed."); // XXX: Transaction error
+                }
+            }
+            List<Provider> providersToImplement = getNetworkProviders(network.getId());
+            for (NetworkElement element : _networkElements) {
+                if (providersToImplement.contains(element.getProvider())) {
+                    if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                        throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                    }
+                    if(element instanceof NetworkMigrationResponder){
+                        if(!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)){
+                            s_logger.error("NetworkElement "+element+" prepareForMigration failed."); // XXX: Transaction error
+                        }
+                    }
+                }
+            }
+            guru.updateNicProfile(profile, network);
+            vm.addNic(profile);
+        }
+    }
+
+    private NicProfile findNicProfileById(VirtualMachineProfile vm, long id){
+        for(NicProfile nic: vm.getNics()){
+            if(nic.getId() == id){
+                return nic;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void commitNicForMigration(
+            VirtualMachineProfile src,
+            VirtualMachineProfile dst) {
+        for(NicProfile nicSrc: src.getNics()){
+            NetworkVO network = _networksDao.findById(nicSrc.getNetworkId());
+            NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+            NicProfile nicDst = findNicProfileById(dst, nicSrc.getId());
+            ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null);
+            ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null);
+
+            if(guru instanceof NetworkMigrationResponder){
+                ((NetworkMigrationResponder) guru).commitMigration(nicSrc, network, src, src_context, dst_context);
+            }
+            List<Provider> providersToImplement = getNetworkProviders(network.getId());
+            for (NetworkElement element : _networkElements) {
+                if (providersToImplement.contains(element.getProvider())) {
+                    if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                        throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                    }
+                    if(element instanceof NetworkMigrationResponder){
+                        ((NetworkMigrationResponder) element).commitMigration(nicSrc, network, src, src_context, dst_context);
+                    }
+                }
+            }
+            // update the reservation id
+            NicVO nicVo = _nicDao.findById(nicDst.getId());
+            nicVo.setReservationId(nicDst.getReservationId());
+            _nicDao.persist(nicVo);
+        }
+    }
+
+    @Override
+    public void rollbackNicForMigration(
+            VirtualMachineProfile src,
+            VirtualMachineProfile dst) {
+        for(NicProfile nicDst: dst.getNics()){
+            NetworkVO network = _networksDao.findById(nicDst.getNetworkId());
+            NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+            NicProfile nicSrc = findNicProfileById(src, nicDst.getId());
+            ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null);
+            ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null);
+
+            if(guru instanceof NetworkMigrationResponder){
+                ((NetworkMigrationResponder) guru).rollbackMigration(nicDst, network, dst, src_context, dst_context);
+            }
+            List<Provider> providersToImplement = getNetworkProviders(network.getId());
+            for (NetworkElement element : _networkElements) {
+                if (providersToImplement.contains(element.getProvider())) {
+                    if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                        throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                    }
+                    if(element instanceof NetworkMigrationResponder){
+                        ((NetworkMigrationResponder) element).rollbackMigration(nicDst, network, dst, src_context, dst_context);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    @DB
+    public void release(VirtualMachineProfile vmProfile, boolean forced) throws
+            ConcurrentOperationException, ResourceUnavailableException {
+        List<NicVO> nics = _nicDao.listByVmId(vmProfile.getId());
+        for (NicVO nic : nics) {
+            releaseNic(vmProfile, nic.getId());
+        }
+    }
+
+    
+    @Override
+    @DB
+    public void releaseNic(VirtualMachineProfile vmProfile, Nic nic)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        releaseNic(vmProfile, nic.getId());
+    }
+
+    @DB
+    protected void releaseNic(VirtualMachineProfile vmProfile, long nicId)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        //lock the nic
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        NicVO nic = _nicDao.lockRow(nicId, true);
+        if (nic == null) {
+            throw new ConcurrentOperationException("Unable to acquire lock on nic " + nic);
+        }
+
+        Nic.State originalState = nic.getState();
+        NetworkVO network = _networksDao.findById(nic.getNetworkId());
+
+        if (originalState == Nic.State.Reserved || originalState == Nic.State.Reserving) {
+            if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
+                NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+                nic.setState(Nic.State.Releasing);
+                _nicDao.update(nic.getId(), nic);
+                NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null,
+                        _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getHypervisorType(), network));
+                if (guru.release(profile, vmProfile, nic.getReservationId())) {
+                    applyProfileToNicForRelease(nic, profile);
+                    nic.setState(Nic.State.Allocated);
+                    if (originalState == Nic.State.Reserved) {
+                        updateNic(nic, network.getId(), -1);
+                    } else {
+                        _nicDao.update(nic.getId(), nic);
+                    }
+                }
+                //commit the transaction before proceeding releasing nic profile on the network elements
+                txn.commit();
+
+                // Perform release on network elements
+                List<Provider> providersToImplement = getNetworkProviders(network.getId());
+                for (NetworkElement element : _networkElements) {
+                    if (providersToImplement.contains(element.getProvider())) {
+                        if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                            throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                        }
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Asking " + element.getName() + " to release " + nic);
+                        }
+                        //NOTE: Context appear to never be used in release method
+                        //implementations. Consider removing it from interface Element
+                        element.release(network, profile, vmProfile, null);
+                    }
+                }
+
+            } else {
+                nic.setState(Nic.State.Allocated);
+                updateNic(nic, network.getId(), -1);
+                txn.commit();
+            }
+        }
+    }
+
+    @Override
+    public void cleanupNics(VirtualMachineProfile vm) {
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Cleaning network for vm: " + vm.getId());
+        }
+
+        List<NicVO> nics = _nicDao.listByVmId(vm.getId());
+        for (NicVO nic : nics) {
+            removeNic(vm, nic);
+        }
+    }
+
+
+    @Override
+    public void removeNic(VirtualMachineProfile vm, Nic nic) {
+        removeNic(vm, _nicDao.findById(nic.getId()));
+    }
+
+
+    protected void removeNic(VirtualMachineProfile vm, NicVO nic) {
+        nic.setState(Nic.State.Deallocating);
+        _nicDao.update(nic.getId(), nic);
+        NetworkVO network = _networksDao.findById(nic.getNetworkId());
+        NicProfile profile = new NicProfile(nic, network, null, null, null,
+                _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network));
+
+        /*
+         * We need to release the nics with a Create ReservationStrategy here
+         * because the nic is now being removed.
+         */
+        if (nic.getReservationStrategy() == Nic.ReservationStrategy.Create) {
+            List<Provider> providersToImplement = getNetworkProviders(network.getId());
+            for (NetworkElement element : _networkElements) {
+                if (providersToImplement.contains(element.getProvider())) {
+                    if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
+                        throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId());
+                    }
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Asking " + element.getName() + " to release " + nic);
+                    }
+                    try {
+                        element.release(network, profile, vm, null);
+                    } catch (ConcurrentOperationException ex) {
+                        s_logger.warn("release failed during the nic " +  nic.toString() + " removeNic due to ", ex);
+                    } catch (ResourceUnavailableException ex) {
+                        s_logger.warn("release failed during the nic " +  nic.toString() + " removeNic due to ", ex);
+                    }
+                }
+            }
+        }
+
+        // remove the dhcpservice ip if this is the last nic in subnet.
+        if (vm.getType() == Type.User && isDhcpAccrossMultipleSubnetsSupported(network) && isLastNicInSubnet(nic) &&
+                   network.getTrafficType() == TrafficType.Guest && network.getGuestType() == GuestType.Shared) {
+            removeDhcpServiceInSubnet(nic);
+        }
+        NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
+        guru.deallocate(network, profile, vm);
+        _nicDao.remove(nic.getId());
+        s_logger.debug("Removed nic id=" + nic.getId());
+        //remove the secondary ip addresses corresponding to to this nic
+        if (!removeVmSecondaryIpsOfNic(nic.getId())) {
+            s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed");
+        }
+    }
+
+    public boolean isDhcpAccrossMultipleSubnetsSupported(Network network) {
+        DhcpServiceProvider dhcpServiceProvider = getDhcpServiceProvider(network);
+        Map <Network.Capability, String> capabilities = dhcpServiceProvider.getCapabilities().get(Network.Service.Dhcp);
+        String supportsMultipleSubnets = capabilities.get(Network.Capability.DhcpAccrossMultipleSubnets);
+        if (supportsMultipleSubnets != null && Boolean.valueOf(supportsMultipleSubnets)) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isLastNicInSubnet(NicVO nic) {
+        if (_nicDao.listByNetworkIdTypeAndGatewayAndBroadcastUri(nic.getNetworkId(), VirtualMachine.Type.User, nic.getGateway(), nic.getBroadcastUri()).size() > 1) {
+              return false;
+        }
+        return true;
+    }
+
+    @DB
+    @Override
+    public void removeDhcpServiceInSubnet(Nic nic) {
+        Network network = _networksDao.findById(nic.getNetworkId());
+        DhcpServiceProvider dhcpServiceProvider = getDhcpServiceProvider(network);
+        try {
+            NicIpAliasVO ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(nic.getGateway(), network.getId(), NicIpAlias.state.active);
+            if (ipAlias != null) {
+                ipAlias.setState(NicIpAlias.state.revoked);
+                Transaction txn = Transaction.currentTxn();
+                txn.start();
+                _nicIpAliasDao.update(ipAlias.getId(),ipAlias);
+                IPAddressVO aliasIpaddressVo = _publicIpAddressDao.findByIpAndSourceNetworkId(ipAlias.getNetworkId(), ipAlias.getIp4Address());
+                _publicIpAddressDao.unassignIpAddress(aliasIpaddressVo.getId());
+                txn.commit();
+                if (!dhcpServiceProvider.removeDhcpSupportForSubnet(network)) {
+                    s_logger.warn("Failed to remove the ip alias on the router, marking it as removed in db and freed the allocated ip " + ipAlias.getIp4Address());
+                }
+            }
+        }
+        catch (ResourceUnavailableException e) {
+            //failed to remove the dhcpconfig on the router.
+            s_logger.info ("Unable to delete the ip alias due to unable to contact the virtualrouter.");
+        }
+
+    }
+
+
+
+    @Override
+    public void expungeNics(VirtualMachineProfile vm) {
+        List<NicVO> nics = _nicDao.listByVmIdIncludingRemoved(vm.getId());
+        for (NicVO nic : nics) {
+            _nicDao.expunge(nic.getId());
+        }
+    }
+
+   
+
+    @Override
+    @DB
+    public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway,
+                                      String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
+                                      PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
+                                      Boolean isDisplayNetworkEnabled, String isolatedPvlan)
+                    throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
+
+        NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
+        // this method supports only guest network creation
+        if (ntwkOff.getTrafficType() != TrafficType.Guest) {
+            s_logger.warn("Only guest networks can be created using this method");
+            return null;
+        }
+
+        boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, aclType);
+        //check resource limits
+        if (updateResourceCount) {
+            _resourceLimitMgr.checkResourceLimit(owner, ResourceType.network);
+        }
+
+        // Validate network offering
+        if (ntwkOff.getState() != NetworkOffering.State.Enabled) {
+            // see NetworkOfferingVO
+            InvalidParameterValueException ex = new InvalidParameterValueException("Can't use specified network offering id as its stat is not " + NetworkOffering.State.Enabled);
+            ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId");
+            throw ex;
+        }
+
+        // Validate physical network
+        if (pNtwk.getState() != PhysicalNetwork.State.Enabled) {
+            // see PhysicalNetworkVO.java
+            InvalidParameterValueException ex = new InvalidParameterValueException("Specified physical network id is" +
+                    " in incorrect state:" + pNtwk.getState());
+            ex.addProxyObject(pNtwk.getUuid(), "physicalNetworkId");
+            throw ex;
+        }
+
+        boolean ipv6 = false;
+        
+        if (ip6Gateway != null && ip6Cidr != null) {
+        	ipv6 = true;
+        }
+        // Validate zone
+        DataCenterVO zone = _dcDao.findById(zoneId);
+        if (zone.getNetworkType() == NetworkType.Basic) {
+        	if (ipv6) {
+                throw new InvalidParameterValueException("IPv6 is not supported in Basic zone");
+        	}
+        	
+            // In Basic zone the network should have aclType=Domain, domainId=1, subdomainAccess=true
+            if (aclType == null || aclType != ACLType.Domain) {
+                throw new InvalidParameterValueException("Only AclType=Domain can be specified for network creation in Basic zone");
+            }
+
+            // Only one guest network is supported in Basic zone
+            List<NetworkVO> guestNetworks = _networksDao.listByZoneAndTrafficType(zone.getId(), TrafficType.Guest);
+            if (!guestNetworks.isEmpty()) {
+                throw new InvalidParameterValueException("Can't have more than one Guest network in zone with network type "
+                                                        + NetworkType.Basic);
+            }
+
+            // if zone is basic, only Shared network offerings w/o source nat service are allowed
+            if (!(ntwkOff.getGuestType() == GuestType.Shared &&
+                    !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))) {
+                throw new InvalidParameterValueException("For zone of type " + NetworkType.Basic + " only offerings of " +
+                        "guestType " + GuestType.Shared + " with disabled " + Service.SourceNat.getName()
+                        + " service are allowed");
+            }
+
+            if (domainId == null || domainId != Domain.ROOT_DOMAIN) {
+                throw new InvalidParameterValueException("Guest network in Basic zone should be dedicated to ROOT domain");
+            }
+
+            if (subdomainAccess == null) {
+                subdomainAccess = true;
+            } else if (!subdomainAccess) {
+                throw new InvalidParameterValueException("Subdomain access should be set to true for the" +
+                        " guest network in the Basic zone");
+            }
+
+            if (vlanId == null) {
+                vlanId = Vlan.UNTAGGED;
+            } else {
+                if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) {
+                    throw new InvalidParameterValueException("Only vlan " + Vlan.UNTAGGED + " can be created in " +
+                            "the zone of type " + NetworkType.Basic);
+                }
+            }
+
+        } else if (zone.getNetworkType() == NetworkType.Advanced) {
+            if (zone.isSecurityGroupEnabled()) {
+            	if (ipv6) {
+            		throw new InvalidParameterValueException("IPv6 is not supported with security group!");
+            	}
+            	if (isolatedPvlan != null) {
+            		throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!");
+            	}
+                // Only Account specific Isolated network with sourceNat service disabled are allowed in security group
+                // enabled zone
+                if ( ntwkOff.getGuestType() != GuestType.Shared ){
+                    throw new InvalidParameterValueException("Only shared guest network can be created in security group enabled zone");
+                }
+                if ( _networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)) {
+                    throw new InvalidParameterValueException("Service SourceNat is not allowed in security group enabled zone");
+                }
+                if (!( _networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SecurityGroup))) {
+                    throw new InvalidParameterValueException("network must have SecurityGroup provider in security group enabled zone");
+                }
+            }
+
+            //don't allow eip/elb networks in Advance zone
+            if (ntwkOff.getElasticIp() || ntwkOff.getElasticLb()) {
+                throw new InvalidParameterValueException("Elastic IP and Elastic LB services are supported in zone of type " + NetworkType.Basic);
+            }
+        }
+
+        // VlanId can be specified only when network offering supports it
+        boolean vlanSpecified = (vlanId != null);
+        if (vlanSpecified != ntwkOff.getSpecifyVlan()) {
+            if (vlanSpecified) {
+                throw new InvalidParameterValueException("Can't specify vlan; corresponding offering says specifyVlan=false");
+            } else {
+                throw new InvalidParameterValueException("Vlan has to be specified; corresponding offering says specifyVlan=true");
+            }
+        }
+
+        if (vlanSpecified) {
+            //don't allow to specify vlan tag used by physical network for dynamic vlan allocation
+            if (_dcDao.findVnet(zoneId, pNtwk.getId(), vlanId).size() > 0) {
+                throw new InvalidParameterValueException("The VLAN tag " + vlanId
+                        + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName());
+            }
+            
+            String uri = BroadcastDomainType.fromString(vlanId).toString();
+            // For Isolated networks, don't allow to create network with vlan that already exists in the zone
+            if (ntwkOff.getGuestType() == GuestType.Isolated) {
+                if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) {
+                    throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId);
+                } else {
+                    List<DataCenterVnetVO> dcVnets = _datacenterVnetDao.findVnet(zoneId, vlanId.toString());
+                    //for the network that is created as part of private gateway,
+                    //the vnet is not coming from the data center vnet table, so the list can be empty
+                    if (!dcVnets.isEmpty()) {
+                        DataCenterVnetVO dcVnet = dcVnets.get(0);
+                        // Fail network creation if specified vlan is dedicated to a different account
+                        if (dcVnet.getAccountGuestVlanMapId() != null) {
+                            Long accountGuestVlanMapId = dcVnet.getAccountGuestVlanMapId();
+                            AccountGuestVlanMapVO map = _accountGuestVlanMapDao.findById(accountGuestVlanMapId);
+                            if (map

<TRUNCATED>