You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/10/17 15:01:31 UTC

[cloudstack] branch master updated (e871638 -> 233f46c)

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

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


    from e871638  Merge remote-tracking branch 'origin/4.11'
     add 5ce14df  network: Allow ability to disable rolling restart feature (#2900)
     new 233f46c  Merge remote-tracking branch 'origin/4.11'

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../orchestration/service/NetworkOrchestrationService.java     |  3 +++
 .../cloudstack/engine/orchestration/NetworkOrchestrator.java   | 10 +++++++++-
 server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java |  7 +++++++
 3 files changed, 19 insertions(+), 1 deletion(-)


[cloudstack] 01/01: Merge remote-tracking branch 'origin/4.11'

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 233f46c94b0b792d3f674cda120066a97e04c8ea
Merge: e871638 5ce14df
Author: Rohit Yadav <ro...@shapeblue.com>
AuthorDate: Wed Oct 17 20:29:58 2018 +0530

    Merge remote-tracking branch 'origin/4.11'
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>

 .../orchestration/service/NetworkOrchestrationService.java     |  3 +++
 .../cloudstack/engine/orchestration/NetworkOrchestrator.java   | 10 +++++++++-
 server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java |  7 +++++++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --cc engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index b61e7c2,0000000..35069c5
mode 100644,000000..100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@@ -1,3836 -1,0 +1,3844 @@@
 +// 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.LinkedList;
 +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 java.util.stream.Collectors;
 +
 +import javax.inject.Inject;
 +import javax.naming.ConfigurationException;
 +
 +import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 +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.framework.config.ConfigKey;
 +import org.apache.cloudstack.framework.config.ConfigKey.Scope;
 +import org.apache.cloudstack.framework.config.Configurable;
 +import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 +import org.apache.cloudstack.framework.messagebus.MessageBus;
 +import org.apache.cloudstack.framework.messagebus.PublishScope;
 +import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 +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.CheckNetworkAnswer;
 +import com.cloud.agent.api.CheckNetworkCommand;
 +import com.cloud.agent.api.Command;
 +import com.cloud.agent.api.StartupCommand;
 +import com.cloud.agent.api.StartupRoutingCommand;
 +import com.cloud.agent.api.routing.NetworkElementCommand;
 +import com.cloud.agent.api.to.NicTO;
 +import com.cloud.alert.AlertManager;
 +import com.cloud.configuration.ConfigurationManager;
 +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.exception.ConcurrentOperationException;
 +import com.cloud.exception.ConnectionException;
 +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.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.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.NetworkStateListener;
 +import com.cloud.network.Networks;
 +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.VpcVirtualNetworkApplianceService;
 +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.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.RemoteAccessVpnDao;
 +import com.cloud.network.dao.RemoteAccessVpnVO;
 +import com.cloud.network.element.AggregatedCommandExecutor;
 +import com.cloud.network.element.DhcpServiceProvider;
 +import com.cloud.network.element.DnsServiceProvider;
 +import com.cloud.network.element.IpDeployer;
 +import com.cloud.network.element.LoadBalancingServiceProvider;
 +import com.cloud.network.element.NetworkElement;
 +import com.cloud.network.element.RedundantResource;
 +import com.cloud.network.element.StaticNatServiceProvider;
 +import com.cloud.network.element.UserDataServiceProvider;
 +import com.cloud.network.guru.NetworkGuru;
 +import com.cloud.network.guru.NetworkGuruAdditionalFunctions;
 +import com.cloud.network.lb.LoadBalancingRulesManager;
 +import com.cloud.network.router.VirtualRouter;
 +import com.cloud.network.rules.FirewallManager;
 +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.RulesManager;
 +import com.cloud.network.rules.StaticNatRule;
 +import com.cloud.network.rules.StaticNatRuleImpl;
 +import com.cloud.network.rules.dao.PortForwardingRulesDao;
 +import com.cloud.network.vpc.NetworkACLManager;
 +import com.cloud.network.vpc.Vpc;
 +import com.cloud.network.vpc.VpcManager;
 +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.StringUtils;
 +import com.cloud.utils.UuidUtils;
 +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.db.TransactionCallback;
 +import com.cloud.utils.db.TransactionCallbackNoReturn;
 +import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 +import com.cloud.utils.db.TransactionStatus;
 +import com.cloud.utils.exception.CloudRuntimeException;
 +import com.cloud.utils.fsm.NoTransitionException;
 +import com.cloud.utils.fsm.StateMachine2;
 +import com.cloud.utils.net.Dhcp;
 +import com.cloud.utils.net.NetUtils;
 +import com.cloud.vm.DomainRouterVO;
 +import com.cloud.vm.Nic;
 +import com.cloud.vm.Nic.ReservationStrategy;
 +import com.cloud.vm.NicExtraDhcpOptionVO;
 +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.DomainRouterDao;
 +import com.cloud.vm.dao.NicDao;
 +import com.cloud.vm.dao.NicExtraDhcpOptionDao;
 +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;
 +import com.google.common.base.Strings;
 +
 +/**
 + * NetworkManagerImpl implements NetworkManager.
 + */
 +public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestrationService, Listener, Configurable {
 +    static final Logger s_logger = Logger.getLogger(NetworkOrchestrator.class);
 +
 +    @Inject
 +    EntityManager _entityMgr;
 +    @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
 +    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
 +    AccountGuestVlanMapDao _accountGuestVlanMapDao;
 +    @Inject
 +    DataCenterVnetDao _datacenterVnetDao;
 +    @Inject
 +    NetworkAccountDao _networkAccountDao;
 +    @Inject
 +    protected NicIpAliasDao _nicIpAliasDao;
 +    @Inject
 +    protected NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
 +    @Inject
 +    protected IPAddressDao _publicIpAddressDao;
 +    @Inject
 +    protected IpAddressManager _ipAddrMgr;
 +    @Inject
 +    MessageBus _messageBus;
 +    @Inject
 +    VMNetworkMapDao _vmNetworkMapDao;
 +    @Inject
 +    DomainRouterDao _routerDao;
 +    @Inject
 +    RemoteAccessVpnDao _remoteAccessVpnDao;
 +    @Inject
 +    VpcVirtualNetworkApplianceService _routerService;
 +
 +    List<NetworkGuru> networkGurus;
 +
 +    @Override
 +    public List<NetworkGuru> getNetworkGurus() {
 +        return networkGurus;
 +    }
 +
 +    public void setNetworkGurus(final List<NetworkGuru> networkGurus) {
 +        this.networkGurus = networkGurus;
 +    }
 +
 +    List<NetworkElement> networkElements;
 +
 +    public List<NetworkElement> getNetworkElements() {
 +        return networkElements;
 +    }
 +
 +    public void setNetworkElements(final List<NetworkElement> networkElements) {
 +        this.networkElements = networkElements;
 +    }
 +
 +    @Inject
 +    NetworkDomainDao _networkDomainDao;
 +
 +    List<IpDeployer> ipDeployers;
 +
 +    public List<IpDeployer> getIpDeployers() {
 +        return ipDeployers;
 +    }
 +
 +    public void setIpDeployers(final List<IpDeployer> ipDeployers) {
 +        this.ipDeployers = ipDeployers;
 +    }
 +
 +    List<DhcpServiceProvider> _dhcpProviders;
 +
 +    public List<DhcpServiceProvider> getDhcpProviders() {
 +        return _dhcpProviders;
 +    }
 +
 +    public void setDhcpProviders(final List<DhcpServiceProvider> dhcpProviders) {
 +        _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
 +    PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
 +    @Inject
 +    AgentManager _agentMgr;
 +    @Inject
 +    HostDao _hostDao;
 +    @Inject
 +    NetworkServiceMapDao _ntwkSrvcDao;
 +    @Inject
 +    VpcManager _vpcMgr;
 +    @Inject
 +    PrivateIpDao _privateIpDao;
 +    @Inject
 +    NetworkACLManager _networkACLMgr;
 +    @Inject
 +    NetworkModel _networkModel;
 +    @Inject
 +    NicSecondaryIpDao _nicSecondaryIpDao;
 +
 +    protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
 +    ScheduledExecutorService _executor;
 +
 +    SearchBuilder<IPAddressVO> AssignIpAddressSearch;
 +    SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
 +
 +    HashMap<Long, Long> _lastNetworkIdsToFree = new HashMap<Long, Long>();
 +
 +    @Override
 +    @DB
 +    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
 +        // populate providers
 +        final Map<Network.Service, Set<Network.Provider>> defaultSharedNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
 +        final 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);
 +
 +        final 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);
 +
 +        final 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);
 +        final Set<Provider> sgProviders = new HashSet<Provider>();
 +        sgProviders.add(Provider.SecurityGroupProvider);
 +        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, sgProviders);
 +
 +        final 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);
 +
 +        final Map<Network.Service, Set<Network.Provider>> defaultVPCOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
 +        defaultProviders.clear();
 +        defaultProviders.add(Network.Provider.VPCVirtualRouter);
 +        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.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                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, true, false);
 +                    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, true, false);
 +                    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, true, false);
 +                    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,
 +                            true, false);
 +
 +                    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, true, true);
 +                    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, true, true);
 +                    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, true, false);
 +                    offering.setState(NetworkOffering.State.Enabled);
 +                    _networkOfferingDao.update(offering.getId(), offering);
 +                }
 +
 +                //#8 - network offering with internal lb service
 +                final Map<Network.Service, Set<Network.Provider>> internalLbOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
 +                final Set<Network.Provider> defaultVpcProvider = new HashSet<Network.Provider>();
 +                defaultVpcProvider.add(Network.Provider.VPCVirtualRouter);
 +
 +                final 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, true, true);
 +                    offering.setState(NetworkOffering.State.Enabled);
 +                    offering.setInternalLb(true);
 +                    offering.setPublicLb(false);
 +                    _networkOfferingDao.update(offering.getId(), offering);
 +                }
 +
 +                final Map<Network.Service, Set<Network.Provider>> netscalerServiceProviders = new HashMap<Network.Service, Set<Network.Provider>>();
 +                final Set<Network.Provider> vrProvider = new HashSet<Network.Provider>();
 +                vrProvider.add(Provider.VirtualRouter);
 +                final Set<Network.Provider> sgProvider = new HashSet<Network.Provider>();
 +                sgProvider.add(Provider.SecurityGroupProvider);
 +                final 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);
 +
 +                final Map<Service, Map<Capability, String>> serviceCapabilityMap = new HashMap<Service, Map<Capability, String>>();
 +                final Map<Capability, String> elb = new HashMap<Capability, String>();
 +                elb.put(Capability.ElasticLb, "true");
 +                final 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, true, false);
 +                    offering.setState(NetworkOffering.State.Enabled);
 +                    offering.setDedicatedLB(false);
 +                    _networkOfferingDao.update(offering.getId(), offering);
 +                }
 +
 +                _networkOfferingDao.persistDefaultL2NetworkOfferings();
 +            }
 +        });
 +
 +        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);
 +        final 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);
 +
 +        final SearchBuilder<VlanVO> podVlanSearch = _vlanDao.createSearchBuilder();
 +        podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ);
 +        podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ);
 +        final 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(_configDao));
 +
 +        s_logger.info("Network Manager is configured.");
 +
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean start() {
 +        final int netGcInterval = NumbersUtil.parseInt(_configDao.getValue(NetworkGcInterval.key()), 60);
 +        s_logger.info("Network Manager will run the NetworkGarbageCollector every '" + netGcInterval + "' seconds.");
 +
 +        _executor.scheduleWithFixedDelay(new NetworkGarbageCollector(), netGcInterval, netGcInterval, TimeUnit.SECONDS);
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean stop() {
 +        return true;
 +    }
 +
 +    protected NetworkOrchestrator() {
 +        setStateMachine();
 +    }
 +
 +    @Override
 +    public List<? extends Network> setupNetwork(final Account owner, final NetworkOffering offering, final DeploymentPlan plan, final String name, final String displayText, final 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(final Account owner, final NetworkOffering offering, final Network predefined, final DeploymentPlan plan, final String name,
 +            final String displayText, final boolean errorIfAlreadySetup, final Long domainId, final ACLType aclType, final Boolean subdomainAccess, final Long vpcId,
 +            final Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException {
 +
 +        final 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 || predefined
 +                            .getBroadcastDomainType() == BroadcastDomainType.Vxlan)) {
 +                final 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) {
 +                        final 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;
 +                    }
 +                }
 +            }
 +
 +            final List<NetworkVO> networks = new ArrayList<NetworkVO>();
 +
 +            long related = -1;
 +
 +            for (final NetworkGuru guru : networkGurus) {
 +                final 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;
 +                }
 +
 +                final long id = _networksDao.getNextInSequence(Long.class, "id");
 +                if (related == -1) {
 +                    related = id;
 +                }
 +
 +                final long relatedFile = related;
 +                Transaction.execute(new TransactionCallbackNoReturn() {
 +                    @Override
 +                    public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                        final NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), relatedFile, name, displayText, predefined
 +                                .getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.isSpecifyIpRanges(),
 +                                vpcId, offering.isRedundantRouter(), predefined.getExternalId());
 +                        vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled);
 +                        vo.setStrechedL2Network(offering.isSupportingStrechedL2());
 +                        final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated,
 +                                finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId()));
 +                        networks.add(networkPersisted);
 +
 +                        if (predefined instanceof NetworkVO && guru instanceof NetworkGuruAdditionalFunctions){
 +                            final NetworkGuruAdditionalFunctions functions = (NetworkGuruAdditionalFunctions) guru;
 +                            functions.finalizeNetworkDesign(networkPersisted.getId(), ((NetworkVO)predefined).getVlanIdAsUUID());
 +                        }
 +
 +                        if (domainId != null && aclType == ACLType.Domain) {
 +                            _networksDao.addDomainToNetwork(id, domainId, subdomainAccess == null ? true : subdomainAccess);
 +                        }
 +                    }
 +                });
 +            }
 +
 +            if (networks.size() < 1) {
 +                // see networkOfferingVO.java
 +                final 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(final VirtualMachineProfile vm, final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final Map<String, Map<Integer, String>> extraDhcpOptions) throws InsufficientCapacityException,
 +    ConcurrentOperationException {
 +
 +        Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
 +                int deviceId = 0;
 +                int size = 0;
 +                for (final Network ntwk : networks.keySet()) {
 +                    final List<? extends NicProfile> profiles = networks.get(ntwk);
 +                    if (profiles != null && !profiles.isEmpty()) {
 +                        size = size + profiles.size();
 +                    } else {
 +                        size = size + 1;
 +                    }
 +                }
 +
 +                final boolean[] deviceIds = new boolean[size];
 +                Arrays.fill(deviceIds, false);
 +
 +                final List<NicProfile> nics = new ArrayList<NicProfile>(size);
 +                NicProfile defaultNic = null;
 +
 +                for (final Map.Entry<? extends Network, List<? extends NicProfile>> network : networks.entrySet()) {
 +                    final Network config = network.getKey();
 +                    List<? extends NicProfile> requestedProfiles = network.getValue();
 +                    if (requestedProfiles == null) {
 +                        requestedProfiles = new ArrayList<NicProfile>();
 +                    }
 +                    if (requestedProfiles.isEmpty()) {
 +                        requestedProfiles.add(null);
 +                    }
 +
 +                    for (final NicProfile requested : requestedProfiles) {
 +                        Boolean isDefaultNic = false;
 +                        if (vm != null && requested != null && requested.isDefaultNic()) {
 +                            isDefaultNic = true;
 +                        }
 +
 +                        while (deviceIds[deviceId] && deviceId < deviceIds.length) {
 +                            deviceId++;
 +                        }
 +
 +                        final Pair<NicProfile, Integer> vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm);
 +                        NicProfile vmNic = null;
 +                        if (vmNicPair != null) {
 +                            vmNic = vmNicPair.first();
 +                            if (vmNic == null) {
 +                                continue;
 +                            }
 +                            deviceId = vmNicPair.second();
 +                        }
 +
 +                        final 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);
 +                        saveExtraDhcpOptions(config.getUuid(), vmNic.getId(), extraDhcpOptions);
 +                    }
 +                }
 +                if (nics.size() != size) {
 +                    s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size);
 +                    throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size);
 +                }
 +
 +                if (nics.size() == 1) {
 +                    nics.get(0).setDefaultNic(true);
 +                }
 +            }
 +        });
 +    }
 +
 +    @Override
 +    public void saveExtraDhcpOptions(final String networkUuid, final Long nicId, final Map<String, Map<Integer, String>> extraDhcpOptionMap) {
 +
 +        if(extraDhcpOptionMap != null) {
 +            Map<Integer, String> extraDhcpOption = extraDhcpOptionMap.get(networkUuid);
 +            if(extraDhcpOption != null) {
 +                List<NicExtraDhcpOptionVO> nicExtraDhcpOptionList = new LinkedList<>();
 +
 +                for (Integer code : extraDhcpOption.keySet()) {
 +                    Dhcp.DhcpOptionCode.valueOfInt(code); //check if code is supported or not.
 +                    NicExtraDhcpOptionVO nicExtraDhcpOptionVO = new NicExtraDhcpOptionVO(nicId, code, extraDhcpOption.get(code));
 +                    nicExtraDhcpOptionList.add(nicExtraDhcpOptionVO);
 +                }
 +                _nicExtraDhcpOptionDao.saveExtraDhcpOptions(nicExtraDhcpOptionList);
 +            }
 +        }
 +    }
 +
 +    @DB
 +    @Override
 +    public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
 +            throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException {
 +
 +        final NetworkVO ntwkVO = _networksDao.findById(network.getId());
 +        s_logger.debug("Allocating nic for vm " + vm.getVirtualMachine() + " in network " + network + " with requested profile " + requested);
 +        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, ntwkVO.getGuruName());
 +
 +        if (requested != null && requested.getMode() == null) {
 +            requested.setMode(network.getMode());
 +        }
 +        final NicProfile profile = guru.allocate(network, requested, vm);
 +        if (profile == null) {
 +            return null;
 +        }
 +
 +        if (isDefaultNic != null) {
 +            profile.setDefaultNic(isDefaultNic);
 +        }
 +
 +        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);
 +
 +        final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
 +        final 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(final NicVO vo, final 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.setIPv4Address(profile.getIPv4Address());
 +        vo.setAddressFormat(profile.getFormat());
 +
 +        if (profile.getMacAddress() != null) {
 +            vo.setMacAddress(profile.getMacAddress());
 +        }
 +
 +        vo.setMode(profile.getMode());
 +        vo.setIPv4Netmask(profile.getIPv4Netmask());
 +        vo.setIPv4Gateway(profile.getIPv4Gateway());
 +
 +        if (profile.getBroadCastUri() != null) {
 +            vo.setBroadcastUri(profile.getBroadCastUri());
 +        }
 +
 +        if (profile.getIsolationUri() != null) {
 +            vo.setIsolationUri(profile.getIsolationUri());
 +        }
 +
 +        vo.setState(Nic.State.Allocated);
 +
 +        vo.setIPv6Address(profile.getIPv6Address());
 +        vo.setIPv6Gateway(profile.getIPv6Gateway());
 +        vo.setIPv6Cidr(profile.getIPv6Cidr());
 +
 +        return deviceId;
 +    }
 +
 +    protected void applyProfileToNicForRelease(final NicVO vo, final NicProfile profile) {
 +        vo.setIPv4Gateway(profile.getIPv4Gateway());
 +        vo.setAddressFormat(profile.getFormat());
 +        vo.setIPv4Address(profile.getIPv4Address());
 +        vo.setIPv6Address(profile.getIPv6Address());
 +        vo.setMacAddress(profile.getMacAddress());
 +        if (profile.getReservationStrategy() != null) {
 +            vo.setReservationStrategy(profile.getReservationStrategy());
 +        }
 +        vo.setBroadcastUri(profile.getBroadCastUri());
 +        vo.setIsolationUri(profile.getIsolationUri());
 +        vo.setIPv4Netmask(profile.getIPv4Netmask());
 +    }
 +
 +    protected void applyProfileToNetwork(final NetworkVO network, final NetworkProfile profile) {
 +        network.setBroadcastUri(profile.getBroadcastUri());
 +        network.setDns1(profile.getDns1());
 +        network.setDns2(profile.getDns2());
 +        network.setPhysicalNetworkId(profile.getPhysicalNetworkId());
 +    }
 +
 +    protected NicTO toNicTO(final NicVO nic, final NicProfile profile, final NetworkVO config) {
 +        final NicTO to = new NicTO();
 +        to.setDeviceId(nic.getDeviceId());
 +        to.setBroadcastType(config.getBroadcastDomainType());
 +        to.setType(config.getTrafficType());
 +        to.setIp(nic.getIPv4Address());
 +        to.setNetmask(nic.getIPv4Netmask());
 +        to.setMac(nic.getMacAddress());
 +        to.setDns1(profile.getIPv4Dns1());
 +        to.setDns2(profile.getIPv4Dns2());
 +        if (nic.getIPv4Gateway() != null) {
 +            to.setGateway(nic.getIPv4Gateway());
 +        } else {
 +            to.setGateway(config.getGateway());
 +        }
 +        if (nic.getVmType() != VirtualMachine.Type.User) {
 +            to.setPxeDisable(true);
 +        }
 +        to.setDefaultNic(nic.isDefaultNic());
 +        to.setBroadcastUri(nic.getBroadcastUri());
 +        to.setIsolationuri(nic.getIsolationUri());
 +        if (profile != null) {
 +            to.setDns1(profile.getIPv4Dns1());
 +            to.setDns2(profile.getIPv4Dns2());
 +        }
 +
 +        final Integer networkRate = _networkModel.getNetworkRate(config.getId(), null);
 +        to.setNetworkRateMbps(networkRate);
 +
 +        to.setUuid(config.getUuid());
 +
 +        return to;
 +    }
 +
 +    boolean isNetworkImplemented(final NetworkVO network) {
 +        final Network.State state = network.getState();
 +        if (state == Network.State.Implemented) {
 +            return true;
 +        } else if (state == Network.State.Setup) {
 +            final DataCenterVO zone = _dcDao.findById(network.getDataCenterId());
 +            if (!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) || zone.getNetworkType() == NetworkType.Basic) {
 +                return true;
 +            }
 +        }
 +        return false;
 +    }
 +
 +    Pair<NetworkGuru, NetworkVO> implementNetwork(final long networkId, final DeployDestination dest, final ReservationContext context, final boolean isRouter) throws ConcurrentOperationException,
 +    ResourceUnavailableException, InsufficientCapacityException {
 +        Pair<NetworkGuru, NetworkVO> implemented = null;
 +        if (!isRouter) {
 +            implemented = implementNetwork(networkId, dest, context);
 +        } else {
 +            // At the time of implementing network (using implementNetwork() method), if the VR needs to be deployed then
 +            // it follows the same path of regular VM deployment. This leads to a nested call to implementNetwork() while
 +            // preparing VR nics. This flow creates issues in dealing with network state transitions. The original call
 +            // puts network in "Implementing" state and then the nested call again tries to put it into same state resulting
 +            // in issues. In order to avoid it, implementNetwork() call for VR is replaced with below code.
 +            final NetworkVO network = _networksDao.findById(networkId);
 +            final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +            implemented = new Pair<NetworkGuru, NetworkVO>(guru, network);
 +        }
 +        return implemented;
 +    }
 +
 +    @Override
 +    @DB
 +    public Pair<NetworkGuru, NetworkVO> implementNetwork(final long networkId, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException,
 +    ResourceUnavailableException, InsufficientCapacityException {
 +        final Pair<NetworkGuru, NetworkVO> implemented = new Pair<NetworkGuru, NetworkVO>(null, null);
 +
 +        NetworkVO network = _networksDao.findById(networkId);
 +        final 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.value());
 +        if (network == null) {
 +            // see NetworkVO.java
 +            final ConcurrentOperationException ex = new ConcurrentOperationException("Unable to acquire network configuration");
 +            ex.addProxyObject(_entityMgr.findById(Network.class, 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);
 +            }
 +
 +            final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
 +
 +            network.setReservationId(context.getReservationId());
 +            if (isSharedNetworkWithServices(network)) {
 +                network.setState(Network.State.Implementing);
 +            } else {
 +                stateTransitTo(network, Event.ImplementNetwork);
 +            }
 +
 +            final 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 (final NoTransitionException e) {
 +            s_logger.error(e.getMessage());
 +            return null;
 +        } catch (final CloudRuntimeException e) {
 +            s_logger.error("Caught exception: " + 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 (final NoTransitionException e) {
 +                    s_logger.error(e.getMessage());
 +                }
 +
 +                try {
 +                    shutdownNetwork(networkId, context, false);
 +                } catch (final Exception e) {
 +                    // Don't throw this exception as it would hide the original thrown exception, just log
 +                    s_logger.error("Exception caught while shutting down a network as part of a failed implementation", e);
 +                }
 +            }
 +
 +            _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 void implementNetworkElementsAndResources(final DeployDestination dest, final ReservationContext context, final Network network, final 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
 +
 +        final boolean sharedSourceNat = offering.isSharedSourceNat();
 +        final 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;
 +            final Account owner = _entityMgr.findById(Account.class, network.getAccountId());
 +            if (network.getVpcId() != null) {
 +                ips = _ipAddressDao.listByAssociatedVpc(network.getVpcId(), true);
 +                if (ips.isEmpty()) {
 +                    final Vpc vpc = _vpcMgr.getActiveVpc(network.getVpcId());
 +                    s_logger.debug("Creating a source nat ip for vpc " + vpc);
 +                    _vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc);
 +                }
 +            } else {
 +                ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true);
 +                if (ips.isEmpty()) {
 +                    s_logger.debug("Creating a source nat ip for network " + network);
 +                    _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network);
 +                }
 +            }
 +        }
 +        // get providers to implement
 +        final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +        implementNetworkElements(dest, context, network, offering, providersToImplement);
 +
 +        //Reset the extra DHCP option that may have been cleared per nic.
 +        List<NicVO> nicVOs = _nicDao.listByNetworkId(network.getId());
 +        for(NicVO nicVO : nicVOs) {
 +            if(nicVO.getState() == Nic.State.Reserved) {
 +                configureExtraDhcpOptions(network, nicVO.getId());
 +            }
 +        }
 +
 +        for (final NetworkElement element : networkElements) {
 +            if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) {
 +                ((AggregatedCommandExecutor)element).prepareAggregatedExecution(network, dest);
 +            }
 +        }
 +
 +        try {
 +            // 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
 +                final ResourceUnavailableException ex = new ResourceUnavailableException("Unable to apply network rules as a part of network " + network + " implement", DataCenter.class,
 +                        network.getDataCenterId());
 +                ex.addProxyObject(_entityMgr.findById(DataCenter.class, network.getDataCenterId()).getUuid());
 +                throw ex;
 +            }
 +            for (final NetworkElement element : networkElements) {
 +                if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) {
 +                    if (!((AggregatedCommandExecutor)element).completeAggregatedExecution(network, dest)) {
 +                        s_logger.warn("Failed to re-program the network as a part of network " + network + " implement due to aggregated commands execution failure!");
 +                        // see DataCenterVO.java
 +                        final ResourceUnavailableException ex = new ResourceUnavailableException("Unable to apply network rules as a part of network " + network + " implement", DataCenter.class,
 +                                network.getDataCenterId());
 +                        ex.addProxyObject(_entityMgr.findById(DataCenter.class, network.getDataCenterId()).getUuid());
 +                        throw ex;
 +                    }
 +                }
 +            }
 +        } finally {
 +            for (final NetworkElement element : networkElements) {
 +                if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) {
 +                    ((AggregatedCommandExecutor)element).cleanupAggregatedExecution(network, dest);
 +                }
 +            }
 +        }
 +    }
 +
 +    private void implementNetworkElements(final DeployDestination dest, final ReservationContext context, final Network network, final NetworkOffering offering, final List<Provider> providersToImplement)
 +            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
 +        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;
 +                }
 +            }
 +        }
 +    }
 +
 +    // This method re-programs the rules/ips for existing network
 +    protected boolean reprogramNetworkRules(final long networkId, final Account caller, final Network network) throws ResourceUnavailableException {
 +        boolean success = true;
 +
 +        //Apply egress rules first to effect the egress policy early on the guest traffic
 +        final List<FirewallRuleVO> firewallEgressRulesToApply = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress);
 +        final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
 +        final DataCenter zone = _dcDao.findById(network.getDataCenterId());
 +        if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Firewall) && _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(), offering.isEgressDefaultPolicy(), true);
 +        }
 +        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;
 +        }
 +
 +        // 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
 +        final 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;
 +        }
 +
 +        // 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
 +        final List<? extends RemoteAccessVpn> vpnsToReapply = _vpnMgr.listRemoteAccessVpns(networkId);
 +        if (vpnsToReapply != null) {
 +            for (final 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(final NetworkElement element, final Network network, final NicProfile profile, final VirtualMachineProfile vmProfile, final DeployDestination dest,
 +            final 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) {
 +                final DhcpServiceProvider sp = (DhcpServiceProvider)element;
 +                if (isDhcpAccrossMultipleSubnetsSupported(sp)) {
 +                    if (!sp.configDhcpSupportForSubnet(network, profile, vmProfile, dest, context)) {
 +                        return false;
 +                    }
 +                }
 +                if(!sp.addDhcpEntry(network, profile, vmProfile, dest, context)) {
 +                    return false;
 +                }
 +            }
 +            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dns)
 +                    && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, element.getProvider()) && element instanceof DnsServiceProvider) {
 +                final DnsServiceProvider sp = (DnsServiceProvider)element;
 +                if (profile.getIPv6Address() == null) {
 +                    if (!sp.configDnsSupportForSubnet(network, profile, vmProfile, dest, context)) {
 +                        return false;
 +                    }
 +                }
 +                if(!sp.addDnsEntry(network, profile, vmProfile, dest, context)) {
 +                    return false;
 +                }
 +            }
 +            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData)
 +                    && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) && element instanceof UserDataServiceProvider) {
 +                final UserDataServiceProvider sp = (UserDataServiceProvider)element;
 +                if(!sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context)){
 +                    return false;
 +                }
 +            }
 +        }
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean canUpdateInSequence(Network network, boolean forced){
 +        List<Provider> providers = getNetworkProviders(network.getId());
 +
 +        //check if the there are no service provider other than virtualrouter.
 +        for(Provider provider : providers) {
 +            if (provider != Provider.VirtualRouter)
 +                throw new UnsupportedOperationException("Cannot update the network resources in sequence when providers other than virtualrouter are used");
 +        }
 +        //check if routers are in correct state before proceeding with the update
 +        List<DomainRouterVO> routers = _routerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER);
 +        for (DomainRouterVO router : routers){
 +            if (router.getRedundantState() == VirtualRouter.RedundantState.UNKNOWN) {
 +                if (!forced) {
 +                    throw new CloudRuntimeException("Domain router: "+router.getInstanceName()+" is in unknown state, Cannot update network. set parameter forced to true for forcing an update");
 +                }
 +            }
 +        }
 +        return true;
 +    }
 +
 +    @Override
 +    public List<String> getServicesNotSupportedInNewOffering(Network network,long newNetworkOfferingId){
 +        NetworkOffering offering =_networkOfferingDao.findById(newNetworkOfferingId);
 +        List<String> services=_ntwkOfferingSrvcDao.listServicesForNetworkOffering(offering.getId());
 +        List<NetworkServiceMapVO> serviceMap= _ntwkSrvcDao.getServicesInNetwork(network.getId());
 +        List<String> servicesNotInNewOffering=new ArrayList<>();
 +        for(NetworkServiceMapVO serviceVO :serviceMap){
 +            boolean inlist=false;
 +            for(String service: services){
 +                if(serviceVO.getService().equalsIgnoreCase(service)){
 +                    inlist=true;
 +                    break;
 +                }
 +            }
 +            if(!inlist){
 +                //ignore Gateway service as this has no effect on the
 +                //behaviour of network.
 +                if(!serviceVO.getService().equalsIgnoreCase(Service.Gateway.getName()))
 +                    servicesNotInNewOffering.add(serviceVO.getService());
 +            }
 +        }
 +        return servicesNotInNewOffering;
 +    }
 +
 +    @Override
 +    public void cleanupConfigForServicesInNetwork(List<String> services, final Network network){
 +        long networkId=network.getId();
 +        Account caller=_accountDao.findById(Account.ACCOUNT_ID_SYSTEM);
 +        long userId=User.UID_SYSTEM;
 +        //remove all PF/Static Nat rules for the network
 +        s_logger.info("Services:"+services+" are no longer supported in network:"+network.getUuid()+
 +                " after applying new network offering:"+network.getNetworkOfferingId()+" removing the related configuration");
 +        if(services.contains(Service.StaticNat.getName())|| services.contains(Service.PortForwarding.getName())) {
 +            try {
 +                if (_rulesMgr.revokeAllPFStaticNatRulesForNetwork(networkId, userId, caller)) {
 +                    s_logger.debug("Successfully cleaned up portForwarding/staticNat rules for network id=" + networkId);
 +                } else {
 +                    s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup");
 +                }
 +                if(services.contains(Service.StaticNat.getName())){
 +                    //removing static nat configured on ips.
 +                    //optimizing the db operations using transaction.
 +                    Transaction.execute(new TransactionCallbackNoReturn() {
 +                        @Override
 +                        public void doInTransactionWithoutResult(TransactionStatus status) {
 +                            List<IPAddressVO> ips = _ipAddressDao.listStaticNatPublicIps(network.getId());
 +                            for (IPAddressVO ip : ips) {
 +                                ip.setOneToOneNat(false);
 +                                ip.setAssociatedWithVmId(null);
 +                                ip.setVmIp(null);
 +                                _ipAddressDao.update(ip.getId(),ip);
 +                            }
 +                        }
 +                    });
 +                }
 +            } catch (ResourceUnavailableException ex) {
 +                s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex);
 +            }
 +        }
 +        if(services.contains(Service.SourceNat.getName())){
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(TransactionStatus status) {
 +                    List<IPAddressVO> ips = _ipAddressDao.listByAssociatedNetwork(network.getId(),true);
 +                    //removing static nat configured on ips.
 +                    for (IPAddressVO ip : ips) {
 +                        ip.setSourceNat(false);
 +                        _ipAddressDao.update(ip.getId(),ip);
 +                    }
 +                }
 +            });
 +        }
 +        if(services.contains(Service.Lb.getName())){
 +            //remove all LB rules for the network
 +            if (_lbMgr.removeAllLoadBalanacersForNetwork(networkId, caller, userId)) {
 +                s_logger.debug("Successfully cleaned up load balancing rules for network id=" + networkId);
 +            } else {
 +                s_logger.warn("Failed to cleanup LB rules as a part of network id=" + networkId + " cleanup");
 +            }
 +        }
 +
 +        if(services.contains(Service.Firewall.getName())){
 +            //revoke all firewall rules for the network
 +            try {
 +                if (_firewallMgr.revokeAllFirewallRulesForNetwork(networkId, userId, caller)) {
 +                    s_logger.debug("Successfully cleaned up firewallRules rules for network id=" + networkId);
 +                } else {
 +                    s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup");
 +                }
 +            } catch (ResourceUnavailableException ex) {
 +                s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex);
 +            }
 +        }
 +
 +        //do not remove vpn service for vpc networks.
 +        if(services.contains(Service.Vpn.getName()) && network.getVpcId()==null){
 +            RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findByAccountAndNetwork(network.getAccountId(),networkId);
 +            try {
 +                _vpnMgr.destroyRemoteAccessVpnForIp(vpn.getServerAddressId(), caller, true);
 +            } catch (ResourceUnavailableException ex) {
 +                s_logger.warn("Failed to cleanup remote access vpn resources of network:"+network.getUuid() + " due to Exception: ", ex);
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public void configureUpdateInSequence(Network network) {
 +        List<Provider> providers = getNetworkProviders(network.getId());
 +        for (NetworkElement element : networkElements) {
 +            if (providers.contains(element.getProvider())) {
 +                if (element instanceof RedundantResource) {
 +                    ((RedundantResource) element).configureResource(network);
 +                }
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public int getResourceCount(Network network){
 +        List<Provider> providers = getNetworkProviders(network.getId());
 +        int resourceCount=0;
 +        for (NetworkElement element : networkElements) {
 +            if (providers.contains(element.getProvider())) {
 +                //currently only one element implements the redundant resource interface
 +                if (element instanceof RedundantResource) {
 +                    resourceCount= ((RedundantResource) element).getResourceCount(network);
 +                    break;
 +                    }
 +                }
 +            }
 +        return resourceCount;
 +        }
 +
 +    @Override
 +    public void configureExtraDhcpOptions(Network network, long nicId, Map<Integer, String> extraDhcpOptions) {
 +        if(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp)) {
 +            if (_networkModel.getNetworkServiceCapabilities(network.getId(), Service.Dhcp).containsKey(Capability.ExtraDhcpOptions)) {
 +                DhcpServiceProvider sp = getDhcpServiceProvider(network);
 +                sp.setExtraDhcpOptions(network, nicId, extraDhcpOptions);
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public void configureExtraDhcpOptions(Network network, long nicId) {
 +        Map<Integer, String> extraDhcpOptions = getExtraDhcpOptions(nicId);
 +        configureExtraDhcpOptions(network, nicId, extraDhcpOptions);
 +    }
 +
 +    @Override
 +    public void finalizeUpdateInSequence(Network network, boolean success) {
 +        List<Provider> providers = getNetworkProviders(network.getId());
 +        for (NetworkElement element : networkElements) {
 +            if (providers.contains(element.getProvider())) {
 +                //currently only one element implements the redundant resource interface
 +                if (element instanceof RedundantResource) {
 +                    ((RedundantResource) element).finalize(network,success);
 +                    break;
 +                }
 +            }
 +        }
 +    }
 +
 +
 +    @DB
 +    protected void updateNic(final NicVO nic, final long networkId, final int count) {
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                _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);
 +                }
 +            }
 +        });
 +    }
 +
 +    @Override
 +    public void prepare(final VirtualMachineProfile vmProfile, final DeployDestination dest, final ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException,
 +    ResourceUnavailableException {
 +        final 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(final NicVO nic1, final NicVO nic2) {
 +                final boolean isDefault1 = nic1.isDefaultNic();
 +                final boolean isDefault2 = nic2.isDefaultNic();
 +
 +                return isDefault1 ^ isDefault2 ? isDefault1 ^ true ? 1 : -1 : 0;
 +            }
 +        });
 +
 +        for (final NicVO nic : nics) {
 +            final Pair<NetworkGuru, NetworkVO> implemented = implementNetwork(nic.getNetworkId(), dest, context, vmProfile.getVirtualMachine().getType() == Type.DomainRouter);
 +            if (implemented == null || 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());
 +            }
 +
 +            final NetworkVO network = implemented.second();
 +            final NicProfile profile = prepareNic(vmProfile, dest, context, nic.getId(), network);
 +            vmProfile.addNic(profile);
 +        }
 +    }
 +
 +    @Override
 +    public NicProfile prepareNic(final VirtualMachineProfile vmProfile, final DeployDestination dest, final ReservationContext context, final long nicId, final Network network)
 +            throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException,
 +            ResourceUnavailableException {
 +
 +        final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vmProfile.getId());
 +        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +        final 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();
 +            }
 +
 +            final 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.setIPv4Address(profile.getIPv4Address());
 +            nic.setAddressFormat(profile.getFormat());
 +            nic.setIPv6Address(profile.getIPv6Address());
 +            nic.setIPv6Cidr(profile.getIPv6Cidr());
 +            nic.setIPv6Gateway(profile.getIPv6Gateway());
 +            nic.setMacAddress(profile.getMacAddress());
 +            nic.setIsolationUri(profile.getIsolationUri());
 +            nic.setBroadcastUri(profile.getBroadCastUri());
 +            nic.setReserver(guru.getName());
 +            nic.setState(Nic.State.Reserved);
 +            nic.setIPv4Netmask(profile.getIPv4Netmask());
 +            nic.setIPv4Gateway(profile.getIPv4Gateway());
 +
 +            if (profile.getReservationStrategy() != null) {
 +                nic.setReservationStrategy(profile.getReservationStrategy());
 +            }
 +
 +            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);
 +        }
 +
 +        final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +        for (final 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);
 +
 +        configureExtraDhcpOptions(network, nicId);
 +        return profile;
 +    }
 +
 +    @Override
 +    public Map<Integer, String> getExtraDhcpOptions(long nicId) {
 +        List<NicExtraDhcpOptionVO> nicExtraDhcpOptionVOList = _nicExtraDhcpOptionDao.listByNicId(nicId);
 +        return nicExtraDhcpOptionVOList
 +                .stream()
 +                .collect(Collectors.toMap(NicExtraDhcpOptionVO::getCode, NicExtraDhcpOptionVO::getValue));
 +    }
 +
 +
 +    @Override
 +    public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployDestination dest) {
 +        if(vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) {
 +            //Include nics hot plugged and not stored in DB
 +            prepareAllNicsForMigration(vm, dest);
 +            return;
 +        }
 +        final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
 +        final ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), null, null);
 +        for (final NicVO nic : nics) {
 +            final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +            final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
 +
 +            final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +            final 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
 +                }
 +            }
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final 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);
 +        }
 +    }
 +
 +    /*
 +    Prepare All Nics for migration including the nics dynamically created and not stored in DB
 +    This is a temporary workaround work KVM migration
 +    Once clean fix is added by stored dynamically nics is DB, this workaround won't be needed
 +     */
 +    @Override
 +    public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final DeployDestination dest) {
 +        final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
 +        final ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), null, null);
 +        Long guestNetworkId = null;
 +        for (final NicVO nic : nics) {
 +            final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +            if(network.getTrafficType().equals(TrafficType.Guest) && network.getGuestType().equals(GuestType.Isolated)){
 +                guestNetworkId = network.getId();
 +            }
 +            final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
 +
 +            final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +            final 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
 +                }
 +            }
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final 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);
 +        }
 +
 +        final List<String> addedURIs = new ArrayList<String>();
 +        if(guestNetworkId != null){
 +            final List<IPAddressVO> publicIps = _ipAddressDao.listByAssociatedNetwork(guestNetworkId, null);
 +            for (final IPAddressVO userIp : publicIps){
 +                final PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
 +                final URI broadcastUri = BroadcastDomainType.Vlan.toUri(publicIp.getVlanTag());
 +                final long ntwkId = publicIp.getNetworkId();
 +                final Nic nic = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(ntwkId, vm.getId(),
 +                        broadcastUri.toString());
 +                if(nic == null && !addedURIs.contains(broadcastUri.toString())){
 +                    //Nic details are not available in DB
 +                    //Create nic profile for migration
 +                    s_logger.debug("Creating nic profile for migration. BroadcastUri: "+broadcastUri.toString()+" NetworkId: "+ntwkId+" Vm: "+vm.getId());
 +                    final NetworkVO network = _networksDao.findById(ntwkId);
 +                    _networkModel.getNetworkRate(network.getId(), vm.getId());
 +                    final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +                    final NicProfile profile = new NicProfile();
 +                    profile.setDeviceId(255); //dummyId
 +                    profile.setIPv4Address(userIp.getAddress().toString());
 +                    profile.setIPv4Netmask(publicIp.getNetmask());
 +                    profile.setIPv4Gateway(publicIp.getGateway());
 +                    profile.setMacAddress(publicIp.getMacAddress());
 +                    profile.setBroadcastType(network.getBroadcastDomainType());
 +                    profile.setTrafficType(network.getTrafficType());
 +                    profile.setBroadcastUri(broadcastUri);
 +                    profile.setIsolationUri(Networks.IsolationType.Vlan.toUri(publicIp.getVlanTag()));
 +                    profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network));
 +                    profile.setName(_networkModel.getNetworkTag(vm.getHypervisorType(), network));
 +                    profile.setNetworId(network.getId());
 +
 +                    guru.updateNicProfile(profile, network);
 +                    vm.addNic(profile);
 +                    addedURIs.add(broadcastUri.toString());
 +                }
 +            }
 +        }
 +    }
 +
 +    private NicProfile findNicProfileById(final VirtualMachineProfile vm, final long id) {
 +        for (final NicProfile nic : vm.getNics()) {
 +            if (nic.getId() == id) {
 +                return nic;
 +            }
 +        }
 +        return null;
 +    }
 +
 +    @Override
 +    public void commitNicForMigration(final VirtualMachineProfile src, final VirtualMachineProfile dst) {
 +        for (final NicProfile nicSrc : src.getNics()) {
 +            final NetworkVO network = _networksDao.findById(nicSrc.getNetworkId());
 +            final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +            final NicProfile nicDst = findNicProfileById(dst, nicSrc.getId());
 +            final ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null);
 +            final ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null);
 +
 +            if (guru instanceof NetworkMigrationResponder) {
 +                ((NetworkMigrationResponder)guru).commitMigration(nicSrc, network, src, src_context, dst_context);
 +            }
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final 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
 +            final NicVO nicVo = _nicDao.findById(nicDst.getId());
 +            nicVo.setReservationId(nicDst.getReservationId());
 +            _nicDao.persist(nicVo);
 +        }
 +    }
 +
 +    @Override
 +    public void rollbackNicForMigration(final VirtualMachineProfile src, final VirtualMachineProfile dst) {
 +        for (final NicProfile nicDst : dst.getNics()) {
 +            final NetworkVO network = _networksDao.findById(nicDst.getNetworkId());
 +            final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +            final NicProfile nicSrc = findNicProfileById(src, nicDst.getId());
 +            final ReservationContext src_context = new ReservationContextImpl(nicSrc.getReservationId(), null, null);
 +            final ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null);
 +
 +            if (guru instanceof NetworkMigrationResponder) {
 +                ((NetworkMigrationResponder)guru).rollbackMigration(nicDst, network, dst, src_context, dst_context);
 +            }
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final 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(final VirtualMachineProfile vmProfile, final boolean forced) throws ConcurrentOperationException, ResourceUnavailableException {
 +        final List<NicVO> nics = _nicDao.listByVmId(vmProfile.getId());
 +        for (final NicVO nic : nics) {
 +            releaseNic(vmProfile, nic.getId());
 +        }
 +    }
 +
 +    @Override
 +    @DB
 +    public void releaseNic(final VirtualMachineProfile vmProfile, final Nic nic) throws ConcurrentOperationException, ResourceUnavailableException {
 +        releaseNic(vmProfile, nic.getId());
 +    }
 +
 +    @DB
 +    protected void releaseNic(final VirtualMachineProfile vmProfile, final long nicId) throws ConcurrentOperationException, ResourceUnavailableException {
 +        final Pair<Network, NicProfile> networkToRelease = Transaction.execute(new TransactionCallback<Pair<Network, NicProfile>>() {
 +            @Override
 +            public Pair<Network, NicProfile> doInTransaction(final TransactionStatus status) {
 +                final NicVO nic = _nicDao.lockRow(nicId, true);
 +                if (nic == null) {
 +                    throw new ConcurrentOperationException("Unable to acquire lock on nic " + nic);
 +                }
 +
 +                final Nic.State originalState = nic.getState();
 +                final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +
 +                if (originalState == Nic.State.Reserved || originalState == Nic.State.Reserving) {
 +                    if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start) {
 +                        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +                        nic.setState(Nic.State.Releasing);
 +                        _nicDao.update(nic.getId(), nic);
 +                        final 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);
 +                            }
 +                        }
 +                        // Perform release on network elements
 +                        return new Pair<Network, NicProfile>(network, profile);
 +                    } else {
 +                        nic.setState(Nic.State.Allocated);
 +                        updateNic(nic, network.getId(), -1);
 +                    }
 +                }
 +
 +                return null;
 +            }
 +        });
 +
 +        // cleanup the entry in vm_network_map
 +        if(vmProfile.getType().equals(VirtualMachine.Type.User)) {
 +            final NicVO nic = _nicDao.findById(nicId);
 +            if(nic != null) {
 +                final NetworkVO vmNetwork = _networksDao.findById(nic.getNetworkId());
 +                final VMNetworkMapVO vno = _vmNetworkMapDao.findByVmAndNetworkId(vmProfile.getVirtualMachine().getId(), vmNetwork.getId());
 +                if(vno != null) {
 +                    _vmNetworkMapDao.remove(vno.getId());
 +                }
 +            }
 +        }
 +
 +        if (networkToRelease != null) {
 +            final Network network = networkToRelease.first();
 +            final NicProfile profile = networkToRelease.second();
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final NetworkElement element : networkElements) {
 +                if (providersToImplement.contains(element.getProvider())) {
 +                    if (s_logger.isDebugEnabled()) {
 +                        s_logger.debug("Asking " + element.getName() + " to release " + profile);
 +                    }
 +                    //NOTE: Context appear to never be used in release method
 +                    //implementations. Consider removing it from interface Element
 +                    element.release(network, profile, vmProfile, null);
 +                }
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public void cleanupNics(final VirtualMachineProfile vm) {
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Cleaning network for vm: " + vm.getId());
 +        }
 +
 +        final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
 +        for (final NicVO nic : nics) {
 +            removeNic(vm, nic);
 +        }
 +    }
 +
 +    @Override
 +    public void removeNic(final VirtualMachineProfile vm, final Nic nic) {
 +        removeNic(vm, _nicDao.findById(nic.getId()));
 +    }
 +
 +    protected void removeNic(final VirtualMachineProfile vm, final NicVO nic) {
 +
 +        if (nic.getReservationStrategy() == Nic.ReservationStrategy.Start && nic.getState() != Nic.State.Allocated) {
 +            // Nics with reservation strategy 'Start' should go through release phase in the Nic life cycle.
 +            // Ensure that release is performed before Nic is to be removed to avoid resource leaks.
 +            try {
 +                releaseNic(vm, nic.getId());
 +            } catch (final Exception ex) {
 +                s_logger.warn("Failed to release nic: " + nic.toString() + " as part of remove operation due to", ex);
 +            }
 +        }
 +
 +        nic.setState(Nic.State.Deallocating);
 +        _nicDao.update(nic.getId(), nic);
 +        final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +        final 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) {
 +            final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +            for (final NetworkElement element : networkElements) {
 +                if (providersToImplement.contains(element.getProvider())) {
 +                    if (s_logger.isDebugEnabled()) {
 +                        s_logger.debug("Asking " + element.getName() + " to release " + nic);
 +                    }
 +                    try {
 +                        element.release(network, profile, vm, null);
 +                    } catch (final ConcurrentOperationException ex) {
 +                        s_logger.warn("release failed during the nic " + nic.toString() + " removeNic due to ", ex);
 +                    } catch (final ResourceUnavailableException ex) {
 +                        s_logger.warn("release failed during the nic " + nic.toString() + " removeNic due to ", ex);
 +                    }
 +                }
 +            }
 +        }
 +
 +        if (vm.getType() == Type.User
 +                && network.getTrafficType() == TrafficType.Guest
 +                && network.getGuestType() == GuestType.Shared
 +                && isLastNicInSubnet(nic)) {
 +            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp)) {
 +                // remove the dhcpservice ip if this is the last nic in subnet.
 +                final DhcpServiceProvider dhcpServiceProvider = getDhcpServiceProvider(network);
 +                if (dhcpServiceProvider != null
 +                        && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) {
 +                    removeDhcpServiceInSubnet(nic);
 +                }
 +            }
 +            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dns)){
 +                final DnsServiceProvider dnsServiceProvider = getDnsServiceProvider(network);
 +                if (dnsServiceProvider != null) {
 +                    try {
 +                        if(!dnsServiceProvider.removeDnsSupportForSubnet(network)) {
 +                            s_logger.warn("Failed to remove the ip alias on the dns server");
 +                        }
 +                    } catch (final ResourceUnavailableException e) {
 +                        //failed to remove the dnsconfig.
 +                        s_logger.info("Unable to delete the ip alias due to unable to contact the dns server.");
 +                    }
 +                }
 +            }
 +        }
 +
 +        final 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(final DhcpServiceProvider dhcpServiceProvider) {
 +
 +        final Map<Network.Capability, String> capabilities = dhcpServiceProvider.getCapabilities().get(Network.Service.Dhcp);
 +        final String supportsMultipleSubnets = capabilities.get(Network.Capability.DhcpAccrossMultipleSubnets);
 +        if (supportsMultipleSubnets != null && Boolean.valueOf(supportsMultipleSubnets)) {
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    private boolean isLastNicInSubnet(final NicVO nic) {
 +        if (_nicDao.listByNetworkIdTypeAndGatewayAndBroadcastUri(nic.getNetworkId(), VirtualMachine.Type.User, nic.getIPv4Gateway(), nic.getBroadcastUri()).size() > 1) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    @DB
 +    @Override
 +    public void removeDhcpServiceInSubnet(final Nic nic) {
 +        final Network network = _networksDao.findById(nic.getNetworkId());
 +        final DhcpServiceProvider dhcpServiceProvider = getDhcpServiceProvider(network);
 +        try {
 +            final NicIpAliasVO ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(nic.getIPv4Gateway(), network.getId(), NicIpAlias.State.active);
 +            if (ipAlias != null) {
 +                ipAlias.setState(NicIpAlias.State.revoked);
 +                Transaction.execute(new TransactionCallbackNoReturn() {
 +                    @Override
 +                    public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                        _nicIpAliasDao.update(ipAlias.getId(), ipAlias);
 +                        final IPAddressVO aliasIpaddressVo = _publicIpAddressDao.findByIpAndSourceNetworkId(ipAlias.getNetworkId(), ipAlias.getIp4Address());
 +                        _publicIpAddressDao.unassignIpAddress(aliasIpaddressVo.getId());
 +                    }
 +                });
 +                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 (final 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(final VirtualMachineProfile vm) {
 +        final List<NicVO> nics = _nicDao.listByVmIdIncludingRemoved(vm.getId());
 +        for (final NicVO nic : nics) {
 +            _nicDao.expunge(nic.getId());
 +        }
 +    }
 +
 +    @Override
 +    @DB
 +    public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
 +                                      boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
 +                                      final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
 +                                      final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
 +
 +        final 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;
 +        }
 +
 +        final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, aclType);
 +        //check resource limits
 +        if (updateResourceCount) {
 +            _resourceLimitMgr.checkResourceLimit(owner, ResourceType.network, isDisplayNetworkEnabled);
 +        }
 +
 +        // Validate network offering
 +        if (ntwkOff.getState() != NetworkOffering.State.Enabled) {
 +            // see NetworkOfferingVO
 +            final 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
 +            final 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 (StringUtils.isNotBlank(ip6Gateway) && StringUtils.isNotBlank(ip6Cidr)) {
 +            ipv6 = true;
 +        }
 +        // Validate zone
 +        final DataCenterVO zone = _dcDao.findById(zoneId);
 +        if (zone.getNetworkType() == NetworkType.Basic) {
 +            // 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
 +            final 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.isElasticIp() || ntwkOff.isElasticLb()) {
 +                throw new InvalidParameterValueException("Elastic IP and Elastic LB services are supported in zone of type " + NetworkType.Basic);
 +            }
 +        }
 +
 +        if (ipv6 && !NetUtils.isValidIp6Cidr(ip6Cidr)) {
 +            throw new InvalidParameterValueException("Invalid IPv6 cidr specified");
 +        }
 +
 +        //TODO(VXLAN): Support VNI specified
 +        // VlanId can be specified only when network offering supports it
 +        final boolean vlanSpecified = vlanId != null;
 +        if (vlanSpecified != ntwkOff.isSpecifyVlan()) {
 +            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) {
 +            URI uri = BroadcastDomainType.fromString(vlanId);
 +            //don't allow to specify vlan tag used by physical network for dynamic vlan allocation
 +            if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).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());
 +            }
 +            if (! UuidUtils.validateUUID(vlanId)){
 +                // For Isolated and L2 networks, don't allow to create network with vlan that already exists in the zone
 +                if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2) {
 +                    if (_networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), null).size() > 0) {
 +                        throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists or overlaps with other network vlans in zone " + zoneId);
 +                    } else {
 +                        final List<DataCenterVnetVO> dcVnets = _datacenterVnetDao.findVnet(zoneId, BroadcastDomainType.getValue(uri));
 +                        //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()) {
 +                            final DataCenterVnetVO dcVnet = dcVnets.get(0);
 +                            // Fail network creation if specified vlan is dedicated to a different account
 +                            if (dcVnet.getAccountGuestVlanMapId() != null) {
 +                                final Long accountGuestVlanMapId = dcVnet.getAccountGuestVlanMapId();
 +                                final AccountGuestVlanMapVO map = _accountGuestVlanMapDao.findById(accountGuestVlanMapId);
 +                                if (map.getAccountId() != owner.getAccountId()) {
 +                                    throw new InvalidParameterValueException("Vlan " + vlanId + " is dedicated to a different account");
 +                                }
 +                                // Fail network creation if owner has a dedicated range of vlans but the specified vlan belongs to the system pool
 +                            } else {
 +                                final List<AccountGuestVlanMapVO> maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(owner.getAccountId());
 +                                if (maps != null && !maps.isEmpty()) {
 +                                    final int vnetsAllocatedToAccount = _datacenterVnetDao.countVnetsAllocatedToAccount(zoneId, owner.getAccountId());
 +                                    final int vnetsDedicatedToAccount = _datacenterVnetDao.countVnetsDedicatedToAccount(zoneId, owner.getAccountId());
 +                                    if (vnetsAllocatedToAccount < vnetsDedicatedToAccount) {
 +                                        throw new InvalidParameterValueException("Specified vlan " + vlanId + " doesn't belong" + " to the vlan range dedicated to the owner "
 +                                                + owner.getAccountName());
 +                                    }
 +                                }
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or
 +                    // shared network with same Vlan ID in the zone
 +                    if (!bypassVlanOverlapCheck && _networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), GuestType.Isolated).size() > 0 ) {
 +                        throw new InvalidParameterValueException("There is an existing isolated/shared network that overlaps with vlan id:" + vlanId + " in zone " + zoneId);
 +                    }
 +                }
 +            }
 +
 +        }
 +
 +        // If networkDomain is not specified, take it from the global configuration
 +        if (_networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Dns)) {
 +            final Map<Network.Capability, String> dnsCapabilities = _networkModel.getNetworkOfferingServiceCapabilities(_entityMgr.findById(NetworkOffering.class, networkOfferingId),
 +                    Service.Dns);
 +            final String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification);
 +            if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) {
 +                if (networkDomain != null) {
 +                    // TBD: NetworkOfferingId and zoneId. Send uuids instead.
 +                    throw new InvalidParameterValueException("Domain name change is not supported by network offering id=" + networkOfferingId + " in zone id=" + zoneId);
 +                }
 +            } else {
 +                if (networkDomain == null) {
 +                    // 1) Get networkDomain from the corresponding account/domain/zone
 +                    if (aclType == ACLType.Domain) {
 +                        networkDomain = _networkModel.getDomainNetworkDomain(domainId, zoneId);
 +                    } else if (aclType == ACLType.Account) {
 +                        networkDomain = _networkModel.getAccountNetworkDomain(owner.getId(), zoneId);
 +                    }
 +
 +                    // 2) If null, generate networkDomain using domain suffix from the global config variables
 +                    if (networkDomain == null) {
 +                        networkDomain = "cs" + Long.toHexString(owner.getId()) + GuestDomainSuffix.valueIn(zoneId);
 +                    }
 +
 +                } else {
 +                    // validate network domain
 +                    if (!NetUtils.verifyDomainName(networkDomain)) {
 +                        throw new InvalidParameterValueException("Invalid network domain. Total length shouldn't exceed 190 chars. Each domain "
 +                                + "label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', "
 +                                + "and the hyphen ('-'); can't start or end with \"-\"");
 +                    }
 +                }
 +            }
 +        }
 +
 +        // In Advance zone Cidr for Shared networks and Isolated networks w/o source nat service can't be NULL - 2.2.x
 +        // limitation, remove after we introduce support for multiple ip ranges
 +        // with different Cidrs for the same Shared network
 +        final boolean cidrRequired = zone.getNetworkType() == NetworkType.Advanced
 +                && ntwkOff.getTrafficType() == TrafficType.Guest
 +                && (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated
 +                && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)));
 +        if (cidr == null && ip6Cidr == null && cidrRequired) {
 +            throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared
 +                    + " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled");
 +        }
 +
 +        checkL2OfferingServices(ntwkOff);
 +
 +        // No cidr can be specified in Basic zone
 +        if (zone.getNetworkType() == NetworkType.Basic && cidr != null) {
 +            throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask can't be specified for zone of type " + NetworkType.Basic);
 +        }
 +
 +        // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4
 +        if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) {
 +            if (!NetUtils.validateGuestCidr(cidr)) {
 +                throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC 1918 or 6598 compliant");
 +            }
 +        }
 +
 +        final String networkDomainFinal = networkDomain;
 +        final String vlanIdFinal = vlanId;
 +        final Boolean subdomainAccessFinal = subdomainAccess;
 +        final Network network = Transaction.execute(new TransactionCallback<Network>() {
 +            @Override
 +            public Network doInTransaction(final TransactionStatus status) {
 +                Long physicalNetworkId = null;
 +                if (pNtwk != null) {
 +                    physicalNetworkId = pNtwk.getId();
 +                }
 +                final DataCenterDeployment plan = new DataCenterDeployment(zoneId, null, null, null, null, physicalNetworkId);
 +                final NetworkVO userNetwork = new NetworkVO();
 +                userNetwork.setNetworkDomain(networkDomainFinal);
 +
 +                if (cidr != null && gateway != null) {
 +                    userNetwork.setCidr(cidr);
 +                    userNetwork.setGateway(gateway);
 +                }
 +
 +                if (StringUtils.isNotBlank(ip6Gateway) && StringUtils.isNotBlank(ip6Cidr)) {
 +                    userNetwork.setIp6Cidr(ip6Cidr);
 +                    userNetwork.setIp6Gateway(ip6Gateway);
 +                }
 +
 +                if (externalId != null) {
 +                    userNetwork.setExternalId(externalId);
 +                }
 +
 +                if (vlanIdFinal != null) {
 +                    if (isolatedPvlan == null) {
 +                        URI uri = null;
 +                        if (UuidUtils.validateUUID(vlanIdFinal)){
 +                            //Logical router's UUID provided as VLAN_ID
 +                            userNetwork.setVlanIdAsUUID(vlanIdFinal); //Set transient field
 +                        } else {
 +                            uri = BroadcastDomainType.fromString(vlanIdFinal);
 +                        }
 +                        userNetwork.setBroadcastUri(uri);
 +                        if (!vlanIdFinal.equalsIgnoreCase(Vlan.UNTAGGED)) {
 +                            userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan);
 +                        } else {
 +                            userNetwork.setBroadcastDomainType(BroadcastDomainType.Native);
 +                        }
 +                    } else {
 +                        if (vlanIdFinal.equalsIgnoreCase(Vlan.UNTAGGED)) {
 +                            throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!");
 +                        }
 +                        userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanIdFinal, isolatedPvlan));
 +                        userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan);
 +                    }
 +                }
 +
 +                final List<? extends Network> networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccessFinal, vpcId,
 +                        isDisplayNetworkEnabled);
 +
 +                Network network = null;
 +                if (networks == null || networks.isEmpty()) {
 +                    throw new CloudRuntimeException("Fail to create a network");
 +                } else {
 +                    if (networks.size() > 0 && networks.get(0).getGuestType() == Network.GuestType.Isolated && networks.get(0).getTrafficType() == TrafficType.Guest) {
 +                        Network defaultGuestNetwork = networks.get(0);
 +                        for (final Network nw : networks) {
 +                            if (nw.getCidr() != null && nw.getCidr().equals(zone.getGuestNetworkCidr())) {
 +                                defaultGuestNetwork = nw;
 +                            }
 +                        }
 +                        network = defaultGuestNetwork;
 +                    } else {
 +                        // For shared network
 +                        network = networks.get(0);
 +                    }
 +                }
 +
 +                if (updateResourceCount) {
 +                    _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.network, isDisplayNetworkEnabled);
 +                }
 +
 +                return network;
 +            }
 +        });
 +
 +        CallContext.current().setEventDetails("Network Id: " + network.getId());
 +        CallContext.current().putContextParameter(Network.class, network.getUuid());
 +        return network;
 +    }
 +
 +    /**
 +     * Checks for L2 network offering services. Only 2 cases allowed:
 +     * - No services
 +     * - User Data service only, provided by ConfigDrive
 +     * @param ntwkOff network offering
 +     */
 +    protected void checkL2OfferingServices(NetworkOfferingVO ntwkOff) {
 +        if (ntwkOff.getGuestType() == GuestType.L2 && !_networkModel.listNetworkOfferingServices(ntwkOff.getId()).isEmpty() &&
 +                (!_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.UserData) ||
 +                        (_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.UserData) &&
 +                                _networkModel.listNetworkOfferingServices(ntwkOff.getId()).size() > 1))) {
 +            throw new InvalidParameterValueException("For L2 networks, only UserData service is allowed");
 +        }
 +    }
 +
 +    @Override
 +    @DB
 +    public boolean shutdownNetwork(final long networkId, final ReservationContext context, final boolean cleanupElements) {
 +        NetworkVO network = _networksDao.findById(networkId);
 +        if (network.getState() == Network.State.Allocated) {
 +            s_logger.debug("Network is already shutdown: " + network);
 +            return true;
 +        }
 +
 +        if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Shutdown) {
 +            s_logger.debug("Network is not implemented: " + network);
 +            return false;
 +        }
 +
 +        try {
 +            //do global lock for the network
 +            network = _networksDao.acquireInLockTable(networkId, NetworkLockTimeout.value());
 +            if (network == null) {
 +                s_logger.warn("Unable to acquire lock for the network " + network + " as a part of network shutdown");
 +                return false;
 +            }
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("Lock is acquired for network " + network + " as a part of network shutdown");
 +            }
 +
 +            if (network.getState() == Network.State.Allocated) {
 +                s_logger.debug("Network is already shutdown: " + network);
 +                return true;
 +            }
 +
 +            if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Shutdown) {
 +                s_logger.debug("Network is not implemented: " + network);
 +                return false;
 +            }
 +
 +            if (isSharedNetworkWithServices(network)) {
 +                network.setState(Network.State.Shutdown);
 +                _networksDao.update(network.getId(), network);
 +            } else {
 +                try {
 +                    stateTransitTo(network, Event.DestroyNetwork);
 +                } catch (final NoTransitionException e) {
 +                    network.setState(Network.State.Shutdown);
 +                    _networksDao.update(network.getId(), network);
 +                }
 +            }
 +
 +            final boolean success = shutdownNetworkElementsAndResources(context, cleanupElements, network);
 +
 +            final NetworkVO networkFinal = network;
 +            final boolean result = Transaction.execute(new TransactionCallback<Boolean>() {
 +                @Override
 +                public Boolean doInTransaction(final TransactionStatus status) {
 +                    boolean result = false;
 +
 +                    if (success) {
 +                        if (s_logger.isDebugEnabled()) {
 +                            s_logger.debug("Network id=" + networkId + " is shutdown successfully, cleaning up corresponding resources now.");
 +                        }
 +                        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, networkFinal.getGuruName());
 +                        final NetworkProfile profile = convertNetworkToNetworkProfile(networkFinal.getId());
 +                        guru.shutdown(profile, _networkOfferingDao.findById(networkFinal.getNetworkOfferingId()));
 +
 +                        applyProfileToNetwork(networkFinal, profile);
 +                        final DataCenterVO zone = _dcDao.findById(networkFinal.getDataCenterId());
 +                        if (isSharedNetworkOfferingWithServices(networkFinal.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) {
 +                            networkFinal.setState(Network.State.Setup);
 +                        } else {
 +                            try {
 +                                stateTransitTo(networkFinal, Event.OperationSucceeded);
 +                            } catch (final NoTransitionException e) {
 +                                networkFinal.setState(Network.State.Allocated);
 +                                networkFinal.setRestartRequired(false);
 +                            }
 +                        }
 +                        _networksDao.update(networkFinal.getId(), networkFinal);
 +                        _networksDao.clearCheckForGc(networkId);
 +                        result = true;
 +                    } else {
 +                        try {
 +                            stateTransitTo(networkFinal, Event.OperationFailed);
 +                        } catch (final NoTransitionException e) {
 +                            networkFinal.setState(Network.State.Implemented);
 +                            _networksDao.update(networkFinal.getId(), networkFinal);
 +                        }
 +                        result = false;
 +                    }
 +
 +                    return result;
 +                }
 +            });
 +
 +            return result;
 +        } finally {
 +            if (network != null) {
 +                _networksDao.releaseFromLockTable(network.getId());
 +                if (s_logger.isDebugEnabled()) {
 +                    s_logger.debug("Lock is released for network " + network + " as a part of network shutdown");
 +                }
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public boolean shutdownNetworkElementsAndResources(final ReservationContext context, final boolean cleanupElements, final Network network) {
 +
 +        // get providers to shutdown
 +        final List<Provider> providersToShutdown = getNetworkProviders(network.getId());
 +
 +        // 1) Cleanup all the rules for the network. If it fails, just log the failure and proceed with shutting down
 +        // the elements
 +        boolean cleanupResult = true;
 +        boolean cleanupNeeded = false;
 +        try {
 +            for (final Provider provider: providersToShutdown) {
 +                if (provider.cleanupNeededOnShutdown()) {
 +                    cleanupNeeded = true;
 +                    break;
 +                }
 +            }
 +            if (cleanupNeeded) {
 +                cleanupResult = shutdownNetworkResources(network.getId(), context.getAccount(), context.getCaller().getId());
 +            }
 +        } catch (final Exception ex) {
 +            s_logger.warn("shutdownNetworkRules failed during the network " + network + " shutdown due to ", ex);
 +        } finally {
 +            // just warn the administrator that the network elements failed to shutdown
 +            if (!cleanupResult) {
 +                s_logger.warn("Failed to cleanup network id=" + network.getId() + " resources as a part of shutdownNetwork");
 +            }
 +        }
 +
 +        // 2) Shutdown all the network elements
 +        boolean success = true;
 +        for (final NetworkElement element : networkElements) {
 +            if (providersToShutdown.contains(element.getProvider())) {
 +                try {
 +                    if (s_logger.isDebugEnabled()) {
 +                        s_logger.debug("Sending network shutdown to " + element.getName());
 +                    }
 +                    if (!element.shutdown(network, context, cleanupElements)) {
 +                        s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName());
 +                        success = false;
 +                    }
 +                } catch (final ResourceUnavailableException e) {
 +                    s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e);
 +                    success = false;
 +                } catch (final ConcurrentOperationException e) {
 +                    s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e);
 +                    success = false;
 +                } catch (final Exception e) {
 +                    s_logger.warn("Unable to complete shutdown of the network elements due to element: " + element.getName(), e);
 +                    success = false;
 +                }
 +            }
 +        }
 +        return success;
 +    }
 +
 +    @Override
 +    @DB
 +    public boolean destroyNetwork(final long networkId, final ReservationContext context, final boolean forced) {
 +        final Account callerAccount = context.getAccount();
 +
 +        NetworkVO network = _networksDao.findById(networkId);
 +        if (network == null) {
 +            s_logger.debug("Unable to find network with id: " + networkId);
 +            return false;
 +        }
 +        // Make sure that there are no user vms in the network that are not Expunged/Error
 +        final List<UserVmVO> userVms = _userVmDao.listByNetworkIdAndStates(networkId);
 +
 +        for (final UserVmVO vm : userVms) {
 +            if (!(vm.getState() == VirtualMachine.State.Expunging && vm.getRemoved() != null)) {
 +                s_logger.warn("Can't delete the network, not all user vms are expunged. Vm " + vm + " is in " + vm.getState() + " state");
 +                return false;
 +            }
 +        }
 +
 +        // Don't allow to delete network via api call when it has vms assigned to it
 +        final int nicCount = getActiveNicsInNetwork(networkId);
 +        if (nicCount > 0) {
 +            s_logger.debug("The network id=" + networkId + " has active Nics, but shouldn't.");
 +            // at this point we have already determined that there are no active user vms in network
 +            // if the op_networks table shows active nics, it's a bug in releasing nics updating op_networks
 +            _networksDao.changeActiveNicsBy(networkId, -1 * nicCount);
 +        }
 +
 +        //In Basic zone, make sure that there are no non-removed console proxies and SSVMs using the network
 +        final DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
 +        if (zone.getNetworkType() == NetworkType.Basic) {
 +            final List<VMInstanceVO> systemVms = _vmDao.listNonRemovedVmsByTypeAndNetwork(network.getId(), Type.ConsoleProxy, Type.SecondaryStorageVm);
 +            if (systemVms != null && !systemVms.isEmpty()) {
 +                s_logger.warn("Can't delete the network, not all consoleProxy/secondaryStorage vms are expunged");
 +                return false;
 +            }
 +        }
 +
 +        // Shutdown network first
 +        shutdownNetwork(networkId, context, false);
 +
 +        // get updated state for the network
 +        network = _networksDao.findById(networkId);
 +        if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup && !forced) {
 +            s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState());
 +            return false;
 +        }
 +
 +        boolean success = true;
 +        if (!cleanupNetworkResources(networkId, callerAccount, context.getCaller().getId())) {
 +            s_logger.warn("Unable to delete network id=" + networkId + ": failed to cleanup network resources");
 +            return false;
 +        }
 +
 +        // get providers to destroy
 +        final List<Provider> providersToDestroy = getNetworkProviders(network.getId());
 +        for (final NetworkElement element : networkElements) {
 +            if (providersToDestroy.contains(element.getProvider())) {
 +                try {
 +                    if (s_logger.isDebugEnabled()) {
 +                        s_logger.debug("Sending destroy to " + element);
 +                    }
 +
 +                    if (!element.destroy(network, context)) {
 +                        success = false;
 +                        s_logger.warn("Unable to complete destroy of the network: failed to destroy network element " + element.getName());
 +                    }
 +                } catch (final ResourceUnavailableException e) {
 +                    s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
 +                    success = false;
 +                } catch (final ConcurrentOperationException e) {
 +                    s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
 +                    success = false;
 +                } catch (final Exception e) {
 +                    s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
 +                    success = false;
 +                }
 +            }
 +        }
 +
 +        if (success) {
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("Network id=" + networkId + " is destroyed successfully, cleaning up corresponding resources now.");
 +            }
 +
 +            final NetworkVO networkFinal = network;
 +            try {
 +                Transaction.execute(new TransactionCallbackNoReturn() {
 +                    @Override
 +                    public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, networkFinal.getGuruName());
 +
 +                        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");
 +                            throw new CloudRuntimeException("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges");
 +                        } else {
 +                            // commit transaction only when ips and vlans for the network are released successfully
 +                            try {
 +                                stateTransitTo(networkFinal, Event.DestroyNetwork);
 +                            } catch (final NoTransitionException e) {
 +                                s_logger.debug(e.getMessage());
 +                            }
 +                            if (_networksDao.remove(networkFinal.getId())) {
 +                                final NetworkDomainVO networkDomain = _networkDomainDao.getDomainNetworkMapByNetworkId(networkFinal.getId());
 +                                if (networkDomain != null) {
 +                                    _networkDomainDao.remove(networkDomain.getId());
 +                                }
 +
 +                                final NetworkAccountVO networkAccount = _networkAccountDao.getAccountNetworkMapByNetworkId(networkFinal.getId());
 +                                if (networkAccount != null) {
 +                                    _networkAccountDao.remove(networkAccount.getId());
 +                                }
 +                            }
 +
 +                            final NetworkOffering ntwkOff = _entityMgr.findById(NetworkOffering.class, networkFinal.getNetworkOfferingId());
 +                            final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, networkFinal.getAclType());
 +                            if (updateResourceCount) {
 +                                _resourceLimitMgr.decrementResourceCount(networkFinal.getAccountId(), ResourceType.network, networkFinal.getDisplayNetwork());
 +                            }
 +                        }
 +                    }
 +                });
 +                if (_networksDao.findById(network.getId()) == null) {
 +                    // remove its related ACL permission
 +                    final Pair<Class<?>, Long> networkMsg = new Pair<Class<?>, Long>(Network.class, networkFinal.getId());
 +                    _messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, networkMsg);
 +                }
 +                return true;
 +            } catch (final CloudRuntimeException e) {
 +                s_logger.error("Failed to delete network", e);
 +                return false;
 +            }
 +        }
 +
 +        return success;
 +    }
 +
 +    @Override
 +    public boolean resourceCountNeedsUpdate(final NetworkOffering ntwkOff, final ACLType aclType) {
 +        //Update resource count only for Isolated account specific non-system networks
 +        final boolean updateResourceCount = ntwkOff.getGuestType() == GuestType.Isolated && !ntwkOff.isSystemOnly() && aclType == ACLType.Account;
 +        return updateResourceCount;
 +    }
 +
 +    protected boolean deleteVlansInNetwork(final long networkId, final long userId, final Account callerAccount) {
 +
 +        //cleanup Public vlans
 +        final List<VlanVO> publicVlans = _vlanDao.listVlansByNetworkId(networkId);
 +        boolean result = true;
 +        for (final VlanVO vlan : publicVlans) {
 +            if (!_configMgr.deleteVlanAndPublicIpRange(userId, vlan.getId(), callerAccount)) {
 +                s_logger.warn("Failed to delete vlan " + vlan.getId() + ");");
 +                result = false;
 +            }
 +        }
 +
 +        //cleanup private vlans
 +        final int privateIpAllocCount = _privateIpDao.countAllocatedByNetworkId(networkId);
 +        if (privateIpAllocCount > 0) {
 +            s_logger.warn("Can't delete Private ip range for network " + networkId + " as it has allocated ip addresses");
 +            result = false;
 +        } else {
 +            _privateIpDao.deleteByNetworkId(networkId);
 +            s_logger.debug("Deleted ip range for private network id=" + networkId);
 +        }
 +        return result;
 +    }
 +
 +    public class NetworkGarbageCollector extends ManagedContextRunnable {
 +        @Override
 +        protected void runInContext() {
 +            final GlobalLock gcLock = GlobalLock.getInternLock("Network.GC.Lock");
 +            try {
 +                if (gcLock.lock(3)) {
 +                    try {
 +                        reallyRun();
 +                    } finally {
 +                        gcLock.unlock();
 +                    }
 +                }
 +            } finally {
 +                gcLock.releaseRef();
 +            }
 +        }
 +
 +        public void reallyRun() {
 +            try {
 +                final List<Long> shutdownList = new ArrayList<Long>();
 +                final long currentTime = System.currentTimeMillis() / 1000;
 +                final HashMap<Long, Long> stillFree = new HashMap<Long, Long>();
 +
 +                final List<Long> networkIds = _networksDao.findNetworksToGarbageCollect();
 +                final int netGcWait = NumbersUtil.parseInt(_configDao.getValue(NetworkGcWait.key()), 60);
 +                s_logger.info("NetworkGarbageCollector uses '" + netGcWait + "' seconds for GC interval.");
 +
 +                for (final Long networkId : networkIds) {
 +
 +                    if (!_networkModel.isNetworkReadyForGc(networkId)) {
 +                        continue;
 +                    }
 +
 +                    final Long time = _lastNetworkIdsToFree.remove(networkId);
 +                    if (time == null) {
 +                        if (s_logger.isDebugEnabled()) {
 +                            s_logger.debug("We found network " + networkId + " to be free for the first time.  Adding it to the list: " + currentTime);
 +                        }
 +                        stillFree.put(networkId, currentTime);
 +                    } else if (time > currentTime - netGcWait) {
 +                        if (s_logger.isDebugEnabled()) {
 +                            s_logger.debug("Network " + networkId + " is still free but it's not time to shutdown yet: " + time);
 +                        }
 +                        stillFree.put(networkId, time);
 +                    } else {
 +                        shutdownList.add(networkId);
 +                    }
 +                }
 +
 +                _lastNetworkIdsToFree = stillFree;
 +
 +                final CallContext cctx = CallContext.current();
 +
 +                for (final Long networkId : shutdownList) {
 +
 +                    // If network is removed, unset gc flag for it
 +                    if (_networksDao.findById(networkId) == null) {
 +                        s_logger.debug("Network id=" + networkId + " is removed, so clearing up corresponding gc check");
 +                        _networksDao.clearCheckForGc(networkId);
 +                    } else {
 +                        try {
 +
 +                            final User caller = cctx.getCallingUser();
 +                            final Account owner = cctx.getCallingAccount();
 +
 +                            final ReservationContext context = new ReservationContextImpl(null, null, caller, owner);
 +
 +                            shutdownNetwork(networkId, context, false);
 +                        } catch (final Exception e) {
 +                            s_logger.warn("Unable to shutdown network: " + networkId);
 +                        }
 +                    }
 +                }
 +            } catch (final Exception e) {
 +                s_logger.warn("Caught exception while running network gc: ", e);
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public boolean startNetwork(final long networkId, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
 +    InsufficientCapacityException {
 +
 +        // Check if network exists
 +        final NetworkVO network = _networksDao.findById(networkId);
 +        if (network == null) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id doesn't exist");
 +            ex.addProxyObject(String.valueOf(networkId), "networkId");
 +            throw ex;
 +        }
 +
 +        // implement the network
 +        s_logger.debug("Starting network " + network + "...");
 +        final Pair<NetworkGuru, NetworkVO> implementedNetwork = implementNetwork(networkId, dest, context);
 +        if (implementedNetwork== null || implementedNetwork.first() == null) {
 +            s_logger.warn("Failed to start the network " + network);
 +            return false;
 +        } else {
 +            return true;
 +        }
 +    }
 +
 +    @Override
 +    public boolean restartNetwork(final Long networkId, final Account callerAccount, final User callerUser, final boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException,
 +    InsufficientCapacityException {
 +
 +        final NetworkVO network = _networksDao.findById(networkId);
 +
 +        s_logger.debug("Restarting network " + networkId + "...");
 +
 +        final ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount);
 +        final NetworkOffering offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
 +        final DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null);
 +
 +        if (cleanup) {
 +            if (!rollingRestartRouters(network, offering, dest, context)) {
 +                setRestartRequired(network, true);
 +                return false;
 +            }
 +            return true;
 +        }
 +
 +        s_logger.debug("Implementing the network " + network + " elements and resources as a part of network restart without cleanup");
 +        try {
 +            implementNetworkElementsAndResources(dest, context, network, offering);
 +            setRestartRequired(network, true);
 +            return true;
 +        } catch (final Exception ex) {
 +            s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network restart due to ", ex);
 +            return false;
 +        }
 +    }
 +
 +    @Override
 +    public void destroyExpendableRouters(final List<? extends VirtualRouter> routers, final ReservationContext context) throws ResourceUnavailableException {
 +        final List<VirtualRouter> remainingRouters = new ArrayList<>();
 +        for (final VirtualRouter router : routers) {
 +            if (router.getState() == VirtualMachine.State.Stopped ||
 +                    router.getState() == VirtualMachine.State.Error ||
 +                    router.getState() == VirtualMachine.State.Shutdowned ||
 +                    router.getState() == VirtualMachine.State.Unknown) {
 +                s_logger.debug("Destroying old router " + router);
 +                _routerService.destroyRouter(router.getId(), context.getAccount(), context.getCaller().getId());
 +            } else {
 +                remainingRouters.add(router);
 +            }
 +        }
 +
 +        if (remainingRouters.size() < 2) {
 +            return;
 +        }
 +
 +        VirtualRouter backupRouter = null;
 +        for (final VirtualRouter router : remainingRouters) {
 +            if (router.getRedundantState() == VirtualRouter.RedundantState.BACKUP) {
 +                backupRouter = router;
 +            }
 +        }
 +        if (backupRouter == null) {
 +            backupRouter = routers.get(routers.size() - 1);
 +        }
 +        if (backupRouter != null) {
 +            _routerService.destroyRouter(backupRouter.getId(), context.getAccount(), context.getCaller().getId());
 +        }
 +    }
 +
 +    @Override
 +    public boolean areRoutersRunning(final List<? extends VirtualRouter> routers) {
 +        for (final VirtualRouter router : routers) {
 +            if (router.getState() != VirtualMachine.State.Running) {
 +                s_logger.debug("Found new router " + router.getInstanceName() + " to be in non-Running state: " + router.getState() + ". Please try restarting network again.");
 +                return false;
 +            }
 +        }
 +        return true;
 +    }
 +
 +    /**
 +     * rollingRestartRouters performs restart of routers of a network by first
 +     * deploying a new VR and then destroying old VRs in rolling fashion. For
 +     * non-redundant network, it will re-program the new router as final step
 +     * otherwise deploys a backup router for the network.
 +     * @param network network to be restarted
 +     * @param offering network offering
 +     * @param dest deployment destination
 +     * @param context reservation context
 +     * @return returns true when the rolling restart operation succeeds
 +     * @throws ResourceUnavailableException
 +     * @throws ConcurrentOperationException
 +     * @throws InsufficientCapacityException
 +     */
 +    private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffering offering, final DeployDestination dest, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
++        if (!NetworkOrchestrationService.RollingRestartEnabled.value()) {
++            if (shutdownNetworkElementsAndResources(context, true, network)) {
++                implementNetworkElementsAndResources(dest, context, network, offering);
++                return true;
++            }
++            s_logger.debug("Failed to shutdown the network elements and resources as a part of network restart: " + network.getState());
++            return false;
++        }
 +        s_logger.debug("Performing rolling restart of routers of network " + network);
 +        destroyExpendableRouters(_routerDao.findByNetwork(network.getId()), context);
 +
 +        final List<Provider> providersToImplement = getNetworkProviders(network.getId());
 +        final List<DomainRouterVO> oldRouters = _routerDao.findByNetwork(network.getId());
 +
 +        // Deploy a new router
 +        if (oldRouters.size() > 0) {
 +            network.setRollingRestart(true);
 +        }
 +        implementNetworkElements(dest, context, network, offering, providersToImplement);
 +        if (oldRouters.size() > 0) {
 +            network.setRollingRestart(false);
 +        }
 +
 +        // For redundant network wait for 3*advert_int+skew_seconds for VRRP to kick in
 +        if (network.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) {
 +            try {
 +                Thread.sleep(NetworkOrchestrationService.RVRHandoverTime);
 +            } catch (final InterruptedException ignored) {}
 +        }
 +
 +        // Destroy old routers
 +        for (final DomainRouterVO oldRouter : oldRouters) {
 +            _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId());
 +        }
 +
 +        if (network.isRedundant()) {
 +            // Add a new backup router for redundant network
 +            implementNetworkElements(dest, context, network, offering, providersToImplement);
 +        } else {
 +            // Re-apply rules for non-redundant network
 +            implementNetworkElementsAndResources(dest, context, network, offering);
 +        }
 +
 +        return areRoutersRunning(_routerDao.findByNetwork(network.getId()));
 +    }
 +
 +    private void setRestartRequired(final NetworkVO network, final boolean restartRequired) {
 +        s_logger.debug("Marking network " + network + " with restartRequired=" + restartRequired);
 +        network.setRestartRequired(restartRequired);
 +        _networksDao.update(network.getId(), network);
 +    }
 +
 +    protected int getActiveNicsInNetwork(final long networkId) {
 +        return _networksDao.getActiveNicsIn(networkId);
 +    }
 +
 +    @Override
 +    public NetworkProfile convertNetworkToNetworkProfile(final long networkId) {
 +        final NetworkVO network = _networksDao.findById(networkId);
 +        final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +        final NetworkProfile profile = new NetworkProfile(network);
 +        guru.updateNetworkProfile(profile);
 +
 +        return profile;
 +    }
 +
 +    @Override
 +    public UserDataServiceProvider getPasswordResetProvider(final Network network) {
 +        final String passwordProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData);
 +
 +        if (passwordProvider == null) {
 +            s_logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName());
 +            return null;
 +        }
 +
 +        return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(passwordProvider);
 +    }
 +
 +    @Override
 +    public UserDataServiceProvider getSSHKeyResetProvider(final Network network) {
 +        final String SSHKeyProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData);
 +
 +        if (SSHKeyProvider == null) {
 +            s_logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName());
 +            return null;
 +        }
 +
 +        return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(SSHKeyProvider);
 +    }
 +
 +    @Override
 +    public DhcpServiceProvider getDhcpServiceProvider(final Network network) {
 +        final String DhcpProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Dhcp);
 +
 +        if (DhcpProvider == null) {
 +            s_logger.debug("Network " + network + " doesn't support service " + Service.Dhcp.getName());
 +            return null;
 +        }
 +
 +        final NetworkElement element = _networkModel.getElementImplementingProvider(DhcpProvider);
 +        if ( element instanceof DhcpServiceProvider ) {
 +            return (DhcpServiceProvider)element;
 +        } else {
 +            return null;
 +        }
 +    }
 +
 +    @Override
 +    public DnsServiceProvider getDnsServiceProvider(final Network network) {
 +        final String dnsProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Dns);
 +
 +        if (dnsProvider == null) {
 +            s_logger.debug("Network " + network + " doesn't support service " + Service.Dhcp.getName());
 +            return null;
 +        }
 +
 +        return  (DnsServiceProvider) _networkModel.getElementImplementingProvider(dnsProvider);
 +    }
 +
 +    protected boolean isSharedNetworkWithServices(final Network network) {
 +        assert network != null;
 +        final DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
 +        if (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced
 +                && isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    protected boolean isSharedNetworkOfferingWithServices(final long networkOfferingId) {
 +        final NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
 +        if (networkOffering.getGuestType() == Network.GuestType.Shared
 +                && (_networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat)
 +                        || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.StaticNat)
 +                        || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Firewall)
 +                        || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.PortForwarding) || _networkModel.areServicesSupportedByNetworkOffering(
 +                                networkOfferingId, Service.Lb))) {
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    @Override
 +    public List<? extends Nic> listVmNics(final long vmId, final Long nicId, final Long networkId, String keyword) {
 +        List<NicVO> result = null;
 +
 +        if (keyword == null || keyword.isEmpty()) {
 +            if (nicId == null && networkId == null) {
 +                result = _nicDao.listByVmId(vmId);
 +            } else {
 +                result = _nicDao.listByVmIdAndNicIdAndNtwkId(vmId, nicId, networkId);
 +            }
 +        } else {
 +            result = _nicDao.listByVmIdAndKeyword(vmId, keyword);
 +        }
 +
 +        for (final NicVO nic : result) {
 +            if (_networkModel.isProviderForNetwork(Provider.NiciraNvp, nic.getNetworkId())) {
 +                //For NSX Based networks, add nsxlogicalswitch, nsxlogicalswitchport to each result
 +                s_logger.info("Listing NSX logical switch and logical switch por for each nic");
 +                final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +                final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +                final NetworkGuruAdditionalFunctions guruFunctions = (NetworkGuruAdditionalFunctions) guru;
 +
 +                final Map<String, ? extends Object> nsxParams = guruFunctions.listAdditionalNicParams(nic.getUuid());
 +                if (nsxParams != null){
 +                    final String lswitchUuuid = nsxParams.containsKey(NetworkGuruAdditionalFunctions.NSX_LSWITCH_UUID)
 +                            ? (String) nsxParams.get(NetworkGuruAdditionalFunctions.NSX_LSWITCH_UUID) : null;
 +                    final String lswitchPortUuuid = nsxParams.containsKey(NetworkGuruAdditionalFunctions.NSX_LSWITCHPORT_UUID)
 +                            ? (String) nsxParams.get(NetworkGuruAdditionalFunctions.NSX_LSWITCHPORT_UUID) : null;
 +                    nic.setNsxLogicalSwitchUuid(lswitchUuuid);
 +                    nic.setNsxLogicalSwitchPortUuid(lswitchPortUuuid);
 +                }
 +            }
 +        }
 +
 +        return result;
 +    }
 +
 +    @DB
 +    @Override
 +    public boolean reallocate(final VirtualMachineProfile vm, final DataCenterDeployment dest) throws InsufficientCapacityException, ConcurrentOperationException {
 +        final VMInstanceVO vmInstance = _vmDao.findById(vm.getId());
 +        final DataCenterVO dc = _dcDao.findById(vmInstance.getDataCenterId());
 +        if (dc.getNetworkType() == NetworkType.Basic) {
 +            final List<NicVO> nics = _nicDao.listByVmId(vmInstance.getId());
 +            final NetworkVO network = _networksDao.findById(nics.get(0).getNetworkId());
 +            final LinkedHashMap<Network, List<? extends NicProfile>> profiles = new LinkedHashMap<Network, List<? extends NicProfile>>();
 +            profiles.put(network, new ArrayList<NicProfile>());
 +
 +            Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
 +                @Override
 +                public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
 +                    cleanupNics(vm);
 +                    allocate(vm, profiles, null);
 +                }
 +            });
 +        }
 +        return true;
 +    }
 +
 +    private boolean cleanupNetworkResources(final long networkId, final Account caller, final long callerUserId) {
 +        boolean success = true;
 +        final Network network = _networksDao.findById(networkId);
 +
 +        //remove all PF/Static Nat rules for the network
 +        try {
 +            if (_rulesMgr.revokeAllPFStaticNatRulesForNetwork(networkId, callerUserId, caller)) {
 +                s_logger.debug("Successfully cleaned up portForwarding/staticNat rules for network id=" + networkId);
 +            } else {
 +                success = false;
 +                s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup");
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            success = false;
 +            // shouldn't even come here as network is being cleaned up after all network elements are shutdown
 +            s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex);
 +        }
 +
 +        //remove all LB rules for the network
 +        if (_lbMgr.removeAllLoadBalanacersForNetwork(networkId, caller, callerUserId)) {
 +            s_logger.debug("Successfully cleaned up load balancing rules for network id=" + networkId);
 +        } else {
 +            // shouldn't even come here as network is being cleaned up after all network elements are shutdown
 +            success = false;
 +            s_logger.warn("Failed to cleanup LB rules as a part of network id=" + networkId + " cleanup");
 +        }
 +
 +        //revoke all firewall rules for the network
 +        try {
 +            if (_firewallMgr.revokeAllFirewallRulesForNetwork(networkId, callerUserId, caller)) {
 +                s_logger.debug("Successfully cleaned up firewallRules rules for network id=" + networkId);
 +            } else {
 +                success = false;
 +                s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup");
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            success = false;
 +            // shouldn't even come here as network is being cleaned up after all network elements are shutdown
 +            s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex);
 +        }
 +
 +        //revoke all network ACLs for network
 +        try {
 +            if (_networkACLMgr.revokeACLItemsForNetwork(networkId)) {
 +                s_logger.debug("Successfully cleaned up NetworkACLs for network id=" + networkId);
 +            } else {
 +                success = false;
 +                s_logger.warn("Failed to cleanup NetworkACLs as a part of network id=" + networkId + " cleanup");
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            success = false;
 +            s_logger.warn("Failed to cleanup Network ACLs as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex);
 +        }
 +
 +        //release all ip addresses
 +        final List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null);
 +        for (final IPAddressVO ipToRelease : ipsToRelease) {
 +            if (ipToRelease.getVpcId() == null) {
 +                if (!ipToRelease.isPortable()) {
 +                    final IPAddressVO ip = _ipAddrMgr.markIpAsUnavailable(ipToRelease.getId());
 +                    assert ip != null : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable.";
 +                } else {
 +                    // portable IP address are associated with owner, until explicitly requested to be disassociated
 +                    // so as part of network clean up just break IP association with guest network
 +                    ipToRelease.setAssociatedWithNetworkId(null);
 +                    _ipAddressDao.update(ipToRelease.getId(), ipToRelease);
 +                    s_logger.debug("Portable IP address " + ipToRelease + " is no longer associated with any network");
 +                }
 +            } else {
 +                _vpcMgr.unassignIPFromVpcNetwork(ipToRelease.getId(), network.getId());
 +            }
 +        }
 +
 +        try {
 +            if (!_ipAddrMgr.applyIpAssociations(network, true)) {
 +                s_logger.warn("Unable to apply ip address associations for " + network);
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException e) {
 +            throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e);
 +        }
 +
 +        return success;
 +    }
 +
 +    private boolean shutdownNetworkResources(final long networkId, final Account caller, final long callerUserId) {
 +        // This method cleans up network rules on the backend w/o touching them in the DB
 +        boolean success = true;
 +        final Network network = _networksDao.findById(networkId);
 +
 +        // Mark all PF rules as revoked and apply them on the backend (not in the DB)
 +        final List<PortForwardingRuleVO> pfRules = _portForwardingRulesDao.listByNetwork(networkId);
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Releasing " + pfRules.size() + " port forwarding rules for network id=" + networkId + " as a part of shutdownNetworkRules");
 +        }
 +
 +        for (final PortForwardingRuleVO pfRule : pfRules) {
 +            s_logger.trace("Marking pf rule " + pfRule + " with Revoke state");
 +            pfRule.setState(FirewallRule.State.Revoke);
 +        }
 +
 +        try {
 +            if (!_firewallMgr.applyRules(pfRules, true, false)) {
 +                s_logger.warn("Failed to cleanup pf rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup pf rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        // Mark all static rules as revoked and apply them on the backend (not in the DB)
 +        final List<FirewallRuleVO> firewallStaticNatRules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.StaticNat);
 +        final List<StaticNatRule> staticNatRules = new ArrayList<StaticNatRule>();
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Releasing " + firewallStaticNatRules.size() + " static nat rules for network id=" + networkId + " as a part of shutdownNetworkRules");
 +        }
 +
 +        for (final FirewallRuleVO firewallStaticNatRule : firewallStaticNatRules) {
 +            s_logger.trace("Marking static nat rule " + firewallStaticNatRule + " with Revoke state");
 +            final IpAddress ip = _ipAddressDao.findById(firewallStaticNatRule.getSourceIpAddressId());
 +            final FirewallRuleVO ruleVO = _firewallDao.findById(firewallStaticNatRule.getId());
 +
 +            if (ip == null || !ip.isOneToOneNat() || ip.getAssociatedWithVmId() == null) {
 +                throw new InvalidParameterValueException("Source ip address of the rule id=" + firewallStaticNatRule.getId() + " is not static nat enabled");
 +            }
 +
 +            //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId());
 +            ruleVO.setState(FirewallRule.State.Revoke);
 +            staticNatRules.add(new StaticNatRuleImpl(ruleVO, ip.getVmIp()));
 +        }
 +
 +        try {
 +            if (!_firewallMgr.applyRules(staticNatRules, true, false)) {
 +                s_logger.warn("Failed to cleanup static nat rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup static nat rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        try {
 +            if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Public)) {
 +                s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        try {
 +            if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Internal)) {
 +                s_logger.warn("Failed to cleanup internal lb rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        // revoke all firewall rules for the network w/o applying them on the DB
 +        final List<FirewallRuleVO> firewallRules = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Ingress);
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Releasing " + firewallRules.size() + " firewall ingress rules for network id=" + networkId + " as a part of shutdownNetworkRules");
 +        }
 +
 +        for (final FirewallRuleVO firewallRule : firewallRules) {
 +            s_logger.trace("Marking firewall ingress rule " + firewallRule + " with Revoke state");
 +            firewallRule.setState(FirewallRule.State.Revoke);
 +        }
 +
 +        try {
 +            if (!_firewallMgr.applyRules(firewallRules, true, false)) {
 +                s_logger.warn("Failed to cleanup firewall ingress rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup firewall ingress rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        final List<FirewallRuleVO> firewallEgressRules = _firewallDao.listByNetworkPurposeTrafficType(networkId, Purpose.Firewall, FirewallRule.TrafficType.Egress);
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Releasing " + firewallEgressRules.size() + " firewall egress rules for network id=" + networkId + " as a part of shutdownNetworkRules");
 +        }
 +
 +        try {
 +            // delete default egress rule
 +            final DataCenter zone = _dcDao.findById(network.getDataCenterId());
 +            if (_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(), _networkModel.getNetworkEgressDefaultPolicy(networkId), false);
 +            }
 +
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup firewall default egress rule as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        for (final FirewallRuleVO firewallRule : firewallEgressRules) {
 +            s_logger.trace("Marking firewall egress rule " + firewallRule + " with Revoke state");
 +            firewallRule.setState(FirewallRule.State.Revoke);
 +        }
 +
 +        try {
 +            if (!_firewallMgr.applyRules(firewallEgressRules, true, false)) {
 +                s_logger.warn("Failed to cleanup firewall egress rules as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException ex) {
 +            s_logger.warn("Failed to cleanup firewall egress rules as a part of shutdownNetworkRules due to ", ex);
 +            success = false;
 +        }
 +
 +        if (network.getVpcId() != null) {
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("Releasing Network ACL Items for network id=" + networkId + " as a part of shutdownNetworkRules");
 +            }
 +
 +            try {
 +                //revoke all Network ACLs for the network w/o applying them in the DB
 +                if (!_networkACLMgr.revokeACLItemsForNetwork(networkId)) {
 +                    s_logger.warn("Failed to cleanup network ACLs as a part of shutdownNetworkRules");
 +                    success = false;
 +                }
 +            } catch (final ResourceUnavailableException ex) {
 +                s_logger.warn("Failed to cleanup network ACLs as a part of shutdownNetworkRules due to ", ex);
 +                success = false;
 +            }
 +
 +        }
 +
 +        //release all static nats for the network
 +        if (!_rulesMgr.applyStaticNatForNetwork(networkId, false, caller, true)) {
 +            s_logger.warn("Failed to disable static nats as part of shutdownNetworkRules for network id " + networkId);
 +            success = false;
 +        }
 +
 +        // Get all ip addresses, mark as releasing and release them on the backend
 +        final List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(networkId, null);
 +        final List<PublicIp> publicIpsToRelease = new ArrayList<PublicIp>();
 +        if (userIps != null && !userIps.isEmpty()) {
 +            for (final IPAddressVO userIp : userIps) {
 +                userIp.setState(IpAddress.State.Releasing);
 +                final PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
 +                publicIpsToRelease.add(publicIp);
 +            }
 +        }
 +
 +        try {
 +            if (!_ipAddrMgr.applyIpAssociations(network, true, true, publicIpsToRelease)) {
 +                s_logger.warn("Unable to apply ip address associations for " + network + " as a part of shutdownNetworkRules");
 +                success = false;
 +            }
 +        } catch (final ResourceUnavailableException e) {
 +            throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e);
 +        }
 +
 +        return success;
 +    }
 +
 +    @Override
 +    public boolean processAnswers(final long agentId, final long seq, final Answer[] answers) {
 +        return false;
 +    }
 +
 +    @Override
 +    public boolean processCommands(final long agentId, final long seq, final Command[] commands) {
 +        return false;
 +    }
 +
 +    @Override
 +    public AgentControlAnswer processControlCommand(final long agentId, final AgentControlCommand cmd) {
 +        return null;
 +    }
 +
 +    public void processHostAdded(long hostId) {
 +    }
 +
 +    @Override
 +    public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException {
 +        if (!(cmd instanceof StartupRoutingCommand)) {
 +            return;
 +        }
 +        final long hostId = host.getId();
 +        final StartupRoutingCommand startup = (StartupRoutingCommand)cmd;
 +
 +        final String dataCenter = startup.getDataCenter();
 +
 +        long dcId = -1;
 +        DataCenterVO dc = _dcDao.findByName(dataCenter);
 +        if (dc == null) {
 +            try {
 +                dcId = Long.parseLong(dataCenter);
 +                dc = _dcDao.findById(dcId);
 +            } catch (final NumberFormatException e) {
 +            }
 +        }
 +        if (dc == null) {
 +            throw new IllegalArgumentException("Host " + startup.getPrivateIpAddress() + " sent incorrect data center: " + dataCenter);
 +        }
 +        dcId = dc.getId();
 +        final HypervisorType hypervisorType = startup.getHypervisorType();
 +
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Host's hypervisorType is: " + hypervisorType);
 +        }
 +
 +        final List<PhysicalNetworkSetupInfo> networkInfoList = new ArrayList<PhysicalNetworkSetupInfo>();
 +
 +        // list all physicalnetworks in the zone & for each get the network names
 +        final List<PhysicalNetworkVO> physicalNtwkList = _physicalNetworkDao.listByZone(dcId);
 +        for (final PhysicalNetworkVO pNtwk : physicalNtwkList) {
 +            final String publicName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Public, hypervisorType);
 +            final String privateName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Management, hypervisorType);
 +            final String guestName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Guest, hypervisorType);
 +            final String storageName = _pNTrafficTypeDao.getNetworkTag(pNtwk.getId(), TrafficType.Storage, hypervisorType);
 +            // String controlName = _pNTrafficTypeDao._networkModel.getNetworkTag(pNtwk.getId(), TrafficType.Control, hypervisorType);
 +            final PhysicalNetworkSetupInfo info = new PhysicalNetworkSetupInfo();
 +            info.setPhysicalNetworkId(pNtwk.getId());
 +            info.setGuestNetworkName(guestName);
 +            info.setPrivateNetworkName(privateName);
 +            info.setPublicNetworkName(publicName);
 +            info.setStorageNetworkName(storageName);
 +            final PhysicalNetworkTrafficTypeVO mgmtTraffic = _pNTrafficTypeDao.findBy(pNtwk.getId(), TrafficType.Management);
 +            if (mgmtTraffic != null) {
 +                final String vlan = mgmtTraffic.getVlan();
 +                info.setMgmtVlan(vlan);
 +            }
 +            networkInfoList.add(info);
 +        }
 +
 +        // send the names to the agent
 +        if (s_logger.isDebugEnabled()) {
 +            s_logger.debug("Sending CheckNetworkCommand to check the Network is setup correctly on Agent");
 +        }
 +        final CheckNetworkCommand nwCmd = new CheckNetworkCommand(networkInfoList);
 +
 +        final CheckNetworkAnswer answer = (CheckNetworkAnswer)_agentMgr.easySend(hostId, nwCmd);
 +
 +        if (answer == null) {
 +            s_logger.warn("Unable to get an answer to the CheckNetworkCommand from agent:" + host.getId());
 +            throw new ConnectionException(true, "Unable to get an answer to the CheckNetworkCommand from agent: " + host.getId());
 +        }
 +
 +        if (!answer.getResult()) {
 +            s_logger.warn("Unable to setup agent " + hostId + " due to " + answer.getDetails() );
 +            final String msg = "Incorrect Network setup on agent, Reinitialize agent after network names are setup, details : " + answer.getDetails();
 +            _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, host.getPodId(), msg, msg);
 +            throw new ConnectionException(true, msg);
 +        } else {
 +            if (answer.needReconnect()) {
 +                throw new ConnectionException(false, "Reinitialize agent after network setup.");
 +            }
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("Network setup is correct on Agent");
 +            }
 +            return;
 +        }
 +    }
 +
 +    @Override
 +    public boolean processDisconnect(final long agentId, final Status state) {
 +        return false;
 +    }
 +
 +    @Override
 +    public void processHostAboutToBeRemoved(long hostId) {
 +    }
 +
 +    @Override
 +    public void processHostRemoved(long hostId, long clusterId) {
 +    }
 +
 +    @Override
 +    public boolean isRecurring() {
 +        return false;
 +    }
 +
 +    @Override
 +    public int getTimeout() {
 +        return 0;
 +    }
 +
 +    @Override
 +    public boolean processTimeout(final long agentId, final long seq) {
 +        return false;
 +    }
 +
 +    @Override
 +    public Map<String, String> finalizeServicesAndProvidersForNetwork(final NetworkOffering offering, final Long physicalNetworkId) {
 +        final Map<String, String> svcProviders = new HashMap<String, String>();
 +        final Map<String, List<String>> providerSvcs = new HashMap<String, List<String>>();
 +        final List<NetworkOfferingServiceMapVO> servicesMap = _ntwkOfferingSrvcDao.listByNetworkOfferingId(offering.getId());
 +
 +        final boolean checkPhysicalNetwork = physicalNetworkId != null ? true : false;
 +
 +        for (final NetworkOfferingServiceMapVO serviceMap : servicesMap) {
 +            if (svcProviders.containsKey(serviceMap.getService())) {
 +                // FIXME - right now we pick up the first provider from the list, need to add more logic based on
 +                // provider load, etc
 +                continue;
 +            }
 +
 +            final String service = serviceMap.getService();
 +            String provider = serviceMap.getProvider();
 +
 +            if (provider == null) {
 +                provider = _networkModel.getDefaultUniqueProviderForService(service).getName();
 +            }
 +
 +            // check that provider is supported
 +            if (checkPhysicalNetwork) {
 +                if (!_pNSPDao.isServiceProviderEnabled(physicalNetworkId, provider, service)) {
 +                    throw new UnsupportedServiceException("Provider " + provider + " is either not enabled or doesn't " + "support service " + service + " in physical network id="
 +                            + physicalNetworkId);
 +                }
 +            }
 +
 +            svcProviders.put(service, provider);
 +            List<String> l = providerSvcs.get(provider);
 +            if (l == null) {
 +                providerSvcs.put(provider, l = new ArrayList<String>());
 +            }
 +            l.add(service);
 +        }
 +
 +        return svcProviders;
 +    }
 +
 +    private List<Provider> getNetworkProviders(final long networkId) {
 +        final List<String> providerNames = _ntwkSrvcDao.getDistinctProviders(networkId);
 +        final List<Provider> providers = new ArrayList<Provider>();
 +        for (final String providerName : providerNames) {
 +            providers.add(Network.Provider.getProvider(providerName));
 +        }
 +
 +        return providers;
 +    }
 +
 +    @Override
 +    public boolean setupDns(final Network network, final Provider provider) {
 +        final boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, provider);
 +        final boolean dhcpProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, provider);
 +
 +        final boolean setupDns = dnsProvided || dhcpProvided;
 +        return setupDns;
 +    }
 +
 +    protected NicProfile getNicProfileForVm(final Network network, final NicProfile requested, final VirtualMachine vm) {
 +        NicProfile nic = null;
 +        if (requested != null && requested.getBroadCastUri() != null) {
 +            final String broadcastUri = requested.getBroadCastUri().toString();
 +            final String ipAddress = requested.getIPv4Address();
 +            final NicVO nicVO = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(network.getId(), vm.getId(), broadcastUri);
 +            if (nicVO != null) {
 +                if (ipAddress == null || nicVO.getIPv4Address().equals(ipAddress)) {
 +                    nic = _networkModel.getNicProfile(vm, network.getId(), broadcastUri);
 +                }
 +            }
 +        } else {
 +            final NicVO nicVO = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId());
 +            if (nicVO != null) {
 +                nic = _networkModel.getNicProfile(vm, network.getId(), null);
 +            }
 +        }
 +        return nic;
 +    }
 +
 +    @Override
 +    public NicProfile createNicForVm(final Network network, final NicProfile requested, final ReservationContext context, final VirtualMachineProfile vmProfile, final boolean prepare)
 +            throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException,
 +            ResourceUnavailableException {
 +
 +        final VirtualMachine vm = vmProfile.getVirtualMachine();
 +        final DataCenter dc = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
 +        final Host host = _hostDao.findById(vm.getHostId());
 +        final DeployDestination dest = new DeployDestination(dc, null, null, host);
 +
 +        NicProfile nic = getNicProfileForVm(network, requested, vm);
 +
 +        //1) allocate nic (if needed) Always allocate if it is a user vm
 +        if (nic == null || vmProfile.getType() == VirtualMachine.Type.User) {
 +            final int deviceId = _nicDao.getFreeDeviceId(vm.getId());
 +
 +            nic = allocateNic(requested, network, false, deviceId, vmProfile).first();
 +
 +            if (nic == null) {
 +                throw new CloudRuntimeException("Failed to allocate nic for vm " + vm + " in network " + network);
 +            }
 +
 +            //Update vm_network_map table
 +            if(vmProfile.getType() == VirtualMachine.Type.User) {
 +                final VMNetworkMapVO vno = new VMNetworkMapVO(vm.getId(), network.getId());
 +                _vmNetworkMapDao.persist(vno);
 +            }
 +            s_logger.debug("Nic is allocated successfully for vm " + vm + " in network " + network);
 +        }
 +
 +        //2) prepare nic
 +        if (prepare) {
 +            final Pair<NetworkGuru, NetworkVO> implemented = implementNetwork(nic.getNetworkId(), dest, context, vmProfile.getVirtualMachine().getType() == Type.DomainRouter);
 +            if (implemented == null || 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());
 +            }
 +            nic = prepareNic(vmProfile, dest, context, nic.getId(), implemented.second());
 +            s_logger.debug("Nic is prepared successfully for vm " + vm + " in network " + network);
 +        }
 +
 +        return nic;
 +    }
 +
 +    @Override
 +    public List<NicProfile> getNicProfiles(final VirtualMachine vm) {
 +        final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
 +        final List<NicProfile> profiles = new ArrayList<NicProfile>();
 +
 +        if (nics != null) {
 +            for (final Nic nic : nics) {
 +                final NetworkVO network = _networksDao.findById(nic.getNetworkId());
 +                final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
 +
 +                final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
 +                final NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate,
 +                        _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network));
 +                guru.updateNicProfile(profile, network);
 +                profiles.add(profile);
 +            }
 +        }
 +        return profiles;
 +    }
 +
 +    @Override
 +    public Map<String, String> getSystemVMAccessDetails(final VirtualMachine vm) {
 +        final Map<String, String> accessDetails = new HashMap<>();
 +        accessDetails.put(NetworkElementCommand.ROUTER_NAME, vm.getInstanceName());
 +        String privateIpAddress = null;
 +        for (final NicProfile profile : getNicProfiles(vm)) {
 +            if (profile == null) {
 +                continue;
 +            }
 +            final Network network = _networksDao.findById(profile.getNetworkId());
 +            if (network == null) {
 +                continue;
 +            }
 +            final String address = profile.getIPv4Address();
 +            if (network.getTrafficType() == Networks.TrafficType.Control) {
 +                accessDetails.put(NetworkElementCommand.ROUTER_IP, address);
 +            }
 +            if (network.getTrafficType() == Networks.TrafficType.Guest) {
 +                accessDetails.put(NetworkElementCommand.ROUTER_GUEST_IP, address);
 +            }
 +            if (network.getTrafficType() == Networks.TrafficType.Management) {
 +                privateIpAddress = address;
 +            }
 +            if (network.getTrafficType() != null && !Strings.isNullOrEmpty(address)) {
 +                accessDetails.put(network.getTrafficType().name(), address);
 +            }
 +        }
 +        if (privateIpAddress != null && Strings.isNullOrEmpty(accessDetails.get(NetworkElementCommand.ROUTER_IP))) {
 +            accessDetails.put(NetworkElementCommand.ROUTER_IP,  privateIpAddress);
 +        }
 +        return accessDetails;
 +    }
 +
 +    protected boolean stateTransitTo(final NetworkVO network, final Network.Event e) throws NoTransitionException {
 +        return _stateMachine.transitTo(network, e, null, _networksDao);
 +    }
 +
 +    private void setStateMachine() {
 +        _stateMachine = Network.State.getStateMachine();
 +    }
 +
 +    private Map<Service, Set<Provider>> getServiceProvidersMap(final long networkId) {
 +        final Map<Service, Set<Provider>> map = new HashMap<Service, Set<Provider>>();
 +        final List<NetworkServiceMapVO> nsms = _ntwkSrvcDao.getServicesInNetwork(networkId);
 +        for (final NetworkServiceMapVO nsm : nsms) {
 +            Set<Provider> providers = map.get(Service.getService(nsm.getService()));
 +            if (providers == null) {
 +                providers = new HashSet<Provider>();
 +            }
 +            providers.add(Provider.getProvider(nsm.getProvider()));
 +            map.put(Service.getService(nsm.getService()), providers);
 +        }
 +        return map;
 +    }
 +
 +    @Override
 +    public List<Provider> getProvidersForServiceInNetwork(final Network network, final Service service) {
 +        final Map<Service, Set<Provider>> service2ProviderMap = getServiceProvidersMap(network.getId());
 +        if (service2ProviderMap.get(service) != null) {
 +            final List<Provider> providers = new ArrayList<Provider>(service2ProviderMap.get(service));
 +            return providers;
 +        }
 +        return null;
 +    }
 +
 +    protected List<NetworkElement> getElementForServiceInNetwork(final Network network, final Service service) {
 +        final List<NetworkElement> elements = new ArrayList<NetworkElement>();
 +        final List<Provider> providers = getProvidersForServiceInNetwork(network, service);
 +        //Only support one provider now
 +        if (providers == null) {
 +            s_logger.error("Cannot find " + service.getName() + " provider for network " + network.getId());
 +            return null;
 +        }
 +        if (providers.size() != 1 && service != Service.Lb) {
 +            //support more than one LB providers only
 +            s_logger.error("Found " + providers.size() + " " + service.getName() + " providers for network!" + network.getId());
 +            return null;
 +        }
 +
 +        for (final Provider provider : providers) {
 +            final NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName());
 +            s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId());
 +            elements.add(element);
 +        }
 +        return elements;
 +    }
 +
 +    @Override
 +    public StaticNatServiceProvider getStaticNatProviderForNetwork(final Network network) {
 +        //only one provider per Static nat service is supoprted
 +        final NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat).get(0);
 +        assert element instanceof StaticNatServiceProvider;
 +        return (StaticNatServiceProvider)element;
 +    }
 +
 +    @Override
 +    public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(final Network network, final Scheme lbScheme) {
 +        final List<NetworkElement> lbElements = getElementForServiceInNetwork(network, Service.Lb);
 +        NetworkElement lbElement = null;
 +        if (lbElements.size() > 1) {
 +            String providerName = null;
 +            //get network offering details
 +            final NetworkOffering off = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
 +            if (lbScheme == Scheme.Public) {
 +                providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.PublicLbProvider);
 +            } else {
 +                providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.InternalLbProvider);
 +            }
 +            if (providerName == null) {
 +                throw new InvalidParameterValueException("Can't find Lb provider supporting scheme " + lbScheme.toString() + " in network " + network);
 +            }
 +            lbElement = _networkModel.getElementImplementingProvider(providerName);
 +        } else if (lbElements.size() == 1) {
 +            lbElement = lbElements.get(0);
 +        }
 +
 +        assert lbElement != null;
 +        assert lbElement instanceof LoadBalancingServiceProvider;
 +        return (LoadBalancingServiceProvider)lbElement;
 +    }
 +
 +    @Override
 +    public boolean isNetworkInlineMode(final Network network) {
 +        final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
 +        return offering.isInline();
 +    }
 +
 +    @Override
 +    public boolean isSecondaryIpSetForNic(final long nicId) {
 +        final NicVO nic = _nicDao.findById(nicId);
 +        return nic.getSecondaryIp();
 +    }
 +
 +    private boolean removeVmSecondaryIpsOfNic(final long nicId) {
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                final List<NicSecondaryIpVO> ipList = _nicSecondaryIpDao.listByNicId(nicId);
 +                if (ipList != null) {
 +                    for (final NicSecondaryIpVO ip : ipList) {
 +                        _nicSecondaryIpDao.remove(ip.getId());
 +                    }
 +                    s_logger.debug("Revoving nic secondary ip entry ...");
 +                }
 +            }
 +        });
 +
 +        return true;
 +    }
 +
 +    @Override
 +    public NicVO savePlaceholderNic(final Network network, final String ip4Address, final String ip6Address, final Type vmType) {
 +        final NicVO nic = new NicVO(null, null, network.getId(), null);
 +        nic.setIPv4Address(ip4Address);
 +        nic.setIPv6Address(ip6Address);
 +        nic.setReservationStrategy(ReservationStrategy.PlaceHolder);
 +        nic.setState(Nic.State.Reserved);
 +        nic.setVmType(vmType);
 +        return _nicDao.persist(nic);
 +    }
 +
 +    @Override
 +    public String getConfigComponentName() {
 +        return NetworkOrchestrationService.class.getSimpleName();
 +    }
 +
 +    public static final ConfigKey<Integer> NetworkGcWait = new ConfigKey<Integer>(Integer.class, "network.gc.wait", "Advanced", "600",
 +            "Time (in seconds) to wait before shutting down a network that's not in used", false, Scope.Global, null);
 +    public static final ConfigKey<Integer> NetworkGcInterval = new ConfigKey<Integer>(Integer.class, "network.gc.interval", "Advanced", "600",
 +            "Seconds to wait before checking for networks to shutdown", true, Scope.Global, null);
 +
 +    @Override
 +    public ConfigKey<?>[] getConfigKeys() {
 +        return new ConfigKey<?>[] {NetworkGcWait, NetworkGcInterval, NetworkLockTimeout,
 +                GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion,
-                 PromiscuousMode, MacAddressChanges, ForgedTransmits};
++                PromiscuousMode, MacAddressChanges, ForgedTransmits, RollingRestartEnabled};
 +    }
 +}
diff --cc server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 422992e,0000000..0447f7e
mode 100644,000000..100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@@ -1,2498 -1,0 +1,2505 @@@
 +// 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.vpc;
 +
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Iterator;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.Set;
 +import java.util.concurrent.ExecutionException;
 +import java.util.concurrent.ExecutorService;
 +import java.util.concurrent.Executors;
 +import java.util.concurrent.Future;
 +import java.util.concurrent.ScheduledExecutorService;
 +import java.util.concurrent.TimeUnit;
 +
 +import javax.annotation.PostConstruct;
 +import javax.inject.Inject;
 +import javax.naming.ConfigurationException;
 +
 +import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 +import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd;
 +import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
 +import org.apache.cloudstack.context.CallContext;
 +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 +import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 +import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 +import org.apache.commons.collections.CollectionUtils;
 +import org.apache.log4j.Logger;
 +
 +import com.cloud.configuration.Config;
 +import com.cloud.configuration.Resource.ResourceType;
 +import com.cloud.dc.DataCenter;
 +import com.cloud.dc.DataCenterVO;
 +import com.cloud.dc.Vlan.VlanType;
 +import com.cloud.dc.VlanVO;
 +import com.cloud.dc.dao.DataCenterDao;
 +import com.cloud.dc.dao.VlanDao;
 +import com.cloud.deploy.DeployDestination;
 +import com.cloud.event.ActionEvent;
 +import com.cloud.event.EventTypes;
 +import com.cloud.exception.ConcurrentOperationException;
 +import com.cloud.exception.InsufficientAddressCapacityException;
 +import com.cloud.exception.InsufficientCapacityException;
 +import com.cloud.exception.InvalidParameterValueException;
 +import com.cloud.exception.NetworkRuleConflictException;
 +import com.cloud.exception.PermissionDeniedException;
 +import com.cloud.exception.ResourceAllocationException;
 +import com.cloud.exception.ResourceUnavailableException;
 +import com.cloud.hypervisor.Hypervisor.HypervisorType;
 +import com.cloud.network.IpAddress;
 +import com.cloud.network.IpAddressManager;
 +import com.cloud.network.Network;
 +import com.cloud.network.Network.Capability;
 +import com.cloud.network.Network.GuestType;
 +import com.cloud.network.Network.Provider;
 +import com.cloud.network.Network.Service;
 +import com.cloud.network.NetworkModel;
 +import com.cloud.network.NetworkService;
 +import com.cloud.network.Networks.BroadcastDomainType;
 +import com.cloud.network.Networks.TrafficType;
 +import com.cloud.network.PhysicalNetwork;
 +import com.cloud.network.addr.PublicIp;
 +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.NetworkVO;
 +import com.cloud.network.element.NetworkElement;
 +import com.cloud.network.element.StaticNatServiceProvider;
 +import com.cloud.network.element.VpcProvider;
 +import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
 +import com.cloud.network.vpc.VpcOffering.State;
 +import com.cloud.network.vpc.dao.NetworkACLDao;
 +import com.cloud.network.vpc.dao.PrivateIpDao;
 +import com.cloud.network.vpc.dao.StaticRouteDao;
 +import com.cloud.network.vpc.dao.VpcDao;
 +import com.cloud.network.vpc.dao.VpcGatewayDao;
 +import com.cloud.network.vpc.dao.VpcOfferingDao;
 +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
 +import com.cloud.network.vpc.dao.VpcServiceMapDao;
 +import com.cloud.network.vpn.Site2SiteVpnManager;
 +import com.cloud.offering.NetworkOffering;
 +import com.cloud.offerings.NetworkOfferingServiceMapVO;
 +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 +import com.cloud.org.Grouping;
 +import com.cloud.projects.Project.ListProjectResourcesCriteria;
 +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.ResourceLimitService;
 +import com.cloud.user.User;
 +import com.cloud.utils.NumbersUtil;
 +import com.cloud.utils.Pair;
 +import com.cloud.utils.StringUtils;
 +import com.cloud.utils.Ternary;
 +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.Filter;
 +import com.cloud.utils.db.GlobalLock;
 +import com.cloud.utils.db.JoinBuilder;
 +import com.cloud.utils.db.SearchBuilder;
 +import com.cloud.utils.db.SearchCriteria;
 +import com.cloud.utils.db.SearchCriteria.Op;
 +import com.cloud.utils.db.Transaction;
 +import com.cloud.utils.db.TransactionCallback;
 +import com.cloud.utils.db.TransactionCallbackNoReturn;
 +import com.cloud.utils.db.TransactionCallbackWithException;
 +import com.cloud.utils.db.TransactionStatus;
 +import com.cloud.utils.exception.CloudRuntimeException;
 +import com.cloud.utils.exception.ExceptionUtil;
 +import com.cloud.utils.net.NetUtils;
 +import com.cloud.vm.DomainRouterVO;
 +import com.cloud.vm.ReservationContext;
 +import com.cloud.vm.ReservationContextImpl;
 +import com.cloud.vm.dao.DomainRouterDao;
 +
 +public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvisioningService, VpcService {
 +    private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class);
 +
 +    public static final String SERVICE = "service";
 +    public static final String CAPABILITYTYPE = "capabilitytype";
 +    public static final String CAPABILITYVALUE = "capabilityvalue";
 +    public static final String TRUE_VALUE = "true";
 +    public static final String FALSE_VALUE = "false";
 +
 +    @Inject
 +    EntityManager _entityMgr;
 +    @Inject
 +    VpcOfferingDao _vpcOffDao;
 +    @Inject
 +    VpcOfferingServiceMapDao _vpcOffSvcMapDao;
 +    @Inject
 +    VpcDao _vpcDao;
 +    @Inject
 +    ConfigurationDao _configDao;
 +    @Inject
 +    AccountManager _accountMgr;
 +    @Inject
 +    NetworkDao _ntwkDao;
 +    @Inject
 +    NetworkOrchestrationService _ntwkMgr;
 +    @Inject
 +    NetworkModel _ntwkModel;
 +    @Inject
 +    NetworkService _ntwkSvc;
 +    @Inject
 +    IPAddressDao _ipAddressDao;
 +    @Inject
 +    VpcGatewayDao _vpcGatewayDao;
 +    @Inject
 +    PrivateIpDao _privateIpDao;
 +    @Inject
 +    StaticRouteDao _staticRouteDao;
 +    @Inject
 +    NetworkOfferingServiceMapDao _ntwkOffServiceDao;
 +    @Inject
 +    VpcOfferingServiceMapDao _vpcOffServiceDao;
 +    @Inject
 +    ResourceTagDao _resourceTagDao;
 +    @Inject
 +    FirewallRulesDao _firewallDao;
 +    @Inject
 +    Site2SiteVpnManager _s2sVpnMgr;
 +    @Inject
 +    VlanDao _vlanDao = null;
 +    @Inject
 +    ResourceLimitService _resourceLimitMgr;
 +    @Inject
 +    VpcServiceMapDao _vpcSrvcDao;
 +    @Inject
 +    DataCenterDao _dcDao;
 +    @Inject
 +    NetworkACLDao _networkAclDao;
 +    @Inject
 +    NetworkACLManager _networkAclMgr;
 +    @Inject
 +    IpAddressManager _ipAddrMgr;
 +    @Inject
 +    VpcVirtualNetworkApplianceManager _routerService;
 +    @Inject
 +    DomainRouterDao _routerDao;
 +
 +    @Inject
 +    private VpcPrivateGatewayTransactionCallable vpcTxCallable;
 +
 +    private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
 +    private List<VpcProvider> vpcElements = null;
 +    private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
 +    private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler,
 +            Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.NuageVsp, Provider.BigSwitchBcf, Provider.ConfigDrive);
 +
 +    int _cleanupInterval;
 +    int _maxNetworks;
 +    SearchBuilder<IPAddressVO> IpAddressSearch;
 +
 +    protected final List<HypervisorType> hTypes = new ArrayList<HypervisorType>();
 +
 +    @PostConstruct
 +    protected void setupSupportedVpcHypervisorsList() {
 +        hTypes.add(HypervisorType.XenServer);
 +        hTypes.add(HypervisorType.VMware);
 +        hTypes.add(HypervisorType.KVM);
 +        hTypes.add(HypervisorType.Simulator);
 +        hTypes.add(HypervisorType.LXC);
 +        hTypes.add(HypervisorType.Hyperv);
 +        hTypes.add(HypervisorType.Ovm3);
 +    }
 +
 +    @Override
 +    @DB
 +    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
 +        // configure default vpc offering
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +
 +                if (_vpcOffDao.findByUniqueName(VpcOffering.defaultVPCOfferingName) == null) {
 +                    s_logger.debug("Creating default VPC offering " + VpcOffering.defaultVPCOfferingName);
 +
 +                    final Map<Service, Set<Provider>> svcProviderMap = new HashMap<Service, Set<Provider>>();
 +                    final Set<Provider> defaultProviders = new HashSet<Provider>();
 +                    defaultProviders.add(Provider.VPCVirtualRouter);
 +                    for (final Service svc : getSupportedServices()) {
 +                        if (svc == Service.Lb) {
 +                            final Set<Provider> lbProviders = new HashSet<Provider>();
 +                            lbProviders.add(Provider.VPCVirtualRouter);
 +                            lbProviders.add(Provider.InternalLbVm);
 +                            svcProviderMap.put(svc, lbProviders);
 +                        } else {
 +                            svcProviderMap.put(svc, defaultProviders);
 +                        }
 +                    }
 +                    createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, false, false);
 +                }
 +
 +                // configure default vpc offering with Netscaler as LB Provider
 +                if (_vpcOffDao.findByUniqueName(VpcOffering.defaultVPCNSOfferingName) == null) {
 +                    s_logger.debug("Creating default VPC offering with Netscaler as LB Provider" + VpcOffering.defaultVPCNSOfferingName);
 +                    final Map<Service, Set<Provider>> svcProviderMap = new HashMap<Service, Set<Provider>>();
 +                    final Set<Provider> defaultProviders = new HashSet<Provider>();
 +                    defaultProviders.add(Provider.VPCVirtualRouter);
 +                    for (final Service svc : getSupportedServices()) {
 +                        if (svc == Service.Lb) {
 +                            final Set<Provider> lbProviders = new HashSet<Provider>();
 +                            lbProviders.add(Provider.Netscaler);
 +                            lbProviders.add(Provider.InternalLbVm);
 +                            svcProviderMap.put(svc, lbProviders);
 +                        } else {
 +                            svcProviderMap.put(svc, defaultProviders);
 +                        }
 +                    }
 +                    createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, svcProviderMap, false, State.Enabled, null, false, false, false);
 +
 +                }
 +
 +                if (_vpcOffDao.findByUniqueName(VpcOffering.redundantVPCOfferingName) == null) {
 +                    s_logger.debug("Creating Redundant VPC offering " + VpcOffering.redundantVPCOfferingName);
 +
 +                    final Map<Service, Set<Provider>> svcProviderMap = new HashMap<Service, Set<Provider>>();
 +                    final Set<Provider> defaultProviders = new HashSet<Provider>();
 +                    defaultProviders.add(Provider.VPCVirtualRouter);
 +                    for (final Service svc : getSupportedServices()) {
 +                        if (svc == Service.Lb) {
 +                            final Set<Provider> lbProviders = new HashSet<Provider>();
 +                            lbProviders.add(Provider.VPCVirtualRouter);
 +                            lbProviders.add(Provider.InternalLbVm);
 +                            svcProviderMap.put(svc, lbProviders);
 +                        } else {
 +                            svcProviderMap.put(svc, defaultProviders);
 +                        }
 +                    }
 +                    createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, false, true);
 +                }
 +            }
 +        });
 +
 +        final Map<String, String> configs = _configDao.getConfiguration(params);
 +        final String value = configs.get(Config.VpcCleanupInterval.key());
 +        _cleanupInterval = NumbersUtil.parseInt(value, 60 * 60); // 1 hour
 +
 +        final String maxNtwks = configs.get(Config.VpcMaxNetworks.key());
 +        _maxNetworks = NumbersUtil.parseInt(maxNtwks, 3); // max=3 is default
 +
 +        IpAddressSearch = _ipAddressDao.createSearchBuilder();
 +        IpAddressSearch.and("accountId", IpAddressSearch.entity().getAllocatedToAccountId(), Op.EQ);
 +        IpAddressSearch.and("dataCenterId", IpAddressSearch.entity().getDataCenterId(), Op.EQ);
 +        IpAddressSearch.and("vpcId", IpAddressSearch.entity().getVpcId(), Op.EQ);
 +        IpAddressSearch.and("associatedWithNetworkId", IpAddressSearch.entity().getAssociatedWithNetworkId(), Op.EQ);
 +        final SearchBuilder<VlanVO> virtualNetworkVlanSB = _vlanDao.createSearchBuilder();
 +        virtualNetworkVlanSB.and("vlanType", virtualNetworkVlanSB.entity().getVlanType(), Op.EQ);
 +        IpAddressSearch
 +        .join("virtualNetworkVlanSB", virtualNetworkVlanSB, IpAddressSearch.entity().getVlanId(), virtualNetworkVlanSB.entity().getId(), JoinBuilder.JoinType.INNER);
 +        IpAddressSearch.done();
 +
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean start() {
 +        _executor.scheduleAtFixedRate(new VpcCleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS);
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean stop() {
 +        return true;
 +    }
 +
 +    @Override
 +    public List<? extends Network> getVpcNetworks(final long vpcId) {
 +        return _ntwkDao.listByVpc(vpcId);
 +    }
 +
 +    @Override
 +    public VpcOffering getVpcOffering(final long vpcOffId) {
 +        return _vpcOffDao.findById(vpcOffId);
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true)
 +    public VpcOffering createVpcOffering(final String name, final String displayText, final List<String> supportedServices, final Map<String, List<String>> serviceProviders,
 +            final Map serviceCapabilitystList, final Long serviceOfferingId) {
 +
 +        final Map<Network.Service, Set<Network.Provider>> svcProviderMap = new HashMap<Network.Service, Set<Network.Provider>>();
 +        final Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
 +        defaultProviders.add(Provider.VPCVirtualRouter);
 +        // Just here for 4.1, replaced by commit 836ce6c1 in newer versions
 +        final Set<Network.Provider> sdnProviders = new HashSet<Network.Provider>();
 +        sdnProviders.add(Provider.NiciraNvp);
 +        sdnProviders.add(Provider.JuniperContrailVpcRouter);
 +        sdnProviders.add(Provider.NuageVsp);
 +
 +        boolean sourceNatSvc = false;
 +        boolean firewallSvs = false;
 +        // populate the services first
 +        for (final String serviceName : supportedServices) {
 +            // validate if the service is supported
 +            final Service service = Network.Service.getService(serviceName);
 +            if (service == null || nonSupportedServices.contains(service)) {
 +                throw new InvalidParameterValueException("Service " + serviceName + " is not supported in VPC");
 +            }
 +
 +            if (service == Service.Connectivity) {
 +                s_logger.debug("Applying Connectivity workaround, setting provider to NiciraNvp");
 +                svcProviderMap.put(service, sdnProviders);
 +            } else {
 +                svcProviderMap.put(service, defaultProviders);
 +            }
 +            if (service == Service.NetworkACL) {
 +                firewallSvs = true;
 +            }
 +
 +            if (service == Service.SourceNat) {
 +                sourceNatSvc = true;
 +            }
 +        }
 +
 +        if (!sourceNatSvc) {
 +            s_logger.debug("Automatically adding source nat service to the list of VPC services");
 +            svcProviderMap.put(Service.SourceNat, defaultProviders);
 +        }
 +
 +        if (!firewallSvs) {
 +            s_logger.debug("Automatically adding network ACL service to the list of VPC services");
 +            svcProviderMap.put(Service.NetworkACL, defaultProviders);
 +        }
 +
 +        if (serviceProviders != null) {
 +            for (final Entry<String, List<String>> serviceEntry : serviceProviders.entrySet()) {
 +                final Network.Service service = Network.Service.getService(serviceEntry.getKey());
 +                if (svcProviderMap.containsKey(service)) {
 +                    final Set<Provider> providers = new HashSet<Provider>();
 +                    for (final String prvNameStr : serviceEntry.getValue()) {
 +                        // check if provider is supported
 +                        final Network.Provider provider = Network.Provider.getProvider(prvNameStr);
 +                        if (provider == null) {
 +                            throw new InvalidParameterValueException("Invalid service provider: " + prvNameStr);
 +                        }
 +
 +                        providers.add(provider);
 +                    }
 +                    svcProviderMap.put(service, providers);
 +                } else {
 +                    throw new InvalidParameterValueException("Service " + serviceEntry.getKey() + " is not enabled for the network " + "offering, can't add a provider to it");
 +                }
 +            }
 +        }
 +
 +        // add gateway provider (if sourceNat provider is enabled)
 +        final Set<Provider> sourceNatServiceProviders = svcProviderMap.get(Service.SourceNat);
 +        if (CollectionUtils.isNotEmpty(sourceNatServiceProviders)) {
 +            svcProviderMap.put(Service.Gateway, sourceNatServiceProviders);
 +        }
 +
 +        validateConnectivtyServiceCapabilities(svcProviderMap.get(Service.Connectivity), serviceCapabilitystList);
 +
 +        final boolean supportsDistributedRouter = isVpcOfferingSupportsDistributedRouter(serviceCapabilitystList);
 +        final boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilitystList);
 +        final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilitystList);
 +        final VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC,
 +                redundantRouter);
 +        CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name);
 +
 +        return offering;
 +    }
 +
 +    @DB
 +    protected VpcOffering createVpcOffering(final String name, final String displayText, final Map<Network.Service, Set<Network.Provider>> svcProviderMap,
 +            final boolean isDefault, final State state, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC,
 +            final boolean redundantRouter) {
 +
 +        return Transaction.execute(new TransactionCallback<VpcOffering>() {
 +            @Override
 +            public VpcOffering doInTransaction(final TransactionStatus status) {
 +                // create vpc offering object
 +                VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, redundantRouter);
 +
 +                if (state != null) {
 +                    offering.setState(state);
 +                }
 +                s_logger.debug("Adding vpc offering " + offering);
 +                offering = _vpcOffDao.persist(offering);
 +                // populate services and providers
 +                if (svcProviderMap != null) {
 +                    for (final Network.Service service : svcProviderMap.keySet()) {
 +                        final Set<Provider> providers = svcProviderMap.get(service);
 +                        if (providers != null && !providers.isEmpty()) {
 +                            for (final Network.Provider provider : providers) {
 +                                final VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider);
 +                                _vpcOffSvcMapDao.persist(offService);
 +                                s_logger.trace("Added service for the vpc offering: " + offService + " with provider " + provider.getName());
 +                            }
 +                        } else {
 +                            throw new InvalidParameterValueException("Provider is missing for the VPC offering service " + service.getName());
 +                        }
 +                    }
 +                }
 +
 +                return offering;
 +            }
 +        });
 +    }
 +
 +    protected void checkCapabilityPerServiceProvider(final Set<Provider> providers, final Capability capability, final Service service) {
 +        // TODO Shouldn't it fail it there are no providers?
 +        if (providers != null) {
 +            for (final Provider provider : providers) {
 +                final NetworkElement element = _ntwkModel.getElementImplementingProvider(provider.getName());
 +                final Map<Service, Map<Capability, String>> capabilities = element.getCapabilities();
 +                if (capabilities != null && !capabilities.isEmpty()) {
 +                    final Map<Capability, String> connectivityCapabilities = capabilities.get(service);
 +                    if (connectivityCapabilities == null || connectivityCapabilities != null && !connectivityCapabilities.keySet().contains(capability)) {
 +                        throw new InvalidParameterValueException(String.format("Provider %s does not support %s  capability.", provider.getName(), capability.getName()));
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    private void validateConnectivtyServiceCapabilities(final Set<Provider> providers, final Map serviceCapabilitystList) {
 +        if (serviceCapabilitystList != null && !serviceCapabilitystList.isEmpty()) {
 +            final Collection serviceCapabilityCollection = serviceCapabilitystList.values();
 +            final Iterator iter = serviceCapabilityCollection.iterator();
 +
 +            while (iter.hasNext()) {
 +                final HashMap<String, String> svcCapabilityMap = (HashMap<String, String>) iter.next();
 +                Capability capability = null;
 +                final String svc = svcCapabilityMap.get(SERVICE);
 +                final String capabilityName = svcCapabilityMap.get(CAPABILITYTYPE);
 +                final String capabilityValue = svcCapabilityMap.get(CAPABILITYVALUE);
 +                if (capabilityName != null) {
 +                    capability = Capability.getCapability(capabilityName);
 +                }
 +
 +                if (capability == null || capabilityValue == null) {
 +                    throw new InvalidParameterValueException("Invalid capability:" + capabilityName + " capability value:" + capabilityValue);
 +                }
 +                final Service usedService = Service.getService(svc);
 +
 +                checkCapabilityPerServiceProvider(providers, capability, usedService);
 +
 +                if (!capabilityValue.equalsIgnoreCase(TRUE_VALUE) && !capabilityValue.equalsIgnoreCase(FALSE_VALUE)) {
 +                    throw new InvalidParameterValueException("Invalid Capability value:" + capabilityValue + " specified.");
 +                }
 +            }
 +        }
 +    }
 +
 +    private boolean findCapabilityForService(final Map serviceCapabilitystList, final Capability capability, final Service service) {
 +        boolean foundCapability = false;
 +        if (serviceCapabilitystList != null && !serviceCapabilitystList.isEmpty()) {
 +            final Iterator iter = serviceCapabilitystList.values().iterator();
 +            while (iter.hasNext()) {
 +                final HashMap<String, String> currentCapabilityMap = (HashMap<String, String>) iter.next();
 +                final String currentCapabilityService = currentCapabilityMap.get(SERVICE);
 +                final String currentCapabilityName = currentCapabilityMap.get(CAPABILITYTYPE);
 +                final String currentCapabilityValue = currentCapabilityMap.get(CAPABILITYVALUE);
 +
 +                if (currentCapabilityName == null || currentCapabilityService == null || currentCapabilityValue == null) {
 +                    throw new InvalidParameterValueException(String.format("Invalid capability with name %s, value %s and service %s", currentCapabilityName,
 +                            currentCapabilityValue, currentCapabilityService));
 +                }
 +
 +                if (currentCapabilityName.equalsIgnoreCase(capability.getName())) {
 +                    foundCapability = currentCapabilityValue.equalsIgnoreCase(TRUE_VALUE);
 +
 +                    if (!currentCapabilityService.equalsIgnoreCase(service.getName())) {
 +                        throw new InvalidParameterValueException(String.format("Invalid Service: %s specified. Capability %s can be specified only for service %s",
 +                                currentCapabilityService, service.getName(), currentCapabilityName));
 +                    }
 +
 +                    break;
 +                }
 +            }
 +        }
 +        return foundCapability;
 +    }
 +
 +    private boolean isVpcOfferingForRegionLevelVpc(final Map serviceCapabilitystList) {
 +        return findCapabilityForService(serviceCapabilitystList, Capability.RegionLevelVpc, Service.Connectivity);
 +    }
 +
 +    private boolean isVpcOfferingSupportsDistributedRouter(final Map serviceCapabilitystList) {
 +        return findCapabilityForService(serviceCapabilitystList, Capability.DistributedRouter, Service.Connectivity);
 +    }
 +
 +    private boolean isVpcOfferingRedundantRouter(final Map serviceCapabilitystList) {
 +        return findCapabilityForService(serviceCapabilitystList, Capability.RedundantRouter, Service.SourceNat);
 +    }
 +
 +    @Override
 +    public Vpc getActiveVpc(final long vpcId) {
 +        return _vpcDao.getActiveVpcById(vpcId);
 +    }
 +
 +    @Override
 +    public Map<Service, Set<Provider>> getVpcOffSvcProvidersMap(final long vpcOffId) {
 +        final Map<Service, Set<Provider>> serviceProviderMap = new HashMap<Service, Set<Provider>>();
 +        final List<VpcOfferingServiceMapVO> map = _vpcOffSvcMapDao.listByVpcOffId(vpcOffId);
 +
 +        for (final VpcOfferingServiceMapVO instance : map) {
 +            final Service service = Service.getService(instance.getService());
 +            Set<Provider> providers;
 +            providers = serviceProviderMap.get(service);
 +            if (providers == null) {
 +                providers = new HashSet<Provider>();
 +            }
 +            providers.add(Provider.getProvider(instance.getProvider()));
 +            serviceProviderMap.put(service, providers);
 +        }
 +
 +        return serviceProviderMap;
 +    }
 +
 +    @Override
 +    public Pair<List<? extends VpcOffering>, Integer> listVpcOfferings(final Long id, final String name, final String displayText, final List<String> supportedServicesStr,
 +            final Boolean isDefault, final String keyword, final String state, final Long startIndex, final Long pageSizeVal) {
 +        final Filter searchFilter = new Filter(VpcOfferingVO.class, "created", false, null, null);
 +        final SearchCriteria<VpcOfferingVO> sc = _vpcOffDao.createSearchCriteria();
 +
 +        if (keyword != null) {
 +            final SearchCriteria<VpcOfferingVO> ssc = _vpcOffDao.createSearchCriteria();
 +            ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%");
 +            ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
 +
 +            sc.addAnd("name", SearchCriteria.Op.SC, ssc);
 +        }
 +
 +        if (name != null) {
 +            sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + name + "%");
 +        }
 +
 +        if (displayText != null) {
 +            sc.addAnd("displayText", SearchCriteria.Op.LIKE, "%" + displayText + "%");
 +        }
 +
 +        if (isDefault != null) {
 +            sc.addAnd("isDefault", SearchCriteria.Op.EQ, isDefault);
 +        }
 +
 +        if (state != null) {
 +            sc.addAnd("state", SearchCriteria.Op.EQ, state);
 +        }
 +
 +        if (id != null) {
 +            sc.addAnd("id", SearchCriteria.Op.EQ, id);
 +        }
 +
 +        final List<VpcOfferingVO> offerings = _vpcOffDao.search(sc, searchFilter);
 +
 +        // filter by supported services
 +        final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !offerings.isEmpty();
 +
 +        if (listBySupportedServices) {
 +            final List<VpcOfferingVO> supportedOfferings = new ArrayList<VpcOfferingVO>();
 +            Service[] supportedServices = null;
 +
 +            if (listBySupportedServices) {
 +                supportedServices = new Service[supportedServicesStr.size()];
 +                int i = 0;
 +                for (final String supportedServiceStr : supportedServicesStr) {
 +                    final Service service = Service.getService(supportedServiceStr);
 +                    if (service == null) {
 +                        throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
 +                    } else {
 +                        supportedServices[i] = service;
 +                    }
 +                    i++;
 +                }
 +            }
 +
 +            for (final VpcOfferingVO offering : offerings) {
 +                if (areServicesSupportedByVpcOffering(offering.getId(), supportedServices)) {
 +                    supportedOfferings.add(offering);
 +                }
 +            }
 +
 +            final List<? extends VpcOffering> wPagination = StringUtils.applyPagination(supportedOfferings, startIndex, pageSizeVal);
 +            if (wPagination != null) {
 +                final Pair<List<? extends VpcOffering>, Integer> listWPagination = new Pair<List<? extends VpcOffering>, Integer>(wPagination, supportedOfferings.size());
 +                return listWPagination;
 +            }
 +            return new Pair<List<? extends VpcOffering>, Integer>(supportedOfferings, supportedOfferings.size());
 +        } else {
 +            final List<? extends VpcOffering> wPagination = StringUtils.applyPagination(offerings, startIndex, pageSizeVal);
 +            if (wPagination != null) {
 +                final Pair<List<? extends VpcOffering>, Integer> listWPagination = new Pair<List<? extends VpcOffering>, Integer>(wPagination, offerings.size());
 +                return listWPagination;
 +            }
 +            return new Pair<List<? extends VpcOffering>, Integer>(offerings, offerings.size());
 +        }
 +    }
 +
 +    protected boolean areServicesSupportedByVpcOffering(final long vpcOffId, final Service... services) {
 +        return _vpcOffSvcMapDao.areServicesSupportedByNetworkOffering(vpcOffId, services);
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_DELETE, eventDescription = "deleting vpc offering")
 +    public boolean deleteVpcOffering(final long offId) {
 +        CallContext.current().setEventDetails(" Id: " + offId);
 +
 +        // Verify vpc offering id
 +        final VpcOfferingVO offering = _vpcOffDao.findById(offId);
 +        if (offering == null) {
 +            throw new InvalidParameterValueException("unable to find vpc offering " + offId);
 +        }
 +
 +        // Don't allow to delete default vpc offerings
 +        if (offering.isDefault() == true) {
 +            throw new InvalidParameterValueException("Default network offering can't be deleted");
 +        }
 +
 +        // don't allow to delete vpc offering if it's in use by existing vpcs
 +        // (the offering can be disabled though)
 +        final int vpcCount = _vpcDao.getVpcCountByOfferingId(offId);
 +        if (vpcCount > 0) {
 +            throw new InvalidParameterValueException("Can't delete vpc offering " + offId + " as its used by " + vpcCount + " vpcs. "
 +                    + "To make the network offering unavaiable, disable it");
 +        }
 +
 +        if (_vpcOffDao.remove(offId)) {
 +            return true;
 +        } else {
 +            return false;
 +        }
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_UPDATE, eventDescription = "updating vpc offering")
 +    public VpcOffering updateVpcOffering(final long vpcOffId, final String vpcOfferingName, final String displayText, final String state) {
 +        CallContext.current().setEventDetails(" Id: " + vpcOffId);
 +
 +        // Verify input parameters
 +        final VpcOfferingVO offeringToUpdate = _vpcOffDao.findById(vpcOffId);
 +        if (offeringToUpdate == null) {
 +            throw new InvalidParameterValueException("Unable to find vpc offering " + vpcOffId);
 +        }
 +
 +        final VpcOfferingVO offering = _vpcOffDao.createForUpdate(vpcOffId);
 +
 +        if (vpcOfferingName != null) {
 +            offering.setName(vpcOfferingName);
 +        }
 +
 +        if (displayText != null) {
 +            offering.setDisplayText(displayText);
 +        }
 +
 +        if (state != null) {
 +            boolean validState = false;
 +            for (final VpcOffering.State st : VpcOffering.State.values()) {
 +                if (st.name().equalsIgnoreCase(state)) {
 +                    validState = true;
 +                    offering.setState(st);
 +                }
 +            }
 +            if (!validState) {
 +                throw new InvalidParameterValueException("Incorrect state value: " + state);
 +            }
 +        }
 +
 +        if (_vpcOffDao.update(vpcOffId, offering)) {
 +            s_logger.debug("Updated VPC offeirng id=" + vpcOffId);
 +            return _vpcOffDao.findById(vpcOffId);
 +        } else {
 +            return null;
 +        }
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
 +    public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain,
 +            final Boolean displayVpc) throws ResourceAllocationException {
 +        final Account caller = CallContext.current().getCallingAccount();
 +        final Account owner = _accountMgr.getAccount(vpcOwnerId);
 +
 +        // Verify that caller can perform actions in behalf of vpc owner
 +        _accountMgr.checkAccess(caller, null, false, owner);
 +
 +        // check resource limit
 +        _resourceLimitMgr.checkResourceLimit(owner, ResourceType.vpc);
 +
 +        // Validate vpc offering
 +        final VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId);
 +        if (vpcOff == null || vpcOff.getState() != State.Enabled) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find vpc offering in " + State.Enabled + " state by specified id");
 +            if (vpcOff == null) {
 +                ex.addProxyObject(String.valueOf(vpcOffId), "vpcOfferingId");
 +            } else {
 +                ex.addProxyObject(vpcOff.getUuid(), "vpcOfferingId");
 +            }
 +            throw ex;
 +        }
 +
 +        final boolean isRegionLevelVpcOff = vpcOff.offersRegionLevelVPC();
 +        if (isRegionLevelVpcOff && networkDomain == null) {
 +            throw new InvalidParameterValueException("Network domain must be specified for region level VPC");
 +        }
 +
 +        // Validate zone
 +        final DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
 +        if (zone == null) {
 +            throw new InvalidParameterValueException("Can't find zone by id specified");
 +        }
 +
 +        if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
 +            // See DataCenterVO.java
 +            final PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
 +            ex.addProxyObject(zone.getUuid(), "zoneId");
 +            throw ex;
 +        }
 +
 +        if (networkDomain == null) {
 +            // 1) Get networkDomain from the corresponding account
 +            networkDomain = _ntwkModel.getAccountNetworkDomain(owner.getId(), zoneId);
 +
 +            // 2) If null, generate networkDomain using domain suffix from the
 +            // global config variables
 +            if (networkDomain == null) {
 +                networkDomain = "cs" + Long.toHexString(owner.getId()) + NetworkOrchestrationService.GuestDomainSuffix.valueIn(zoneId);
 +            }
 +        }
 +
 +        final boolean useDistributedRouter = vpcOff.supportsDistributedRouter();
 +        final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff,
 +                vpcOff.getRedundantRouter());
 +
 +        return createVpc(displayVpc, vpc);
 +    }
 +
 +    @DB
 +    protected Vpc createVpc(final Boolean displayVpc, final VpcVO vpc) {
 +        final String cidr = vpc.getCidr();
 +        // Validate CIDR
 +        if (!NetUtils.isValidIp4Cidr(cidr)) {
 +            throw new InvalidParameterValueException("Invalid CIDR specified " + cidr);
 +        }
 +
 +        // cidr has to be RFC 1918 complient
 +        if (!NetUtils.validateGuestCidr(cidr)) {
 +            throw new InvalidParameterValueException("Guest Cidr " + cidr + " is not RFC1918 compliant");
 +        }
 +
 +        // validate network domain
 +        if (!NetUtils.verifyDomainName(vpc.getNetworkDomain())) {
 +            throw new InvalidParameterValueException("Invalid network domain. Total length shouldn't exceed 190 chars. Each domain "
 +                    + "label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', " + "the digits '0' through '9', "
 +                    + "and the hyphen ('-'); can't start or end with \"-\"");
 +        }
 +
 +        return Transaction.execute(new TransactionCallback<VpcVO>() {
 +            @Override
 +            public VpcVO doInTransaction(final TransactionStatus status) {
 +                if (displayVpc != null) {
 +                    vpc.setDisplay(displayVpc);
 +                }
 +
 +                final VpcVO persistedVpc = _vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(vpc.getZoneId(), vpc.getVpcOfferingId()));
 +                _resourceLimitMgr.incrementResourceCount(vpc.getAccountId(), ResourceType.vpc);
 +                s_logger.debug("Created VPC " + persistedVpc);
 +
 +                return persistedVpc;
 +            }
 +        });
 +    }
 +
 +    private Map<String, List<String>> finalizeServicesAndProvidersForVpc(final long zoneId, final long offeringId) {
 +        final Map<String, List<String>> svcProviders = new HashMap<>();
 +        final List<VpcOfferingServiceMapVO> servicesMap = _vpcOffSvcMapDao.listByVpcOffId(offeringId);
 +
 +        for (final VpcOfferingServiceMapVO serviceMap : servicesMap) {
 +            final String service = serviceMap.getService();
 +            String provider = serviceMap.getProvider();
 +
 +            if (provider == null) {
 +                // Default to VPCVirtualRouter
 +                provider = Provider.VPCVirtualRouter.getName();
 +            }
 +
 +            if (!_ntwkModel.isProviderEnabledInZone(zoneId, provider)) {
 +                throw new InvalidParameterValueException("Provider " + provider + " should be enabled in at least one physical network of the zone specified");
 +            }
 +
 +            List<String> providers = null;
 +            if (svcProviders.get(service) == null) {
 +                providers = new ArrayList<String>();
 +            } else {
 +                providers = svcProviders.get(service);
 +            }
 +            providers.add(provider);
 +            svcProviders.put(service, providers);
 +        }
 +
 +        return svcProviders;
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_DELETE, eventDescription = "deleting VPC")
 +    public boolean deleteVpc(final long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
 +        CallContext.current().setEventDetails(" Id: " + vpcId);
 +        final CallContext ctx = CallContext.current();
 +
 +        // Verify vpc id
 +        final Vpc vpc = _vpcDao.findById(vpcId);
 +        if (vpc == null) {
 +            throw new InvalidParameterValueException("unable to find VPC id=" + vpcId);
 +        }
 +
 +        // verify permissions
 +        _accountMgr.checkAccess(ctx.getCallingAccount(), null, false, vpc);
 +        _resourceTagDao.removeByIdAndType(vpcId, ResourceObjectType.Vpc);
 +
 +        return destroyVpc(vpc, ctx.getCallingAccount(), ctx.getCallingUserId());
 +    }
 +
 +    @Override
 +    @DB
 +    public boolean destroyVpc(final Vpc vpc, final Account caller, final Long callerUserId) throws ConcurrentOperationException, ResourceUnavailableException {
 +        s_logger.debug("Destroying vpc " + vpc);
 +
 +        // don't allow to delete vpc if it's in use by existing non system
 +        // networks (system networks are networks of a private gateway of the
 +        // VPC,
 +        // and they will get removed as a part of VPC cleanup
 +        final int networksCount = _ntwkDao.getNonSystemNetworkCountByVpcId(vpc.getId());
 +        if (networksCount > 0) {
 +            throw new InvalidParameterValueException("Can't delete VPC " + vpc + " as its used by " + networksCount + " networks");
 +        }
 +
 +        // mark VPC as inactive
 +        if (vpc.getState() != Vpc.State.Inactive) {
 +            s_logger.debug("Updating VPC " + vpc + " with state " + Vpc.State.Inactive + " as a part of vpc delete");
 +            final VpcVO vpcVO = _vpcDao.findById(vpc.getId());
 +            vpcVO.setState(Vpc.State.Inactive);
 +
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                    _vpcDao.update(vpc.getId(), vpcVO);
 +
 +                    // decrement resource count
 +                    _resourceLimitMgr.decrementResourceCount(vpc.getAccountId(), ResourceType.vpc);
 +                }
 +            });
 +        }
 +
 +        // shutdown VPC
 +        if (!shutdownVpc(vpc.getId())) {
 +            s_logger.warn("Failed to shutdown vpc " + vpc + " as a part of vpc destroy process");
 +            return false;
 +        }
 +
 +        // cleanup vpc resources
 +        if (!cleanupVpcResources(vpc.getId(), caller, callerUserId)) {
 +            s_logger.warn("Failed to cleanup resources for vpc " + vpc);
 +            return false;
 +        }
 +
 +        // update the instance with removed flag only when the cleanup is
 +        // executed successfully
 +        if (_vpcDao.remove(vpc.getId())) {
 +            s_logger.debug("Vpc " + vpc + " is destroyed succesfully");
 +            return true;
 +        } else {
 +            s_logger.warn("Vpc " + vpc + " failed to destroy");
 +            return false;
 +        }
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc")
 +    public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc) {
 +        CallContext.current().setEventDetails(" Id: " + vpcId);
 +        final Account caller = CallContext.current().getCallingAccount();
 +
 +        // Verify input parameters
 +        final VpcVO vpcToUpdate = _vpcDao.findById(vpcId);
 +        if (vpcToUpdate == null) {
 +            throw new InvalidParameterValueException("Unable to find vpc by id " + vpcId);
 +        }
 +
 +        _accountMgr.checkAccess(caller, null, false, vpcToUpdate);
 +
 +        final VpcVO vpc = _vpcDao.createForUpdate(vpcId);
 +
 +        if (vpcName != null) {
 +            vpc.setName(vpcName);
 +        }
 +
 +        if (displayText != null) {
 +            vpc.setDisplayText(displayText);
 +        }
 +
 +        if (customId != null) {
 +            vpc.setUuid(customId);
 +        }
 +
 +        if (displayVpc != null) {
 +            vpc.setDisplay(displayVpc);
 +        }
 +
 +        if (_vpcDao.update(vpcId, vpc)) {
 +            s_logger.debug("Updated VPC id=" + vpcId);
 +            return _vpcDao.findById(vpcId);
 +        } else {
 +            return null;
 +        }
 +    }
 +
 +    @Override
 +    public Pair<List<? extends Vpc>, Integer> listVpcs(final Long id, final String vpcName, final String displayText, final List<String> supportedServicesStr, final String cidr,
 +            final Long vpcOffId, final String state, final String accountName, Long domainId, final String keyword, final Long startIndex, final Long pageSizeVal,
 +            final Long zoneId, Boolean isRecursive, final Boolean listAll, final Boolean restartRequired, final Map<String, String> tags, final Long projectId,
 +            final Boolean display) {
 +        final Account caller = CallContext.current().getCallingAccount();
 +        final List<Long> permittedAccounts = new ArrayList<Long>();
 +        final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive,
 +                null);
 +        _accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccounts, domainIdRecursiveListProject, listAll, false);
 +        domainId = domainIdRecursiveListProject.first();
 +        isRecursive = domainIdRecursiveListProject.second();
 +        final ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
 +        final Filter searchFilter = new Filter(VpcVO.class, "created", false, null, null);
 +
 +        final SearchBuilder<VpcVO> sb = _vpcDao.createSearchBuilder();
 +        _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +
 +        sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
 +        sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
 +        sb.and("displayText", sb.entity().getDisplayText(), SearchCriteria.Op.LIKE);
 +        sb.and("vpcOfferingId", sb.entity().getVpcOfferingId(), SearchCriteria.Op.EQ);
 +        sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
 +        sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
 +        sb.and("restartRequired", sb.entity().isRestartRequired(), SearchCriteria.Op.EQ);
 +        sb.and("cidr", sb.entity().getCidr(), SearchCriteria.Op.EQ);
 +        sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ);
 +
 +        if (tags != null && !tags.isEmpty()) {
 +            final SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
 +            for (int count = 0; count < tags.size(); count++) {
 +                tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
 +                tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
 +                tagSearch.cp();
 +            }
 +            tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
 +            sb.groupBy(sb.entity().getId());
 +            sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
 +        }
 +
 +        // now set the SC criteria...
 +        final SearchCriteria<VpcVO> sc = sb.create();
 +        _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +
 +        if (keyword != null) {
 +            final SearchCriteria<VpcVO> ssc = _vpcDao.createSearchCriteria();
 +            ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%");
 +            ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
 +            sc.addAnd("name", SearchCriteria.Op.SC, ssc);
 +        }
 +
 +        if (vpcName != null) {
 +            sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + vpcName + "%");
 +        }
 +
 +        if (displayText != null) {
 +            sc.addAnd("displayText", SearchCriteria.Op.LIKE, "%" + displayText + "%");
 +        }
 +
 +        if (tags != null && !tags.isEmpty()) {
 +            int count = 0;
 +            sc.setJoinParameters("tagSearch", "resourceType", ResourceObjectType.Vpc.toString());
 +            for (final Map.Entry<String, String> entry : tags.entrySet()) {
 +                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), entry.getKey());
 +                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), entry.getValue());
 +                count++;
 +            }
 +        }
 +
 +        if (display != null) {
 +            sc.setParameters("display", display);
 +        }
 +
 +        if (id != null) {
 +            sc.addAnd("id", SearchCriteria.Op.EQ, id);
 +        }
 +
 +        if (vpcOffId != null) {
 +            sc.addAnd("vpcOfferingId", SearchCriteria.Op.EQ, vpcOffId);
 +        }
 +
 +        if (zoneId != null) {
 +            sc.addAnd("zoneId", SearchCriteria.Op.EQ, zoneId);
 +        }
 +
 +        if (state != null) {
 +            sc.addAnd("state", SearchCriteria.Op.EQ, state);
 +        }
 +
 +        if (cidr != null) {
 +            sc.addAnd("cidr", SearchCriteria.Op.EQ, cidr);
 +        }
 +
 +        if (restartRequired != null) {
 +            sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
 +        }
 +
 +        final List<VpcVO> vpcs = _vpcDao.search(sc, searchFilter);
 +
 +        // filter by supported services
 +        final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty();
 +
 +        if (listBySupportedServices) {
 +            final List<VpcVO> supportedVpcs = new ArrayList<VpcVO>();
 +            Service[] supportedServices = null;
 +
 +            if (listBySupportedServices) {
 +                supportedServices = new Service[supportedServicesStr.size()];
 +                int i = 0;
 +                for (final String supportedServiceStr : supportedServicesStr) {
 +                    final Service service = Service.getService(supportedServiceStr);
 +                    if (service == null) {
 +                        throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
 +                    } else {
 +                        supportedServices[i] = service;
 +                    }
 +                    i++;
 +                }
 +            }
 +
 +            for (final VpcVO vpc : vpcs) {
 +                if (areServicesSupportedByVpcOffering(vpc.getVpcOfferingId(), supportedServices)) {
 +                    supportedVpcs.add(vpc);
 +                }
 +            }
 +
 +            final List<? extends Vpc> wPagination = StringUtils.applyPagination(supportedVpcs, startIndex, pageSizeVal);
 +            if (wPagination != null) {
 +                final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, supportedVpcs.size());
 +                return listWPagination;
 +            }
 +            return new Pair<List<? extends Vpc>, Integer>(supportedVpcs, supportedVpcs.size());
 +        } else {
 +            final List<? extends Vpc> wPagination = StringUtils.applyPagination(vpcs, startIndex, pageSizeVal);
 +            if (wPagination != null) {
 +                final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, vpcs.size());
 +                return listWPagination;
 +            }
 +            return new Pair<List<? extends Vpc>, Integer>(vpcs, vpcs.size());
 +        }
 +    }
 +
 +    protected List<Service> getSupportedServices() {
 +        final List<Service> services = new ArrayList<Service>();
 +        services.add(Network.Service.Dhcp);
 +        services.add(Network.Service.Dns);
 +        services.add(Network.Service.UserData);
 +        services.add(Network.Service.NetworkACL);
 +        services.add(Network.Service.PortForwarding);
 +        services.add(Network.Service.Lb);
 +        services.add(Network.Service.SourceNat);
 +        services.add(Network.Service.StaticNat);
 +        services.add(Network.Service.Gateway);
 +        services.add(Network.Service.Vpn);
 +        return services;
 +    }
 +
 +    @Override
 +    public boolean startVpc(final long vpcId, final boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
 +        final CallContext ctx = CallContext.current();
 +        final Account caller = ctx.getCallingAccount();
 +        final User callerUser = _accountMgr.getActiveUser(ctx.getCallingUserId());
 +
 +        // check if vpc exists
 +        final Vpc vpc = getActiveVpc(vpcId);
 +        if (vpc == null) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
 +            ex.addProxyObject(String.valueOf(vpcId), "VPC");
 +            throw ex;
 +        }
 +
 +        // permission check
 +        _accountMgr.checkAccess(caller, null, false, vpc);
 +
 +        final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId());
 +
 +        final DeployDestination dest = new DeployDestination(dc, null, null, null);
 +        final ReservationContext context = new ReservationContextImpl(null, null, callerUser, _accountMgr.getAccount(vpc.getAccountId()));
 +
 +        boolean result = true;
 +        try {
 +            if (!startVpc(vpc, dest, context)) {
 +                s_logger.warn("Failed to start vpc " + vpc);
 +                result = false;
 +            }
 +        } catch (final Exception ex) {
 +            s_logger.warn("Failed to start vpc " + vpc + " due to ", ex);
 +            result = false;
 +        } finally {
 +            // do cleanup
 +            if (!result && destroyOnFailure) {
 +                s_logger.debug("Destroying vpc " + vpc + " that failed to start");
 +                if (destroyVpc(vpc, caller, callerUser.getId())) {
 +                    s_logger.warn("Successfully destroyed vpc " + vpc + " that failed to start");
 +                } else {
 +                    s_logger.warn("Failed to destroy vpc " + vpc + " that failed to start");
 +                }
 +            }
 +        }
 +        return result;
 +    }
 +
 +    protected boolean startVpc(final Vpc vpc, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
 +    InsufficientCapacityException {
 +        // deploy provider
 +        boolean success = true;
 +        final List<Provider> providersToImplement = getVpcProviders(vpc.getId());
 +        for (final VpcProvider element : getVpcElements()) {
 +            if (providersToImplement.contains(element.getProvider())) {
 +                if (element.implementVpc(vpc, dest, context)) {
 +                    s_logger.debug("Vpc " + vpc + " has started successfully");
 +                } else {
 +                    s_logger.warn("Vpc " + vpc + " failed to start");
 +                    success = false;
 +                }
 +            }
 +        }
 +        return success;
 +    }
 +
 +    @Override
 +    public boolean shutdownVpc(final long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
 +        final CallContext ctx = CallContext.current();
 +        final Account caller = ctx.getCallingAccount();
 +
 +        // check if vpc exists
 +        final Vpc vpc = _vpcDao.findById(vpcId);
 +        if (vpc == null) {
 +            throw new InvalidParameterValueException("Unable to find vpc by id " + vpcId);
 +        }
 +
 +        // permission check
 +        _accountMgr.checkAccess(caller, null, false, vpc);
 +
 +        // shutdown provider
 +        s_logger.debug("Shutting down vpc " + vpc);
 +        // TODO - shutdown all vpc resources here (ACLs, gateways, etc)
 +
 +        boolean success = true;
 +        final List<Provider> providersToImplement = getVpcProviders(vpc.getId());
 +        final ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallingUserId()), caller);
 +        for (final VpcProvider element : getVpcElements()) {
 +            if (providersToImplement.contains(element.getProvider())) {
 +                if (element.shutdownVpc(vpc, context)) {
 +                    s_logger.debug("Vpc " + vpc + " has been shutdown succesfully");
 +                } else {
 +                    s_logger.warn("Vpc " + vpc + " failed to shutdown");
 +                    success = false;
 +                }
 +            }
 +        }
 +
 +        return success;
 +    }
 +
 +    @DB
 +    @Override
 +    public void validateNtwkOffForNtwkInVpc(final Long networkId, final long newNtwkOffId, final String newCidr, final String newNetworkDomain, final Vpc vpc,
 +            final String gateway, final Account networkOwner, final Long aclId) {
 +
 +        final NetworkOffering guestNtwkOff = _entityMgr.findById(NetworkOffering.class, newNtwkOffId);
 +
 +        if (guestNtwkOff == null) {
 +            throw new InvalidParameterValueException("Can't find network offering by id specified");
 +        }
 +
 +        if (networkId == null) {
 +            // 1) Validate attributes that has to be passed in when create new
 +            // guest network
 +            validateNewVpcGuestNetwork(newCidr, gateway, networkOwner, vpc, newNetworkDomain);
 +        }
 +
 +        // 2) validate network offering attributes
 +        final List<Service> svcs = _ntwkModel.listNetworkOfferingServices(guestNtwkOff.getId());
 +        validateNtwkOffForVpc(guestNtwkOff, svcs);
 +
 +        // 3) Check services/providers against VPC providers
 +        final List<NetworkOfferingServiceMapVO> networkProviders = _ntwkOffServiceDao.listByNetworkOfferingId(guestNtwkOff.getId());
 +
 +        for (final NetworkOfferingServiceMapVO nSvcVO : networkProviders) {
 +            final String pr = nSvcVO.getProvider();
 +            final String service = nSvcVO.getService();
 +            if (_vpcOffServiceDao.findByServiceProviderAndOfferingId(service, pr, vpc.getVpcOfferingId()) == null) {
 +                throw new InvalidParameterValueException("Service/provider combination " + service + "/" + pr + " is not supported by VPC " + vpc);
 +            }
 +        }
 +
 +        // 4) Only one network in the VPC can support public LB inside the VPC.
 +        // Internal LB can be supported on multiple VPC tiers
 +        if (_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb) && guestNtwkOff.isPublicLb()) {
 +            final List<? extends Network> networks = getVpcNetworks(vpc.getId());
 +            for (final Network network : networks) {
 +                if (networkId != null && network.getId() == networkId.longValue()) {
 +                    // skip my own network
 +                    continue;
 +                } else {
 +                    final NetworkOffering otherOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
 +                    // throw only if networks have different offerings with
 +                    // public lb support
 +                    if (_ntwkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb) && otherOff.isPublicLb() && guestNtwkOff.getId() != otherOff.getId()) {
 +                        throw new InvalidParameterValueException("Public LB service is already supported " + "by network " + network + " in VPC " + vpc);
 +                    }
 +                }
 +            }
 +        }
 +
 +        // 5) When aclId is provided, verify that ACLProvider is supported by
 +        // network offering
 +        if (aclId != null && !_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.NetworkACL)) {
 +            throw new InvalidParameterValueException("Cannot apply NetworkACL. Network Offering does not support NetworkACL service");
 +        }
 +
 +    }
 +
 +    @Override
 +    public void validateNtwkOffForVpc(final NetworkOffering guestNtwkOff, final List<Service> supportedSvcs) {
 +        // 1) in current release, only vpc provider is supported by Vpc offering
 +        final List<Provider> providers = _ntwkModel.getNtwkOffDistinctProviders(guestNtwkOff.getId());
 +        for (final Provider provider : providers) {
 +            if (!supportedProviders.contains(provider)) {
 +                throw new InvalidParameterValueException("Provider of type " + provider.getName() + " is not supported for network offerings that can be used in VPC");
 +            }
 +        }
 +
 +        // 2) Only Isolated networks with Source nat service enabled can be
 +        // added to vpc
 +        if (!(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) {
 +
 +            throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName()
 +                    + " are valid for vpc ");
 +        }
 +
 +        // 3) No redundant router support
 +        /*
 +         * TODO This should have never been hardcoded like this in the first
 +         * place if (guestNtwkOff.getRedundantRouter()) { throw new
 +         * InvalidParameterValueException
 +         * ("No redunant router support when network belnogs to VPC"); }
 +         */
 +
 +        // 4) Conserve mode should be off
 +        if (guestNtwkOff.isConserveMode()) {
 +            throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC");
 +        }
 +
 +        // 5) If Netscaler is LB provider make sure it is in dedicated mode
 +        if (providers.contains(Provider.Netscaler) && !guestNtwkOff.isDedicatedLB()) {
 +            throw new InvalidParameterValueException("Netscaler only with Dedicated LB can belong to VPC");
 +        }
 +        return;
 +    }
 +
 +    @DB
 +    protected void validateNewVpcGuestNetwork(final String cidr, final String gateway, final Account networkOwner, final Vpc vpc, final String networkDomain) {
 +
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                final Vpc locked = _vpcDao.acquireInLockTable(vpc.getId());
 +                if (locked == null) {
 +                    throw new CloudRuntimeException("Unable to acquire lock on " + vpc);
 +                }
 +
 +                try {
 +                    // check number of active networks in vpc
 +                    if (_ntwkDao.countVpcNetworks(vpc.getId()) >= _maxNetworks) {
 +                        throw new CloudRuntimeException("Number of networks per VPC can't extend " + _maxNetworks + "; increase it using global config " + Config.VpcMaxNetworks);
 +                    }
 +
 +                    // 1) CIDR is required
 +                    if (cidr == null) {
 +                        throw new InvalidParameterValueException("Gateway/netmask are required when create network for VPC");
 +                    }
 +
 +                    // 2) Network cidr should be within vpcCidr
 +                    if (!NetUtils.isNetworkAWithinNetworkB(cidr, vpc.getCidr())) {
 +                        throw new InvalidParameterValueException("Network cidr " + cidr + " is not within vpc " + vpc + " cidr");
 +                    }
 +
 +                    // 3) Network cidr shouldn't cross the cidr of other vpc
 +                    // network cidrs
 +                    final List<? extends Network> ntwks = _ntwkDao.listByVpc(vpc.getId());
 +                    for (final Network ntwk : ntwks) {
 +                        assert cidr != null : "Why the network cidr is null when it belongs to vpc?";
 +
 +                        if (NetUtils.isNetworkAWithinNetworkB(ntwk.getCidr(), cidr) || NetUtils.isNetworkAWithinNetworkB(cidr, ntwk.getCidr())) {
 +                            throw new InvalidParameterValueException("Network cidr " + cidr + " crosses other network cidr " + ntwk + " belonging to the same vpc " + vpc);
 +                        }
 +                    }
 +
 +                    // 4) vpc and network should belong to the same owner
 +                    if (vpc.getAccountId() != networkOwner.getId()) {
 +                        throw new InvalidParameterValueException("Vpc " + vpc + " owner is different from the network owner " + networkOwner);
 +                    }
 +
 +                    // 5) network domain should be the same as VPC's
 +                    if (!networkDomain.equalsIgnoreCase(vpc.getNetworkDomain())) {
 +                        throw new InvalidParameterValueException("Network domain of the new network should match network" + " domain of vpc " + vpc);
 +                    }
 +
 +                    // 6) gateway should never be equal to the cidr subnet
 +                    if (NetUtils.getCidrSubNet(cidr).equalsIgnoreCase(gateway)) {
 +                        throw new InvalidParameterValueException("Invalid gateway specified. It should never be equal to the cidr subnet value");
 +                    }
 +                } finally {
 +                    s_logger.debug("Releasing lock for " + locked);
 +                    _vpcDao.releaseFromLockTable(locked.getId());
 +                }
 +            }
 +        });
 +    }
 +
 +    public List<VpcProvider> getVpcElements() {
 +        if (vpcElements == null) {
 +            vpcElements = new ArrayList<VpcProvider>();
 +            vpcElements.add((VpcProvider) _ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName()));
 +            vpcElements.add((VpcProvider) _ntwkModel.getElementImplementingProvider(Provider.JuniperContrailVpcRouter.getName()));
 +        }
 +
 +        if (vpcElements == null) {
 +            throw new CloudRuntimeException("Failed to initialize vpc elements");
 +        }
 +
 +        return vpcElements;
 +    }
 +
 +    @Override
 +    public List<? extends Vpc> getVpcsForAccount(final long accountId) {
 +        final List<Vpc> vpcs = new ArrayList<Vpc>();
 +        vpcs.addAll(_vpcDao.listByAccountId(accountId));
 +        return vpcs;
 +    }
 +
 +    public boolean cleanupVpcResources(final long vpcId, final Account caller, final long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException {
 +        s_logger.debug("Cleaning up resources for vpc id=" + vpcId);
 +        boolean success = true;
 +
 +        // 1) Remove VPN connections and VPN gateway
 +        s_logger.debug("Cleaning up existed site to site VPN connections");
 +        _s2sVpnMgr.cleanupVpnConnectionByVpc(vpcId);
 +        s_logger.debug("Cleaning up existed site to site VPN gateways");
 +        _s2sVpnMgr.cleanupVpnGatewayByVpc(vpcId);
 +
 +        // 2) release all ip addresses
 +        final List<IPAddressVO> ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null);
 +        s_logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup");
 +        for (final IPAddressVO ipToRelease : ipsToRelease) {
 +            if (ipToRelease.isPortable()) {
 +                // portable IP address are associated with owner, until
 +                // explicitly requested to be disassociated.
 +                // so as part of VPC clean up just break IP association with VPC
 +                ipToRelease.setVpcId(null);
 +                ipToRelease.setAssociatedWithNetworkId(null);
 +                _ipAddressDao.update(ipToRelease.getId(), ipToRelease);
 +                s_logger.debug("Portable IP address " + ipToRelease + " is no longer associated with any VPC");
 +            } else {
 +                success = success && _ipAddrMgr.disassociatePublicIpAddress(ipToRelease.getId(), callerUserId, caller);
 +                if (!success) {
 +                    s_logger.warn("Failed to cleanup ip " + ipToRelease + " as a part of vpc id=" + vpcId + " cleanup");
 +                }
 +            }
 +        }
 +
 +        if (success) {
 +            s_logger.debug("Released ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process");
 +        } else {
 +            s_logger.warn("Failed to release ip addresses for vpc id=" + vpcId + " as a part of cleanup vpc process");
 +            // although it failed, proceed to the next cleanup step as it
 +            // doesn't depend on the public ip release
 +        }
 +
 +        // 3) Delete all static route rules
 +        if (!revokeStaticRoutesForVpc(vpcId, caller)) {
 +            s_logger.warn("Failed to revoke static routes for vpc " + vpcId + " as a part of cleanup vpc process");
 +            return false;
 +        }
 +
 +        // 4) Delete private gateways
 +        final List<PrivateGateway> gateways = getVpcPrivateGateways(vpcId);
 +        if (gateways != null) {
 +            for (final PrivateGateway gateway : gateways) {
 +                if (gateway != null) {
 +                    s_logger.debug("Deleting private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
 +                    if (!deleteVpcPrivateGateway(gateway.getId())) {
 +                        success = false;
 +                        s_logger.debug("Failed to delete private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
 +                    } else {
 +                        s_logger.debug("Deleted private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup");
 +                    }
 +                }
 +            }
 +        }
 +
 +        //5) Delete ACLs
 +        final SearchBuilder<NetworkACLVO> searchBuilder = _networkAclDao.createSearchBuilder();
 +
 +        searchBuilder.and("vpcId", searchBuilder.entity().getVpcId(), Op.IN);
 +        final SearchCriteria<NetworkACLVO> searchCriteria = searchBuilder.create();
 +        searchCriteria.setParameters("vpcId", vpcId, 0);
 +
 +        final Filter filter = new Filter(NetworkACLVO.class, "id", false, null, null);
 +        final Pair<List<NetworkACLVO>, Integer> aclsCountPair =  _networkAclDao.searchAndCount(searchCriteria, filter);
 +
 +        final List<NetworkACLVO> acls = aclsCountPair.first();
 +        for (final NetworkACLVO networkAcl : acls) {
 +            if (networkAcl.getId() != NetworkACL.DEFAULT_ALLOW && networkAcl.getId() != NetworkACL.DEFAULT_DENY) {
 +                _networkAclMgr.deleteNetworkACL(networkAcl);
 +            }
 +        }
 +        return success;
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_VPC_RESTART, eventDescription = "restarting vpc")
 +    public boolean restartVpc(final long vpcId, final boolean cleanUp, final boolean makeRedundant) throws ConcurrentOperationException, ResourceUnavailableException,
 +    InsufficientCapacityException {
 +
 +        final Account callerAccount = CallContext.current().getCallingAccount();
 +        final User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
 +        final ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount);
 +
 +        // Verify input parameters
 +        Vpc vpc = getActiveVpc(vpcId);
 +        if (vpc == null) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
 +            ex.addProxyObject(String.valueOf(vpcId), "VPC");
 +            throw ex;
 +        }
 +
 +        _accountMgr.checkAccess(callerAccount, null, false, vpc);
 +
 +        s_logger.debug("Restarting VPC " + vpc);
 +        boolean restartRequired = false;
 +        try {
 +            boolean forceCleanup = cleanUp;
 +            if (!vpc.isRedundant() && makeRedundant) {
 +                final VpcOfferingVO redundantOffering = _vpcOffDao.findByUniqueName(VpcOffering.redundantVPCOfferingName);
 +
 +                final VpcVO entity = _vpcDao.findById(vpcId);
 +                entity.setRedundant(true);
 +                entity.setVpcOfferingId(redundantOffering.getId());
 +
 +                // Change the VPC in order to get it updated after the end of
 +                // the restart procedure.
 +                if (_vpcDao.update(vpc.getId(), entity)) {
 +                    vpc = entity;
 +                }
 +
 +                // If the offering and redundant column are changing, force the
 +                // clean up.
 +                forceCleanup = true;
 +            }
 +
 +            if (forceCleanup) {
 +                if (!rollingRestartVpc(vpc, context)) {
 +                    s_logger.warn("Failed to execute a rolling restart as a part of VPC " + vpc + " restart process");
 +                    restartRequired = true;
 +                    return false;
 +                }
 +                return true;
 +            }
 +
 +            s_logger.debug("Starting VPC " + vpc + " as a part of VPC restart process without cleanup");
 +            if (!startVpc(vpcId, false)) {
 +                s_logger.warn("Failed to start vpc as a part of VPC " + vpc + " restart process");
 +                restartRequired = true;
 +                return false;
 +            }
 +            s_logger.debug("VPC " + vpc + " was restarted successfully");
 +            return true;
 +        } finally {
 +            s_logger.debug("Updating VPC " + vpc + " with restartRequired=" + restartRequired);
 +            final VpcVO vo = _vpcDao.findById(vpcId);
 +            vo.setRestartRequired(restartRequired);
 +            _vpcDao.update(vpc.getId(), vo);
 +        }
 +    }
 +
 +    @Override
 +    public List<PrivateGateway> getVpcPrivateGateways(final long vpcId) {
 +        final List<VpcGatewayVO> gateways = _vpcGatewayDao.listByVpcIdAndType(vpcId, VpcGateway.Type.Private);
 +
 +        if (gateways != null) {
 +            final List<PrivateGateway> pvtGateway = new ArrayList<PrivateGateway>();
 +            for (final VpcGatewayVO gateway : gateways) {
 +                pvtGateway.add(getPrivateGatewayProfile(gateway));
 +            }
 +            return pvtGateway;
 +        } else {
 +            return null;
 +        }
 +    }
 +
 +    @Override
 +    public PrivateGateway getVpcPrivateGateway(final long id) {
 +        final VpcGateway gateway = _vpcGatewayDao.findById(id);
 +
 +        if (gateway == null || gateway.getType() != VpcGateway.Type.Private) {
 +            return null;
 +        }
 +        return getPrivateGatewayProfile(gateway);
 +    }
 +
 +    protected PrivateGateway getPrivateGatewayProfile(final VpcGateway gateway) {
 +        final Network network = _ntwkModel.getNetwork(gateway.getNetworkId());
 +        return new PrivateGatewayProfile(gateway, network.getPhysicalNetworkId());
 +    }
 +
 +    @Override
 +    @DB
 +    @ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_CREATE, eventDescription = "creating VPC private gateway", create = true)
 +    public PrivateGateway createVpcPrivateGateway(final long vpcId, Long physicalNetworkId, final String broadcastUri, final String ipAddress, final String gateway,
 +            final String netmask, final long gatewayOwnerId, final Long networkOfferingId, final Boolean isSourceNat, final Long aclId) throws ResourceAllocationException,
 +            ConcurrentOperationException, InsufficientCapacityException {
 +
 +        // Validate parameters
 +        final Vpc vpc = getActiveVpc(vpcId);
 +        if (vpc == null) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC by id specified");
 +            ex.addProxyObject(String.valueOf(vpcId), "VPC");
 +            throw ex;
 +        }
 +
 +        PhysicalNetwork physNet = null;
 +        // Validate physical network
 +        if (physicalNetworkId == null) {
 +            final List<? extends PhysicalNetwork> pNtwks = _ntwkModel.getPhysicalNtwksSupportingTrafficType(vpc.getZoneId(), TrafficType.Guest);
 +            if (pNtwks.isEmpty() || pNtwks.size() != 1) {
 +                throw new InvalidParameterValueException("Physical network can't be determined; pass physical network id");
 +            }
 +            physNet = pNtwks.get(0);
 +            physicalNetworkId = physNet.getId();
 +        }
 +
 +        if (physNet == null) {
 +            physNet = _entityMgr.findById(PhysicalNetwork.class, physicalNetworkId);
 +        }
 +        final Long dcId = physNet.getDataCenterId();
 +
 +        final Long physicalNetworkIdFinal = physicalNetworkId;
 +        final PhysicalNetwork physNetFinal = physNet;
 +        VpcGatewayVO gatewayVO = null;
 +        try {
 +            gatewayVO = Transaction.execute(new TransactionCallbackWithException<VpcGatewayVO, Exception>() {
 +                @Override
 +                public VpcGatewayVO doInTransaction(final TransactionStatus status) throws ResourceAllocationException, ConcurrentOperationException,
 +                InsufficientCapacityException {
 +                    s_logger.debug("Creating Private gateway for VPC " + vpc);
 +                    // 1) create private network unless it is existing and
 +                    // lswitch'd
 +                    Network privateNtwk = null;
 +                    if (BroadcastDomainType.getSchemeValue(BroadcastDomainType.fromString(broadcastUri)) == BroadcastDomainType.Lswitch) {
 +                        final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
 +                        privateNtwk = _ntwkDao.getPrivateNetwork(broadcastUri, cidr, gatewayOwnerId, dcId, networkOfferingId);
 +                        // if the dcid is different we get no network so next we
 +                        // try to create it
 +                    }
 +                    if (privateNtwk == null) {
 +                        s_logger.info("creating new network for vpc " + vpc + " using broadcast uri: " + broadcastUri);
 +                        final String networkName = "vpc-" + vpc.getName() + "-privateNetwork";
 +                        privateNtwk = _ntwkSvc.createPrivateNetwork(networkName, networkName, physicalNetworkIdFinal, broadcastUri, ipAddress, null, gateway, netmask,
 +                                gatewayOwnerId, vpcId, isSourceNat, networkOfferingId);
 +                    } else { // create the nic/ip as createPrivateNetwork
 +                        // doesn''t do that work for us now
 +                        s_logger.info("found and using existing network for vpc " + vpc + ": " + broadcastUri);
 +                        final DataCenterVO dc = _dcDao.lockRow(physNetFinal.getDataCenterId(), true);
 +
 +                        // add entry to private_ip_address table
 +                        PrivateIpVO privateIp = _privateIpDao.findByIpAndSourceNetworkId(privateNtwk.getId(), ipAddress);
 +                        if (privateIp != null) {
 +                            throw new InvalidParameterValueException("Private ip address " + ipAddress + " already used for private gateway" + " in zone "
 +                                    + _entityMgr.findById(DataCenter.class, dcId).getName());
 +                        }
 +
 +                        final Long mac = dc.getMacAddress();
 +                        final Long nextMac = mac + 1;
 +                        dc.setMacAddress(nextMac);
 +
 +                        s_logger.info("creating private ip address for vpc (" + ipAddress + ", " + privateNtwk.getId() + ", " + nextMac + ", " + vpcId + ", " + isSourceNat + ")");
 +                        privateIp = new PrivateIpVO(ipAddress, privateNtwk.getId(), nextMac, vpcId, isSourceNat);
 +                        _privateIpDao.persist(privateIp);
 +
 +                        _dcDao.update(dc.getId(), dc);
 +                    }
 +
 +                    long networkAclId = NetworkACL.DEFAULT_DENY;
 +                    if (aclId != null) {
 +                        final NetworkACLVO aclVO = _networkAclDao.findById(aclId);
 +                        if (aclVO == null) {
 +                            throw new InvalidParameterValueException("Invalid network acl id passed ");
 +                        }
 +                        if (aclVO.getVpcId() != vpcId && !(aclId == NetworkACL.DEFAULT_DENY || aclId == NetworkACL.DEFAULT_ALLOW)) {
 +                            throw new InvalidParameterValueException("Private gateway and network acl are not in the same vpc");
 +                        }
 +
 +                        networkAclId = aclId;
 +                    }
 +
 +                    { // experimental block, this is a hack
 +                        // set vpc id in network to null
 +                        // might be needed for all types of broadcast domains
 +                        // the ugly hack is that vpc gateway nets are created as
 +                        // guest network
 +                        // while they are not.
 +                        // A more permanent solution would be to define a type of
 +                        // 'gatewaynetwork'
 +                        // so that handling code is not mixed between the two
 +                        final NetworkVO gatewaynet = _ntwkDao.findById(privateNtwk.getId());
 +                        gatewaynet.setVpcId(null);
 +                        _ntwkDao.persist(gatewaynet);
 +                    }
 +
 +                    // 2) create gateway entry
 +                    final VpcGatewayVO gatewayVO = new VpcGatewayVO(ipAddress, VpcGateway.Type.Private, vpcId, privateNtwk.getDataCenterId(), privateNtwk.getId(), broadcastUri,
 +                            gateway, netmask, vpc.getAccountId(), vpc.getDomainId(), isSourceNat, networkAclId);
 +                    _vpcGatewayDao.persist(gatewayVO);
 +
 +                    s_logger.debug("Created vpc gateway entry " + gatewayVO);
 +
 +                    return gatewayVO;
 +                }
 +            });
 +        } catch (final Exception e) {
 +            ExceptionUtil.rethrowRuntime(e);
 +            ExceptionUtil.rethrow(e, InsufficientCapacityException.class);
 +            ExceptionUtil.rethrow(e, ResourceAllocationException.class);
 +            throw new IllegalStateException(e);
 +        }
 +
 +        CallContext.current().setEventDetails("Private Gateway Id: " + gatewayVO.getId());
 +        return getVpcPrivateGateway(gatewayVO.getId());
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_CREATE, eventDescription = "Applying VPC private gateway", async = true)
 +    public PrivateGateway applyVpcPrivateGateway(final long gatewayId, final boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException {
 +        final VpcGatewayVO vo = _vpcGatewayDao.findById(gatewayId);
 +
 +        boolean success = true;
 +        try {
 +            final List<Provider> providersToImplement = getVpcProviders(vo.getVpcId());
 +
 +            final PrivateGateway gateway = getVpcPrivateGateway(gatewayId);
 +            for (final VpcProvider provider : getVpcElements()) {
 +                if (providersToImplement.contains(provider.getProvider())) {
 +                    if (!provider.createPrivateGateway(gateway)) {
 +                        success = false;
 +                    }
 +                }
 +            }
 +            if (success) {
 +                s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend");
 +                if (vo.getState() != VpcGateway.State.Ready) {
 +                    vo.setState(VpcGateway.State.Ready);
 +                    _vpcGatewayDao.update(vo.getId(), vo);
 +                    s_logger.debug("Marke gateway " + gateway + " with state " + VpcGateway.State.Ready);
 +                }
 +                CallContext.current().setEventDetails("Private Gateway Id: " + gatewayId);
 +                return getVpcPrivateGateway(gatewayId);
 +            } else {
 +                s_logger.warn("Private gateway " + gateway + " failed to apply on the backend");
 +                return null;
 +            }
 +        } finally {
 +            // do cleanup
 +            if (!success) {
 +                if (destroyOnFailure) {
 +                    s_logger.debug("Destroying private gateway " + vo + " that failed to start");
 +                    // calling deleting from db because on createprivategateway
 +                    // fail, destroyPrivateGateway is already called
 +                    if (deletePrivateGatewayFromTheDB(getVpcPrivateGateway(gatewayId))) {
 +                        s_logger.warn("Successfully destroyed vpc " + vo + " that failed to start");
 +                    } else {
 +                        s_logger.warn("Failed to destroy vpc " + vo + " that failed to start");
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_DELETE, eventDescription = "deleting private gateway")
 +    @DB
 +    public boolean deleteVpcPrivateGateway(final long gatewayId) throws ConcurrentOperationException, ResourceUnavailableException {
 +        final VpcGatewayVO gatewayToBeDeleted = _vpcGatewayDao.findById(gatewayId);
 +        if (gatewayToBeDeleted == null) {
 +            s_logger.debug("VPC gateway is already deleted for id=" + gatewayId);
 +            return true;
 +        }
 +
 +        final VpcGatewayVO gatewayVO = _vpcGatewayDao.acquireInLockTable(gatewayId);
 +        if (gatewayVO == null || gatewayVO.getType() != VpcGateway.Type.Private) {
 +            throw new ConcurrentOperationException("Unable to lock gateway " + gatewayId);
 +        }
 +
 +        try {
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                    // don't allow to remove gateway when there are static
 +                    // routes associated with it
 +                    final long routeCount = _staticRouteDao.countRoutesByGateway(gatewayVO.getId());
 +                    if (routeCount > 0) {
 +                        throw new CloudRuntimeException("Can't delete private gateway " + gatewayVO + " as it has " + routeCount
 +                                + " static routes applied. Remove the routes first");
 +                    }
 +
 +                    gatewayVO.setState(VpcGateway.State.Deleting);
 +                    _vpcGatewayDao.update(gatewayVO.getId(), gatewayVO);
 +                    s_logger.debug("Marked gateway " + gatewayVO + " with state " + VpcGateway.State.Deleting);
 +                }
 +            });
 +
 +            // 1) delete the gateway on the backend
 +            final List<Provider> providersToImplement = getVpcProviders(gatewayVO.getVpcId());
 +            final PrivateGateway gateway = getVpcPrivateGateway(gatewayId);
 +            for (final VpcProvider provider : getVpcElements()) {
 +                if (providersToImplement.contains(provider.getProvider())) {
 +                    if (provider.deletePrivateGateway(gateway)) {
 +                        s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend");
 +                    } else {
 +                        s_logger.warn("Private gateway " + gateway + " failed to apply on the backend");
 +                        gatewayVO.setState(VpcGateway.State.Ready);
 +                        _vpcGatewayDao.update(gatewayVO.getId(), gatewayVO);
 +                        s_logger.debug("Marked gateway " + gatewayVO + " with state " + VpcGateway.State.Ready);
 +
 +                        return false;
 +                    }
 +                }
 +            }
 +
 +            // 2) Delete private gateway from the DB
 +            return deletePrivateGatewayFromTheDB(gateway);
 +
 +        } finally {
 +            if (gatewayVO != null) {
 +                _vpcGatewayDao.releaseFromLockTable(gatewayId);
 +            }
 +        }
 +    }
 +
 +    @DB
 +    protected boolean deletePrivateGatewayFromTheDB(final PrivateGateway gateway) {
 +        // check if there are ips allocted in the network
 +        final long networkId = gateway.getNetworkId();
 +
 +        vpcTxCallable.setGateway(gateway);
 +
 +        final ExecutorService txExecutor = Executors.newSingleThreadExecutor();
 +        final Future<Boolean> futureResult = txExecutor.submit(vpcTxCallable);
 +
 +        boolean deleteNetworkFinal;
 +        try {
 +            deleteNetworkFinal = futureResult.get();
 +            if (deleteNetworkFinal) {
 +                final User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
 +                final Account owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
 +                final ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner);
 +                _ntwkMgr.destroyNetwork(networkId, context, false);
 +                s_logger.debug("Deleted private network id=" + networkId);
 +            }
 +        } catch (final InterruptedException e) {
 +            s_logger.error("deletePrivateGatewayFromTheDB failed to delete network id " + networkId + "due to => ", e);
 +        } catch (final ExecutionException e) {
 +            s_logger.error("deletePrivateGatewayFromTheDB failed to delete network id " + networkId + "due to => ", e);
 +        }
 +
 +        return true;
 +    }
 +
 +    @Override
 +    public Pair<List<PrivateGateway>, Integer> listPrivateGateway(final ListPrivateGatewaysCmd cmd) {
 +        final String ipAddress = cmd.getIpAddress();
 +        final String vlan = cmd.getVlan();
 +        final Long vpcId = cmd.getVpcId();
 +        final Long id = cmd.getId();
 +        Boolean isRecursive = cmd.isRecursive();
 +        final Boolean listAll = cmd.listAll();
 +        Long domainId = cmd.getDomainId();
 +        final String accountName = cmd.getAccountName();
 +        final Account caller = CallContext.current().getCallingAccount();
 +        final List<Long> permittedAccounts = new ArrayList<Long>();
 +        final String state = cmd.getState();
 +        final Long projectId = cmd.getProjectId();
 +
 +        final Filter searchFilter = new Filter(VpcGatewayVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
 +        final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive,
 +                null);
 +        _accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccounts, domainIdRecursiveListProject, listAll, false);
 +        domainId = domainIdRecursiveListProject.first();
 +        isRecursive = domainIdRecursiveListProject.second();
 +        final ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
 +
 +        final SearchBuilder<VpcGatewayVO> sb = _vpcGatewayDao.createSearchBuilder();
 +        _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +        if (vlan != null) {
 +            final SearchBuilder<NetworkVO> ntwkSearch = _ntwkDao.createSearchBuilder();
 +            ntwkSearch.and("vlan", ntwkSearch.entity().getBroadcastUri(), SearchCriteria.Op.EQ);
 +            sb.join("networkSearch", ntwkSearch, sb.entity().getNetworkId(), ntwkSearch.entity().getId(), JoinBuilder.JoinType.INNER);
 +        }
 +
 +        final SearchCriteria<VpcGatewayVO> sc = sb.create();
 +        _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +        if (id != null) {
 +            sc.addAnd("id", Op.EQ, id);
 +        }
 +
 +        if (ipAddress != null) {
 +            sc.addAnd("ip4Address", Op.EQ, ipAddress);
 +        }
 +
 +        if (state != null) {
 +            sc.addAnd("state", Op.EQ, state);
 +        }
 +
 +        if (vpcId != null) {
 +            sc.addAnd("vpcId", Op.EQ, vpcId);
 +        }
 +
 +        if (vlan != null) {
 +            sc.setJoinParameters("networkSearch", "vlan", BroadcastDomainType.Vlan.toUri(vlan));
 +        }
 +
 +        final Pair<List<VpcGatewayVO>, Integer> vos = _vpcGatewayDao.searchAndCount(sc, searchFilter);
 +        final List<PrivateGateway> privateGtws = new ArrayList<PrivateGateway>(vos.first().size());
 +        for (final VpcGateway vo : vos.first()) {
 +            privateGtws.add(getPrivateGatewayProfile(vo));
 +        }
 +
 +        return new Pair<List<PrivateGateway>, Integer>(privateGtws, vos.second());
 +    }
 +
 +    @Override
 +    public StaticRoute getStaticRoute(final long routeId) {
 +        return _staticRouteDao.findById(routeId);
 +    }
 +
 +    @Override
 +    public boolean applyStaticRoutesForVpc(final long vpcId) throws ResourceUnavailableException {
 +        final Account caller = CallContext.current().getCallingAccount();
 +        final List<? extends StaticRoute> routes = _staticRouteDao.listByVpcId(vpcId);
 +        return applyStaticRoutes(routes, caller, true);
 +    }
 +
 +    protected boolean applyStaticRoutes(final List<? extends StaticRoute> routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException {
 +        final boolean success = true;
 +        final List<StaticRouteProfile> staticRouteProfiles = new ArrayList<StaticRouteProfile>(routes.size());
 +        final Map<Long, VpcGateway> gatewayMap = new HashMap<Long, VpcGateway>();
 +        for (final StaticRoute route : routes) {
 +            VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId());
 +            if (gateway == null) {
 +                gateway = _vpcGatewayDao.findById(route.getVpcGatewayId());
 +                gatewayMap.put(gateway.getId(), gateway);
 +            }
 +            staticRouteProfiles.add(new StaticRouteProfile(route, gateway));
 +        }
 +        if (!applyStaticRoutes(staticRouteProfiles)) {
 +            s_logger.warn("Routes are not completely applied");
 +            return false;
 +        } else {
 +            if (updateRoutesInDB) {
 +                for (final StaticRoute route : routes) {
 +                    if (route.getState() == StaticRoute.State.Revoke) {
 +                        _staticRouteDao.remove(route.getId());
 +                        s_logger.debug("Removed route " + route + " from the DB");
 +                    } else if (route.getState() == StaticRoute.State.Add) {
 +                        final StaticRouteVO ruleVO = _staticRouteDao.findById(route.getId());
 +                        ruleVO.setState(StaticRoute.State.Active);
 +                        _staticRouteDao.update(ruleVO.getId(), ruleVO);
 +                        s_logger.debug("Marked route " + route + " with state " + StaticRoute.State.Active);
 +                    }
 +                }
 +            }
 +        }
 +
 +        return success;
 +    }
 +
 +    protected boolean applyStaticRoutes(final List<StaticRouteProfile> routes) throws ResourceUnavailableException {
 +        if (routes.isEmpty()) {
 +            s_logger.debug("No static routes to apply");
 +            return true;
 +        }
 +        final Vpc vpc = _vpcDao.findById(routes.get(0).getVpcId());
 +
 +        s_logger.debug("Applying static routes for vpc " + vpc);
 +        final String staticNatProvider = _vpcSrvcDao.getProviderForServiceInVpc(vpc.getId(), Service.StaticNat);
 +
 +        for (final VpcProvider provider : getVpcElements()) {
 +            if (!(provider instanceof StaticNatServiceProvider && provider.getName().equalsIgnoreCase(staticNatProvider))) {
 +                continue;
 +            }
 +
 +            if (provider.applyStaticRoutes(vpc, routes)) {
 +                s_logger.debug("Applied static routes for vpc " + vpc);
 +            } else {
 +                s_logger.warn("Failed to apply static routes for vpc " + vpc);
 +                return false;
 +            }
 +        }
 +
 +        return true;
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_DELETE, eventDescription = "deleting static route")
 +    public boolean revokeStaticRoute(final long routeId) throws ResourceUnavailableException {
 +        final Account caller = CallContext.current().getCallingAccount();
 +
 +        final StaticRouteVO route = _staticRouteDao.findById(routeId);
 +        if (route == null) {
 +            throw new InvalidParameterValueException("Unable to find static route by id");
 +        }
 +
 +        _accountMgr.checkAccess(caller, null, false, route);
 +
 +        markStaticRouteForRevoke(route, caller);
 +
 +        return applyStaticRoutesForVpc(route.getVpcId());
 +    }
 +
 +    @DB
 +    protected boolean revokeStaticRoutesForVpc(final long vpcId, final Account caller) throws ResourceUnavailableException {
 +        // get all static routes for the vpc
 +        final List<StaticRouteVO> routes = _staticRouteDao.listByVpcId(vpcId);
 +        s_logger.debug("Found " + routes.size() + " to revoke for the vpc " + vpcId);
 +        if (!routes.isEmpty()) {
 +            // mark all of them as revoke
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                    for (final StaticRouteVO route : routes) {
 +                        markStaticRouteForRevoke(route, caller);
 +                    }
 +                }
 +            });
 +            return applyStaticRoutesForVpc(vpcId);
 +        }
 +
 +        return true;
 +    }
 +
 +    @Override
 +    @DB
 +    @ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_CREATE, eventDescription = "creating static route", create = true)
 +    public StaticRoute createStaticRoute(final long gatewayId, final String cidr) throws NetworkRuleConflictException {
 +        final Account caller = CallContext.current().getCallingAccount();
 +
 +        // parameters validation
 +        final VpcGateway gateway = _vpcGatewayDao.findById(gatewayId);
 +        if (gateway == null) {
 +            throw new InvalidParameterValueException("Invalid gateway id is given");
 +        }
 +
 +        if (gateway.getState() != VpcGateway.State.Ready) {
 +            throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState());
 +        }
 +
 +        final Vpc vpc = getActiveVpc(gateway.getVpcId());
 +        if (vpc == null) {
 +            throw new InvalidParameterValueException("Can't add static route to VPC that is being deleted");
 +        }
 +        _accountMgr.checkAccess(caller, null, false, vpc);
 +
 +        if (!NetUtils.isValidIp4Cidr(cidr)) {
 +            throw new InvalidParameterValueException("Invalid format for cidr " + cidr);
 +        }
 +
 +        // validate the cidr
 +        // 1) CIDR should be outside of VPC cidr for guest networks
 +        if (NetUtils.isNetworksOverlap(vpc.getCidr(), cidr)) {
 +            throw new InvalidParameterValueException("CIDR should be outside of VPC cidr " + vpc.getCidr());
 +        }
 +
 +        // 2) CIDR should be outside of link-local cidr
 +        if (NetUtils.isNetworksOverlap(vpc.getCidr(), NetUtils.getLinkLocalCIDR())) {
 +            throw new InvalidParameterValueException("CIDR should be outside of link local cidr " + NetUtils.getLinkLocalCIDR());
 +        }
 +
 +        // 3) Verify against blacklisted routes
 +        if (isCidrBlacklisted(cidr, vpc.getZoneId())) {
 +            throw new InvalidParameterValueException("The static gateway cidr overlaps with one of the blacklisted routes of the zone the VPC belongs to");
 +        }
 +
 +        return Transaction.execute(new TransactionCallbackWithException<StaticRouteVO, NetworkRuleConflictException>() {
 +            @Override
 +            public StaticRouteVO doInTransaction(final TransactionStatus status) throws NetworkRuleConflictException {
 +                StaticRouteVO newRoute = new StaticRouteVO(gateway.getId(), cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId());
 +                s_logger.debug("Adding static route " + newRoute);
 +                newRoute = _staticRouteDao.persist(newRoute);
 +
 +                detectRoutesConflict(newRoute);
 +
 +                if (!_staticRouteDao.setStateToAdd(newRoute)) {
 +                    throw new CloudRuntimeException("Unable to update the state to add for " + newRoute);
 +                }
 +                CallContext.current().setEventDetails("Static route Id: " + newRoute.getId());
 +
 +                return newRoute;
 +            }
 +        });
 +    }
 +
 +    protected boolean isCidrBlacklisted(final String cidr, final long zoneId) {
 +        final String routesStr = NetworkOrchestrationService.GuestDomainSuffix.valueIn(zoneId);
 +        if (routesStr != null && !routesStr.isEmpty()) {
 +            final String[] cidrBlackList = routesStr.split(",");
 +
 +            if (cidrBlackList != null && cidrBlackList.length > 0) {
 +                for (final String blackListedRoute : cidrBlackList) {
 +                    if (NetUtils.isNetworksOverlap(blackListedRoute, cidr)) {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +
 +        return false;
 +    }
 +
 +    @Override
 +    public Pair<List<? extends StaticRoute>, Integer> listStaticRoutes(final ListStaticRoutesCmd cmd) {
 +        final Long id = cmd.getId();
 +        final Long gatewayId = cmd.getGatewayId();
 +        final Long vpcId = cmd.getVpcId();
 +        Long domainId = cmd.getDomainId();
 +        Boolean isRecursive = cmd.isRecursive();
 +        final Boolean listAll = cmd.listAll();
 +        final String accountName = cmd.getAccountName();
 +        final Account caller = CallContext.current().getCallingAccount();
 +        final List<Long> permittedAccounts = new ArrayList<Long>();
 +        final Map<String, String> tags = cmd.getTags();
 +        final Long projectId = cmd.getProjectId();
 +
 +        final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive,
 +                null);
 +        _accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccounts, domainIdRecursiveListProject, listAll, false);
 +        domainId = domainIdRecursiveListProject.first();
 +        isRecursive = domainIdRecursiveListProject.second();
 +        final ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
 +        final Filter searchFilter = new Filter(StaticRouteVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
 +
 +        final SearchBuilder<StaticRouteVO> sb = _staticRouteDao.createSearchBuilder();
 +        _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +
 +        sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
 +        sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ);
 +        sb.and("vpcGatewayId", sb.entity().getVpcGatewayId(), SearchCriteria.Op.EQ);
 +
 +        if (tags != null && !tags.isEmpty()) {
 +            final SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
 +            for (int count = 0; count < tags.size(); count++) {
 +                tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
 +                tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
 +                tagSearch.cp();
 +            }
 +            tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
 +            sb.groupBy(sb.entity().getId());
 +            sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
 +        }
 +
 +        final SearchCriteria<StaticRouteVO> sc = sb.create();
 +        _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 +        if (id != null) {
 +            sc.addAnd("id", Op.EQ, id);
 +        }
 +
 +        if (vpcId != null) {
 +            sc.addAnd("vpcId", Op.EQ, vpcId);
 +        }
 +
 +        if (gatewayId != null) {
 +            sc.addAnd("vpcGatewayId", Op.EQ, gatewayId);
 +        }
 +
 +        if (tags != null && !tags.isEmpty()) {
 +            int count = 0;
 +            sc.setJoinParameters("tagSearch", "resourceType", ResourceObjectType.StaticRoute.toString());
 +            for (final String key : tags.keySet()) {
 +                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
 +                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
 +                count++;
 +            }
 +        }
 +
 +        final Pair<List<StaticRouteVO>, Integer> result = _staticRouteDao.searchAndCount(sc, searchFilter);
 +        return new Pair<List<? extends StaticRoute>, Integer>(result.first(), result.second());
 +    }
 +
 +    protected void detectRoutesConflict(final StaticRoute newRoute) throws NetworkRuleConflictException {
 +        // Multiple private gateways can exist within Vpc. Check for conflicts
 +        // for all static routes in Vpc
 +        // and not just the gateway
 +        final List<? extends StaticRoute> routes = _staticRouteDao.listByVpcIdAndNotRevoked(newRoute.getVpcId());
 +        assert routes.size() >= 1 : "For static routes, we now always first persist the route and then check for "
 +                + "network conflicts so we should at least have one rule at this point.";
 +
 +        for (final StaticRoute route : routes) {
 +            if (route.getId() == newRoute.getId()) {
 +                continue; // Skips my own route.
 +            }
 +
 +            if (NetUtils.isNetworksOverlap(route.getCidr(), newRoute.getCidr())) {
 +                throw new NetworkRuleConflictException("New static route cidr conflicts with existing route " + route);
 +            }
 +        }
 +    }
 +
 +    protected void markStaticRouteForRevoke(final StaticRouteVO route, final Account caller) {
 +        s_logger.debug("Revoking static route " + route);
 +        if (caller != null) {
 +            _accountMgr.checkAccess(caller, null, false, route);
 +        }
 +
 +        if (route.getState() == StaticRoute.State.Staged) {
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("Found a static route that is still in stage state so just removing it: " + route);
 +            }
 +            _staticRouteDao.remove(route.getId());
 +        } else if (route.getState() == StaticRoute.State.Add || route.getState() == StaticRoute.State.Active) {
 +            route.setState(StaticRoute.State.Revoke);
 +            _staticRouteDao.update(route.getId(), route);
 +            s_logger.debug("Marked static route " + route + " with state " + StaticRoute.State.Revoke);
 +        }
 +    }
 +
 +    protected class VpcCleanupTask extends ManagedContextRunnable {
 +        @Override
 +        protected void runInContext() {
 +            try {
 +                final GlobalLock lock = GlobalLock.getInternLock("VpcCleanup");
 +                if (lock == null) {
 +                    s_logger.debug("Couldn't get the global lock");
 +                    return;
 +                }
 +
 +                if (!lock.lock(30)) {
 +                    s_logger.debug("Couldn't lock the db");
 +                    return;
 +                }
 +
 +                try {
 +                    // Cleanup inactive VPCs
 +                    final List<VpcVO> inactiveVpcs = _vpcDao.listInactiveVpcs();
 +                    if (inactiveVpcs != null) {
 +                        s_logger.info("Found " + inactiveVpcs.size() + " removed VPCs to cleanup");
 +                        for (final VpcVO vpc : inactiveVpcs) {
 +                            s_logger.debug("Cleaning up " + vpc);
 +                            destroyVpc(vpc, _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), User.UID_SYSTEM);
 +                        }
 +                    }
 +                } catch (final Exception e) {
 +                    s_logger.error("Exception ", e);
 +                } finally {
 +                    lock.unlock();
 +                }
 +            } catch (final Exception e) {
 +                s_logger.error("Exception ", e);
 +            }
 +        }
 +    }
 +
 +    @DB
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true)
 +    public IpAddress associateIPToVpc(final long ipId, final long vpcId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException,
 +    ConcurrentOperationException {
 +        final Account caller = CallContext.current().getCallingAccount();
 +        Account owner = null;
 +
 +        final IpAddress ipToAssoc = _ntwkModel.getIp(ipId);
 +        if (ipToAssoc != null) {
 +            _accountMgr.checkAccess(caller, null, true, ipToAssoc);
 +            owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId());
 +        } else {
 +            s_logger.debug("Unable to find ip address by id: " + ipId);
 +            return null;
 +        }
 +
 +        final Vpc vpc = _vpcDao.findById(vpcId);
 +        if (vpc == null) {
 +            throw new InvalidParameterValueException("Invalid VPC id provided");
 +        }
 +
 +        // check permissions
 +        _accountMgr.checkAccess(caller, null, true, owner, vpc);
 +
 +        s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
 +
 +        final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(owner.getId(), vpcId) == null;
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(final TransactionStatus status) {
 +                final IPAddressVO ip = _ipAddressDao.findById(ipId);
 +                // update ip address with networkId
 +                ip.setVpcId(vpcId);
 +                ip.setSourceNat(isSourceNatFinal);
 +
 +                _ipAddressDao.update(ipId, ip);
 +
 +                // mark ip as allocated
 +                _ipAddrMgr.markPublicIpAsAllocated(ip);
 +            }
 +        });
 +
 +        s_logger.debug("Successfully assigned ip " + ipToAssoc + " to vpc " + vpc);
 +
 +        return _ipAddressDao.findById(ipId);
 +    }
 +
 +    @Override
 +    public void unassignIPFromVpcNetwork(final long ipId, final long networkId) {
 +        final IPAddressVO ip = _ipAddressDao.findById(ipId);
 +        if (isIpAllocatedToVpc(ip)) {
 +            return;
 +        }
 +
 +        if (ip == null || ip.getVpcId() == null) {
 +            return;
 +        }
 +
 +        s_logger.debug("Releasing VPC ip address " + ip + " from vpc network id=" + networkId);
 +
 +        final long vpcId = ip.getVpcId();
 +        boolean success = false;
 +        try {
 +            // unassign ip from the VPC router
 +            success = _ipAddrMgr.applyIpAssociations(_ntwkModel.getNetwork(networkId), true);
 +        } catch (final ResourceUnavailableException ex) {
 +            throw new CloudRuntimeException("Failed to apply ip associations for network id=" + networkId + " as a part of unassigning ip " + ipId + " from vpc", ex);
 +        }
 +
 +        if (success) {
 +            ip.setAssociatedWithNetworkId(null);
 +            _ipAddressDao.update(ipId, ip);
 +            s_logger.debug("IP address " + ip + " is no longer associated with the network inside vpc id=" + vpcId);
 +        } else {
 +            throw new CloudRuntimeException("Failed to apply ip associations for network id=" + networkId + " as a part of unassigning ip " + ipId + " from vpc");
 +        }
 +        s_logger.debug("Successfully released VPC ip address " + ip + " back to VPC pool ");
 +    }
 +
 +    @Override
 +    public boolean isIpAllocatedToVpc(final IpAddress ip) {
 +        return ip != null && ip.getVpcId() != null && (ip.isOneToOneNat() || !_firewallDao.listByIp(ip.getId()).isEmpty());
 +    }
 +
 +    @DB
 +    @Override
 +    public Network createVpcGuestNetwork(final long ntwkOffId, final String name, final String displayText, final String gateway, final String cidr, final String vlanId,
 +            String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, final Boolean subdomainAccess,
 +            final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId) throws ConcurrentOperationException, InsufficientCapacityException,
 +            ResourceAllocationException {
 +
 +        final Vpc vpc = getActiveVpc(vpcId);
 +
 +        if (vpc == null) {
 +            final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Enabled VPC ");
 +            ex.addProxyObject(String.valueOf(vpcId), "VPC");
 +            throw ex;
 +        }
 +        _accountMgr.checkAccess(caller, null, false, vpc);
 +
 +        if (networkDomain == null) {
 +            networkDomain = vpc.getNetworkDomain();
 +        }
 +
 +        if (!vpc.isRegionLevelVpc() && vpc.getZoneId() != zoneId) {
 +            throw new InvalidParameterValueException("New network doesn't belong to vpc zone");
 +        }
 +
 +        // 1) Validate if network can be created for VPC
 +        validateNtwkOffForNtwkInVpc(null, ntwkOffId, cidr, networkDomain, vpc, gateway, owner, aclId);
 +
 +        // 2) Create network
 +        final Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, false, networkDomain, owner, domainId, pNtwk, zoneId, aclType,
 +                                                                 subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled, null, externalId);
 +
 +        if (guestNetwork != null) {
 +            guestNetwork.setNetworkACLId(aclId);
 +            _ntwkDao.update(guestNetwork.getId(), (NetworkVO) guestNetwork);
 +        }
 +        return guestNetwork;
 +    }
 +
 +    protected IPAddressVO getExistingSourceNatInVpc(final long ownerId, final long vpcId) {
 +
 +        final List<IPAddressVO> addrs = listPublicIpsAssignedToVpc(ownerId, true, vpcId);
 +
 +        IPAddressVO sourceNatIp = null;
 +        if (addrs.isEmpty()) {
 +            return null;
 +        } else {
 +            // Account already has ip addresses
 +            for (final IPAddressVO addr : addrs) {
 +                if (addr.isSourceNat()) {
 +                    sourceNatIp = addr;
 +                    return sourceNatIp;
 +                }
 +            }
 +
 +            assert sourceNatIp != null : "How do we get a bunch of ip addresses but none of them are source nat? " + "account=" + ownerId + "; vpcId=" + vpcId;
 +        }
 +
 +        return sourceNatIp;
 +    }
 +
 +    protected List<IPAddressVO> listPublicIpsAssignedToVpc(final long accountId, final Boolean sourceNat, final long vpcId) {
 +        final SearchCriteria<IPAddressVO> sc = IpAddressSearch.create();
 +        sc.setParameters("accountId", accountId);
 +        sc.setParameters("vpcId", vpcId);
 +
 +        if (sourceNat != null) {
 +            sc.addAnd("sourceNat", SearchCriteria.Op.EQ, sourceNat);
 +        }
 +        sc.setJoinParameters("virtualNetworkVlanSB", "vlanType", VlanType.VirtualNetwork);
 +
 +        return _ipAddressDao.search(sc, null);
 +    }
 +
 +    @Override
 +    public PublicIp assignSourceNatIpAddressToVpc(final Account owner, final Vpc vpc) throws InsufficientAddressCapacityException, ConcurrentOperationException {
 +        final long dcId = vpc.getZoneId();
 +
 +        final IPAddressVO sourceNatIp = getExistingSourceNatInVpc(owner.getId(), vpc.getId());
 +
 +        PublicIp ipToReturn = null;
 +
 +        if (sourceNatIp != null) {
 +            ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId()));
 +        } else {
 +            ipToReturn = _ipAddrMgr.assignDedicateIpAddress(owner, null, vpc.getId(), dcId, true);
 +        }
 +
 +        return ipToReturn;
 +    }
 +
 +    @Override
 +    public List<HypervisorType> getSupportedVpcHypervisors() {
 +        return Collections.unmodifiableList(hTypes);
 +    }
 +
 +    private List<Provider> getVpcProviders(final long vpcId) {
 +        final List<String> providerNames = _vpcSrvcDao.getDistinctProviders(vpcId);
 +        final Map<String, Provider> providers = new HashMap<String, Provider>();
 +        for (final String providerName : providerNames) {
 +            if (!providers.containsKey(providerName)) {
 +                providers.put(providerName, Network.Provider.getProvider(providerName));
 +            }
 +        }
 +
 +        return new ArrayList<Provider>(providers.values());
 +    }
 +
 +    @Inject
 +    public void setVpcElements(final List<VpcProvider> vpcElements) {
 +        this.vpcElements = vpcElements;
 +    }
 +
 +    @Override
 +    @ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_CREATE, eventDescription = "Applying static route", async = true)
 +    public boolean applyStaticRoute(final long routeId) throws ResourceUnavailableException {
 +        final StaticRoute route = _staticRouteDao.findById(routeId);
 +        return applyStaticRoutesForVpc(route.getVpcId());
 +    }
 +
 +    @Override
 +    public boolean isSrcNatIpRequired(long vpcOfferingId) {
 +        final Map<Network.Service, Set<Network.Provider>> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId);
 +        return vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter);
 +    }
 +
 +    /**
 +     * rollingRestartVpc performs restart of routers of a VPC by first
 +     * deploying a new VR and then destroying old VRs in rolling fashion. For
 +     * non-redundant VPC, it will re-program the new router as final step
 +     * otherwise deploys a backup router for the VPC.
 +     * @param vpc vpc to be restarted
 +     * @param context reservation context
 +     * @return returns true when the rolling restart succeeds
 +     * @throws ResourceUnavailableException
 +     * @throws ConcurrentOperationException
 +     * @throws InsufficientCapacityException
 +     */
 +    private boolean rollingRestartVpc(final Vpc vpc, final ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
++        if (!NetworkOrchestrationService.RollingRestartEnabled.value()) {
++            if (shutdownVpc(vpc.getId())) {
++                return startVpc(vpc.getId(), false);
++            }
++            s_logger.warn("Failed to shutdown vpc as a part of VPC " + vpc + " restart process");
++            return false;
++        }
 +        s_logger.debug("Performing rolling restart of routers of VPC " + vpc);
 +        _ntwkMgr.destroyExpendableRouters(_routerDao.listByVpcId(vpc.getId()), context);
 +
 +        final DeployDestination dest = new DeployDestination(_dcDao.findById(vpc.getZoneId()), null, null, null);
 +        final List<DomainRouterVO> oldRouters = _routerDao.listByVpcId(vpc.getId());
 +
 +        // Create a new router
 +        if (oldRouters.size() > 0) {
 +            vpc.setRollingRestart(true);
 +        }
 +        startVpc(vpc, dest, context);
 +        if (oldRouters.size() > 0) {
 +            vpc.setRollingRestart(false);
 +        }
 +
 +        // For redundant vpc wait for 3*advert_int+skew_seconds for VRRP to kick in
 +        if (vpc.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) {
 +            try {
 +                Thread.sleep(NetworkOrchestrationService.RVRHandoverTime);
 +            } catch (final InterruptedException ignored) {
 +            }
 +        }
 +
 +        // Destroy old routers
 +        for (final DomainRouterVO oldRouter : oldRouters) {
 +            _routerService.destroyRouter(oldRouter.getId(), context.getAccount(), context.getCaller().getId());
 +        }
 +
 +        // Re-program VPC VR or add a new backup router for redundant VPC
 +        if (!startVpc(vpc, dest, context)) {
 +            s_logger.debug("Failed to re-program VPC router or deploy a new backup router for VPC" + vpc);
 +            return false;
 +        }
 +
 +        return _ntwkMgr.areRoutersRunning(_routerDao.listByVpcId(vpc.getId()));
 +    }
 +
 +}