You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ch...@apache.org on 2013/01/18 02:01:23 UTC

[5/39] WIP : extract NetworkService WIP : move stuff between network manager and network service. at this point there is about 700 lines of duplicated code WIP: Leave creation of default offerings to NetworkManager init WIP: clean up imports

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f4da2199/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
new file mode 100755
index 0000000..edd53e2
--- /dev/null
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -0,0 +1,2964 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import java.security.InvalidParameterException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.acl.ControlledEntity.ACLType;
+import com.cloud.acl.SecurityChecker.AccessType;
+import com.cloud.api.commands.CreateNetworkCmd;
+import com.cloud.api.commands.ListNetworksCmd;
+import com.cloud.api.commands.ListTrafficTypeImplementorsCmd;
+import com.cloud.api.commands.RestartNetworkCmd;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.AccountVlanMapDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventVO;
+import com.cloud.event.dao.EventDao;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.UnsupportedServiceException;
+import com.cloud.network.IpAddress.State;
+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.Networks.BroadcastDomainType;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.PhysicalNetwork.BroadcastDomainRange;
+import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDomainDao;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
+import com.cloud.network.element.NetworkElement;
+import com.cloud.network.element.VirtualRouterElement;
+import com.cloud.network.element.VpcVirtualRouterElement;
+import com.cloud.network.guru.NetworkGuru;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.rules.RulesManager;
+import com.cloud.network.vpc.PrivateIpVO;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpc.dao.PrivateIpDao;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.org.Grouping;
+import com.cloud.projects.Project;
+import com.cloud.projects.ProjectManager;
+import com.cloud.server.ResourceTag.TaggedResourceType;
+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.AccountVO;
+import com.cloud.user.DomainManager;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.User;
+import com.cloud.user.UserContext;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.AnnotationHelper;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
+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.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.ReservationContextImpl;
+import com.cloud.vm.SecondaryStorageVmVO;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+/**
+ * NetworkServiceImpl implements NetworkService.
+ */
+@Local(value = { NetworkService.class })
+public class NetworkServiceImpl implements  NetworkService, Manager {
+    private static final Logger s_logger = Logger.getLogger(NetworkServiceImpl.class);
+
+    String _name;
+    @Inject
+    DataCenterDao _dcDao = null;
+    @Inject
+    VlanDao _vlanDao = null;
+    @Inject
+    IPAddressDao _ipAddressDao = null;
+    @Inject
+    AccountDao _accountDao = null;
+    @Inject
+    DomainDao _domainDao = null;
+
+    @Inject
+    EventDao _eventDao = null;
+    @Inject
+    ConfigurationDao _configDao;
+    @Inject
+    UserVmDao _userVmDao = null;
+
+    @Inject
+    AccountManager _accountMgr;
+    @Inject
+    ConfigurationManager _configMgr;
+    @Inject
+    AccountVlanMapDao _accountVlanMapDao;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao = null;
+    @Inject
+    NetworkDao _networksDao = null;
+    @Inject
+    NicDao _nicDao = null;
+    @Inject
+    RulesManager _rulesMgr;
+
+    @Inject
+    UsageEventDao _usageEventDao;
+    
+    @Inject(adapter = NetworkGuru.class)
+    Adapters<NetworkGuru> _networkGurus;
+  
+    @Inject
+    NetworkDomainDao _networkDomainDao;
+    @Inject
+    VMInstanceDao _vmDao;
+
+    @Inject
+    FirewallRulesDao _firewallDao;
+  
+    @Inject
+    ResourceLimitService _resourceLimitMgr;
+   
+    @Inject
+    DomainManager _domainMgr;
+    @Inject
+    ProjectManager _projectMgr;
+    @Inject
+    NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    PhysicalNetworkServiceProviderDao _pNSPDao;
+    
+    @Inject
+    PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
+
+    @Inject
+    NetworkServiceMapDao _ntwkSrvcDao;
+    @Inject
+    StorageNetworkManager _stnwMgr;
+    @Inject
+    VpcManager _vpcMgr;
+    @Inject
+    PrivateIpDao _privateIpDao;
+    @Inject
+    ResourceTagDao _resourceTagDao;
+    @Inject
+    NetworkManager _networkMgr;
+
+    private final HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5);
+
+    String _networkDomain;
+    int _cidrLimit;
+    boolean _allowSubdomainNetworkAccess;
+
+    private Map<String, String> _configs;
+
+    
+   
+
+    /* Get a list of IPs, classify them by service */
+    //@Override
+    public Map<PublicIp, Set<Service>> getIpToServices(List<PublicIp> publicIps, boolean rulesRevoked, boolean includingFirewall) {
+        Map<PublicIp, Set<Service>> ipToServices = new HashMap<PublicIp, Set<Service>>();
+
+        if (publicIps != null && !publicIps.isEmpty()) {
+            Set<Long> networkSNAT = new HashSet<Long>();
+            for (PublicIp ip : publicIps) {
+                Set<Service> services = ipToServices.get(ip);
+                if (services == null) {
+                    services = new HashSet<Service>();
+                }
+                if (ip.isSourceNat()) {
+                    if (!networkSNAT.contains(ip.getAssociatedWithNetworkId())) {
+                        services.add(Service.SourceNat);
+                        networkSNAT.add(ip.getAssociatedWithNetworkId());
+                    } else {
+                        CloudRuntimeException ex = new CloudRuntimeException("Multiple generic soure NAT IPs provided for network");
+                        // see the IPAddressVO.java class.
+                        ex.addProxyObject("user_ip_address", ip.getAssociatedWithNetworkId(), "networkId");
+                        throw ex;
+                    }
+                }
+                ipToServices.put(ip, services);
+
+                // if IP in allocating state then it will not have any rules attached so skip IPAssoc to network service
+                // provider
+                if (ip.getState() == State.Allocating) {
+                    continue;
+                }
+
+                // check if any active rules are applied on the public IP
+                Set<Purpose> purposes = getPublicIpPurposeInRules(ip, false, includingFirewall);
+                // Firewall rules didn't cover static NAT
+                if (ip.isOneToOneNat() && ip.getAssociatedWithVmId() != null) {
+                    if (purposes == null) {
+                        purposes = new HashSet<Purpose>();
+                    }
+                    purposes.add(Purpose.StaticNat);
+                }
+                if (purposes == null || purposes.isEmpty()) {
+                    // since no active rules are there check if any rules are applied on the public IP but are in
+// revoking state
+                    
+                    purposes = getPublicIpPurposeInRules(ip, true, includingFirewall);
+                    if (ip.isOneToOneNat()) {
+                        if (purposes == null) {
+                            purposes = new HashSet<Purpose>();
+                        }
+                        purposes.add(Purpose.StaticNat);
+                    }
+                    if (purposes == null || purposes.isEmpty()) {
+                        // IP is not being used for any purpose so skip IPAssoc to network service provider
+                        continue;
+                    } else {
+                        if (rulesRevoked) {
+                            // no active rules/revoked rules are associated with this public IP, so remove the
+// association with the provider
+                            ip.setState(State.Releasing);
+                        } else {
+                            if (ip.getState() == State.Releasing) {
+                                // rules are not revoked yet, so don't let the network service provider revoke the IP
+// association
+                                // mark IP is allocated so that IP association will not be removed from the provider
+                                ip.setState(State.Allocated);
+                            }
+                        }
+                    }
+                }
+                if (purposes.contains(Purpose.StaticNat)) {
+                    services.add(Service.StaticNat);
+                }
+                if (purposes.contains(Purpose.LoadBalancing)) {
+                    services.add(Service.Lb);
+                }
+                if (purposes.contains(Purpose.PortForwarding)) {
+                    services.add(Service.PortForwarding);
+                }
+                if (purposes.contains(Purpose.Vpn)) {
+                    services.add(Service.Vpn);
+                }
+                if (purposes.contains(Purpose.Firewall)) {
+                    services.add(Service.Firewall);
+                }
+                if (services.isEmpty()) {
+                    continue;
+                }
+                ipToServices.put(ip, services);
+            }
+        }
+        return ipToServices;
+    }
+
+    public boolean canIpUsedForNonConserveService(PublicIp ip, Service service) {
+        // If it's non-conserve mode, then the new ip should not be used by any other services
+        List<PublicIp> ipList = new ArrayList<PublicIp>();
+        ipList.add(ip);
+        Map<PublicIp, Set<Service>> ipToServices = getIpToServices(ipList, false, false);
+        Set<Service> services = ipToServices.get(ip);
+        // Not used currently, safe
+        if (services == null || services.isEmpty()) {
+            return true;
+        }
+        // Since it's non-conserve mode, only one service should used for IP
+        if (services.size() != 1) {
+            throw new InvalidParameterException("There are multiple services used ip " + ip.getAddress() + ".");
+        }
+        if (service != null && !((Service) services.toArray()[0] == service || service.equals(Service.Firewall))) {
+            throw new InvalidParameterException("The IP " + ip.getAddress() + " is already used as " + ((Service) services.toArray()[0]).getName() + " rather than " + service.getName());
+        }
+        return true;
+    }
+
+    protected boolean canIpsUsedForNonConserve(List<PublicIp> publicIps) {
+        boolean result = true;
+        for (PublicIp ip : publicIps) {
+            result = canIpUsedForNonConserveService(ip, null);
+            if (!result) {
+                break;
+            }
+        }
+        return result;
+    }
+
+    private boolean canIpsUseOffering(List<PublicIp> publicIps, long offeringId) {
+        Map<PublicIp, Set<Service>> ipToServices = getIpToServices(publicIps, false, true);
+        Map<Service, Set<Provider>> serviceToProviders = _networkMgr.getNetworkOfferingServiceProvidersMap(offeringId);
+        for (PublicIp ip : ipToServices.keySet()) {
+            Set<Service> services = ipToServices.get(ip);
+            Provider provider = null;
+            for (Service service : services) {
+                Set<Provider> curProviders = serviceToProviders.get(service);
+                if (curProviders == null || curProviders.isEmpty()) {
+                    continue;
+                }
+                Provider curProvider = (Provider) curProviders.toArray()[0];
+                if (provider == null) {
+                    provider = curProvider;
+                    continue;
+                }
+                // We don't support multiple providers for one service now
+                if (!provider.equals(curProvider)) {
+                    throw new InvalidParameterException("There would be multiple providers for IP " + ip.getAddress() + " with the new network offering!");
+                }
+            }
+        }
+        return true;
+    }
+    
+
+    
+
+    private Set<Purpose> getPublicIpPurposeInRules(PublicIp ip, boolean includeRevoked, boolean includingFirewall) {
+        Set<Purpose> result = new HashSet<Purpose>();
+        List<FirewallRuleVO> rules = null;
+        if (includeRevoked) {
+            rules = _firewallDao.listByIp(ip.getId());
+        } else {
+            rules = _firewallDao.listByIpAndNotRevoked(ip.getId());
+        }
+
+        if (rules == null || rules.isEmpty()) {
+            return null;
+        }
+
+        for (FirewallRuleVO rule : rules) {
+            if (rule.getPurpose() != Purpose.Firewall || includingFirewall) {
+                result.add(rule.getPurpose());
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public List<? extends Network> getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner) {
+
+        return _networksDao.listByZoneAndGuestType(owner.getId(), zoneId, Network.GuestType.Isolated, false);
+    }
+    
+    @Override
+    public List<? extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner) {
+
+        return _networksDao.listSourceNATEnabledNetworks(owner.getId(), zoneId, Network.GuestType.Isolated);
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true)
+    public IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId)
+            throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
+
+        if (networkId != null) {
+            Network network = _networksDao.findById(networkId);
+            if (network == null) {
+                throw new InvalidParameterValueException("Invalid network id is given");
+            }
+            if (network.getGuestType() == Network.GuestType.Shared) {
+                DataCenter zone = _configMgr.getZone(zoneId);
+                if (zone == null) {
+                    throw new InvalidParameterValueException("Invalid zone Id is given");
+                }
+
+                // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork'
+                if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) {
+                    Account caller = UserContext.current().getCaller();
+                    long callerUserId = UserContext.current().getCallerUserId();
+                    _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network);
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId());
+                    }
+                    return _networkMgr.allocateIp(ipOwner, false, caller, zone);
+                } else {
+                    throw new InvalidParameterValueException("Associate IP address can only be called on the shared networks in the advanced zone" +
+                            " with Firewall/Source Nat/Static Nat/Port Forwarding/Load balancing services enabled");
+                }
+            }
+        }
+
+        return allocateIP(ipOwner, false,  zoneId);
+    }
+
+    protected IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) 
+            throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
+        Account caller = UserContext.current().getCaller();
+        long callerUserId = UserContext.current().getCallerUserId();
+        // check permissions
+        _accountMgr.checkAccess(caller, null, false, ipOwner);
+        
+        DataCenter zone = _configMgr.getZone(zoneId);
+        
+        return _networkMgr.allocateIp(ipOwner, isSystem, caller, zone);
+    }
+
+   
+    
+
+
+    @Override
+    @DB
+    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
+        _name = name;
+
+        
+
+        _configs = _configDao.getConfiguration("Network", params);
+        _networkDomain = _configs.get(Config.GuestDomainSuffix.key());
+
+        _cidrLimit = NumbersUtil.parseInt(_configs.get(Config.NetworkGuestCidrLimit.key()), 22);
+
+        NetworkOfferingVO publicNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemPublicNetwork, TrafficType.Public, true);
+        publicNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(publicNetworkOffering);
+        _systemNetworks.put(NetworkOfferingVO.SystemPublicNetwork, publicNetworkOffering);
+        NetworkOfferingVO managementNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemManagementNetwork, TrafficType.Management, false);
+        managementNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(managementNetworkOffering);
+        _systemNetworks.put(NetworkOfferingVO.SystemManagementNetwork, managementNetworkOffering);
+        NetworkOfferingVO controlNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemControlNetwork, TrafficType.Control, false);
+        controlNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(controlNetworkOffering);
+        _systemNetworks.put(NetworkOfferingVO.SystemControlNetwork, controlNetworkOffering);
+        NetworkOfferingVO storageNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemStorageNetwork, TrafficType.Storage, true);
+        storageNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(storageNetworkOffering);
+        _systemNetworks.put(NetworkOfferingVO.SystemStorageNetwork, storageNetworkOffering);
+        NetworkOfferingVO privateGatewayNetworkOffering = new NetworkOfferingVO(NetworkOfferingVO.SystemPrivateGatewayNetworkOffering,
+                GuestType.Isolated);
+        privateGatewayNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(privateGatewayNetworkOffering);
+        _systemNetworks.put(NetworkOfferingVO.SystemPrivateGatewayNetworkOffering, privateGatewayNetworkOffering);
+
+
+        
+
+
+        _allowSubdomainNetworkAccess = Boolean.valueOf(_configs.get(Config.SubDomainNetworkAccess.key()));
+
+        s_logger.info("Network Manager is configured.");
+
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public boolean start() {
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    protected NetworkServiceImpl() {
+    }
+
+
+
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_NET_IP_RELEASE, eventDescription = "disassociating Ip", async = true)
+    public boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
+        Long userId = UserContext.current().getCallerUserId();
+        Account caller = UserContext.current().getCaller();
+
+        // Verify input parameters
+        IPAddressVO ipVO = _ipAddressDao.findById(ipAddressId);
+        if (ipVO == null) {
+            throw new InvalidParameterValueException("Unable to find ip address by id");
+        }
+
+        if (ipVO.getAllocatedTime() == null) {
+            s_logger.debug("Ip Address id= " + ipAddressId + " is not allocated, so do nothing.");
+            return true;
+        }
+
+        // verify permissions
+        if (ipVO.getAllocatedToAccountId() != null) {
+            _accountMgr.checkAccess(caller, null, true, ipVO);
+        }
+
+        if (ipVO.isSourceNat()) {
+            throw new IllegalArgumentException("ip address is used for source nat purposes and can not be disassociated.");
+        }
+
+        VlanVO vlan = _vlanDao.findById(ipVO.getVlanId());
+        if (!vlan.getVlanType().equals(VlanType.VirtualNetwork)) {
+            throw new IllegalArgumentException("only ip addresses that belong to a virtual network may be disassociated.");
+        }
+
+        // Check for account wide pool. It will have an entry for account_vlan_map.
+        if (_accountVlanMapDao.findAccountVlanMap(ipVO.getAllocatedToAccountId(), ipVO.getVlanId()) != null) {            
+            //see IPaddressVO.java
+            InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to" +
+                    " Account wide IP pool and cannot be disassociated");
+            ex.addProxyObject("user_ip_address", ipAddressId, "ipAddressId");
+            throw ex;
+        }
+
+        // don't allow releasing system ip address
+        if (ipVO.getSystem()) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Can't release system IP address with specified id");
+            ex.addProxyObject(ipVO, ipVO.getId(), "systemIpAddrId");
+            throw ex;
+        }
+
+        boolean success = _networkMgr.disassociatePublicIpAddress(ipAddressId, userId, caller);
+
+        if (success) {
+            Long networkId = ipVO.getAssociatedWithNetworkId();
+            if (networkId != null) {
+                Network guestNetwork = getNetwork(networkId);
+                NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId());
+                Long vmId = ipVO.getAssociatedWithVmId();
+                if (offering.getElasticIp() && vmId != null) {
+                    _rulesMgr.getSystemIpAndEnableStaticNatForVm(_userVmDao.findById(vmId), true);
+                    return true;
+                }
+            }
+        } else {
+            s_logger.warn("Failed to release public ip address id=" + ipAddressId);
+        }
+        return success;
+    }
+
+
+    @Override
+    @DB
+    public Network getNetwork(long id) {
+        return _networksDao.findById(id);
+    }
+   
+
+    private void checkSharedNetworkCidrOverlap(Long zoneId, long physicalNetworkId, String cidr) {
+        if (zoneId == null || cidr == null) {
+            return;
+        }
+
+        DataCenter zone = _dcDao.findById(zoneId);
+        List<NetworkVO> networks = _networksDao.listByZone(zoneId);
+        Map<Long, String> networkToCidr = new HashMap<Long, String>();
+
+        // check for CIDR overlap with all possible CIDR for isolated guest networks
+        // in the zone when using external networking
+        PhysicalNetworkVO pNetwork = _physicalNetworkDao.findById(physicalNetworkId);
+        if (pNetwork.getVnet() != null) {
+            String vlanRange[] = pNetwork.getVnet().split("-");
+            int lowestVlanTag = Integer.valueOf(vlanRange[0]);
+            int highestVlanTag = Integer.valueOf(vlanRange[1]);
+            for (int vlan=lowestVlanTag; vlan <= highestVlanTag; ++vlan) {
+                int offset = vlan - lowestVlanTag;
+                String globalVlanBits = _configDao.getValue(Config.GuestVlanBits.key());
+                int cidrSize = 8 + Integer.parseInt(globalVlanBits);
+                String guestNetworkCidr = zone.getGuestNetworkCidr();
+                String[] cidrTuple = guestNetworkCidr.split("\\/");
+                long newCidrAddress = (NetUtils.ip2Long(cidrTuple[0]) & 0xff000000) | (offset << (32 - cidrSize));
+                if (NetUtils.isNetworksOverlap(NetUtils.long2Ip(newCidrAddress), cidr)) {
+                    throw new InvalidParameterValueException("Specified CIDR for shared network conflict with CIDR that is reserved for zone vlan " + vlan);
+                }
+            }
+        }
+
+        // check for CIDR overlap with all CIDR's of the shared networks in the zone
+        for (NetworkVO network : networks) {
+            if (network.getGuestType() == GuestType.Isolated) {
+                continue;
+            }
+            if (network.getCidr() != null) {
+                networkToCidr.put(network.getId(), network.getCidr());
+            }
+        }
+        if (networkToCidr != null && !networkToCidr.isEmpty()) {
+            for (long networkId : networkToCidr.keySet()) {
+                String ntwkCidr = networkToCidr.get(networkId);
+                if (NetUtils.isNetworksOverlap(ntwkCidr, cidr)) {
+                    throw new InvalidParameterValueException("Specified CIDR for shared network conflict with CIDR of a shared network in the zone.");
+                }
+            }
+        }
+    }
+    
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network")
+    public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
+        Long networkOfferingId = cmd.getNetworkOfferingId();
+        String gateway = cmd.getGateway();
+        String startIP = cmd.getStartIp();
+        String endIP = cmd.getEndIp();
+        String netmask = cmd.getNetmask();
+        String networkDomain = cmd.getNetworkDomain();
+        String vlanId = cmd.getVlan();
+        String name = cmd.getNetworkName();
+        String displayText = cmd.getDisplayText();
+        Account caller = UserContext.current().getCaller();
+        Long physicalNetworkId = cmd.getPhysicalNetworkId();
+        Long zoneId = cmd.getZoneId();
+        String aclTypeStr = cmd.getAclType();
+        Long domainId = cmd.getDomainId();
+        boolean isDomainSpecific = false;
+        Boolean subdomainAccess = cmd.getSubdomainAccess();
+        Long vpcId = cmd.getVpcId();
+
+        // Validate network offering
+        NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
+        if (ntwkOff == null || ntwkOff.isSystemOnly()) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id");
+            if (ntwkOff != null) {
+                ex.addProxyObject(ntwkOff, networkOfferingId, "networkOfferingId");                
+                // Get the VO object's table name.
+                String tablename = AnnotationHelper.getTableName(ntwkOff);
+                if (tablename != null) {
+                    ex.addProxyObject(tablename, networkOfferingId, "networkOfferingId");
+                } else {
+                    s_logger.info("\nCould not retrieve table name (annotation) from " + tablename + " VO proxy object\n");
+                }
+                throw ex;
+            }
+            throw ex;
+        }
+        // validate physical network and zone
+        // Check if physical network exists
+        PhysicalNetwork pNtwk = null;
+        if (physicalNetworkId != null) {
+            pNtwk = _physicalNetworkDao.findById(physicalNetworkId);
+            if (pNtwk == null) {
+                throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id");
+            }
+        }
+
+        if (zoneId == null) {
+            zoneId = pNtwk.getDataCenterId();
+        }
+
+        DataCenter zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Specified zone id was not found");
+        }
+        
+        if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
+            // See DataCenterVO.java
+            PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
+            ex.addProxyObject(zone, zoneId, "zoneId");
+            throw ex;            
+        }
+
+        // Only domain and account ACL types are supported in Acton.
+        ACLType aclType = null;
+        if (aclTypeStr != null) {
+            if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) {
+                aclType = ACLType.Account;
+            } else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) {
+                aclType = ACLType.Domain;
+            } else {
+                throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types");
+            }
+            // In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account
+            if (ntwkOff.getGuestType() == GuestType.Isolated) {
+                if (aclType != ACLType.Account) {
+                    throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + Network.GuestType.Isolated);
+                }
+            } else if (ntwkOff.getGuestType() == GuestType.Shared) {
+                if (!(aclType == ACLType.Domain || aclType == ACLType.Account)) {
+                    throw new InvalidParameterValueException("AclType should be " + ACLType.Domain + " or " + 
+                ACLType.Account + " for network of type " + Network.GuestType.Shared);
+                }
+            }
+        } else {
+            if (ntwkOff.getGuestType() == GuestType.Isolated) {
+                aclType = ACLType.Account;
+            } else if (ntwkOff.getGuestType() == GuestType.Shared) {
+                aclType = ACLType.Domain;
+            }
+        }
+
+        // Only Admin can create Shared networks
+        if (ntwkOff.getGuestType() == GuestType.Shared && !_accountMgr.isAdmin(caller.getType())) {
+            throw new InvalidParameterValueException("Only Admins can create network with guest type " + GuestType.Shared);
+        }
+
+        // Check if the network is domain specific
+        if (aclType == ACLType.Domain) {
+            // only Admin can create domain with aclType=Domain
+            if (!_accountMgr.isAdmin(caller.getType())) {
+                throw new PermissionDeniedException("Only admin can create networks with aclType=Domain");
+            }
+
+            // only shared networks can be Domain specific
+            if (ntwkOff.getGuestType() != GuestType.Shared) {
+                throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain);
+            }
+
+            if (domainId != null) {
+                if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Shared) {
+                    throw new InvalidParameterValueException("Domain level networks are supported just for traffic type "
+                + TrafficType.Guest + " and guest type " + Network.GuestType.Shared);
+                }
+
+                DomainVO domain = _domainDao.findById(domainId);
+                if (domain == null) {                    
+                    throw new InvalidParameterValueException("Unable to find domain by specified id");
+                }
+                _accountMgr.checkAccess(caller, domain);
+            }
+            isDomainSpecific = true;
+
+        } else if (subdomainAccess != null) {
+            throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain");
+        }
+        Account owner = null;
+        if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) {
+            owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId());
+        } else {
+            owner = caller;
+        }
+
+        UserContext.current().setAccountId(owner.getAccountId());
+
+        // VALIDATE IP INFO
+        // if end ip is not specified, default it to startIp
+        if (startIP != null) {
+            if (!NetUtils.isValidIp(startIP)) {
+                throw new InvalidParameterValueException("Invalid format for the startIp parameter");
+            }
+            if (endIP == null) {
+                endIP = startIP;
+            } else if (!NetUtils.isValidIp(endIP)) {
+                throw new InvalidParameterValueException("Invalid format for the endIp parameter");
+            }
+        }
+
+        if (startIP != null && endIP != null) {
+            if (!(gateway != null && netmask != null)) {
+                throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in");
+            }
+        }
+
+        String cidr = null;
+        if (gateway != null && netmask != null) {
+            if (!NetUtils.isValidIp(gateway)) {
+                throw new InvalidParameterValueException("Invalid gateway");
+            }
+            if (!NetUtils.isValidNetmask(netmask)) {
+                throw new InvalidParameterValueException("Invalid netmask");
+            }
+
+            cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
+        }
+
+        // Regular user can create Guest Isolated Source Nat enabled network only
+        if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL
+                && (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated
+                        && areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))) {
+            throw new InvalidParameterValueException("Regular user can create a network only from the network" +
+                    " offering having traffic type " + TrafficType.Guest + " and network type "
+                    + Network.GuestType.Isolated + " with a service " + Service.SourceNat.getName() + " enabled");
+        }
+
+        // Don't allow to specify vlan if the caller is a regular user
+        if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getSpecifyVlan() || vlanId != null)) {
+            throw new InvalidParameterValueException("Regular user is not allowed to specify vlanId");
+        }
+
+        // For non-root admins check cidr limit - if it's allowed by global config value
+        if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && cidr != null) {
+
+            String[] cidrPair = cidr.split("\\/");
+            int cidrSize = Integer.valueOf(cidrPair[1]);
+
+            if (cidrSize < _cidrLimit) {
+                throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit);
+            }
+        }
+
+        Collection<String> ntwkProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(ntwkOff, physicalNetworkId).values();
+        if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
+            if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) &&
+                    isSharedNetworkOfferingWithServices(networkOfferingId)) {
+                // validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone
+                checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr);
+            } else {
+                throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!");
+            }
+        }
+
+
+        // Vlan is created in 2 cases - works in Advance zone only:
+        // 1) GuestType is Shared
+        // 2) GuestType is Isolated, but SourceNat service is disabled
+        boolean createVlan = (startIP != null && endIP != null && zone.getNetworkType() == NetworkType.Advanced
+                && ((ntwkOff.getGuestType() == Network.GuestType.Shared)
+                || (ntwkOff.getGuestType() == GuestType.Isolated && 
+                !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))));
+
+        // Can add vlan range only to the network which allows it
+        if (createVlan && !ntwkOff.getSpecifyIpRanges()) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id doesn't support adding multiple ip ranges");
+            ex.addProxyObject(ntwkOff, ntwkOff.getId(), "networkOfferingId");
+            String tablename = AnnotationHelper.getTableName(ntwkOff);
+            if (tablename != null) {
+                ex.addProxyObject(tablename, ntwkOff.getId(), "networkOfferingId");
+            } else {
+                s_logger.info("\nCould not retrieve table name (annotation) from " + tablename + " VO proxy object\n");
+            }
+            throw ex;   
+        }
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        Long sharedDomainId = null;
+        if (isDomainSpecific) {
+            if (domainId != null) {
+                sharedDomainId = domainId;
+            } else {
+                sharedDomainId = _domainMgr.getDomain(Domain.ROOT_DOMAIN).getId();
+                subdomainAccess = true;
+            }
+        }
+
+        // default owner to system if network has aclType=Domain
+        if (aclType == ACLType.Domain) {
+            owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
+        }
+
+        //Create guest network
+        Network network = null;
+        if (vpcId != null) {
+            if (!_configMgr.isOfferingForVpc(ntwkOff)){
+                throw new InvalidParameterValueException("Network offering can't be used for VPC networks");
+            }
+            network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, 
+                    networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, caller);
+        } else {
+            if (_configMgr.isOfferingForVpc(ntwkOff)){
+                throw new InvalidParameterValueException("Network offering can be used for VPC networks only");
+            }
+            network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, 
+                    networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId);
+        }  
+
+        if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) {
+            // Create vlan ip range
+            _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId,
+                    false, null, startIP, endIP, gateway, netmask, vlanId, null);
+        }
+
+        txn.commit();
+
+        return network;
+    }
+
+   
+
+    @Override
+    public List<? extends Network> searchForNetworks(ListNetworksCmd cmd) {
+        Long id = cmd.getId();
+        String keyword = cmd.getKeyword();
+        Long zoneId = cmd.getZoneId();
+        Account caller = UserContext.current().getCaller();
+        Long domainId = cmd.getDomainId();
+        String accountName = cmd.getAccountName();
+        String guestIpType = cmd.getGuestIpType();
+        String trafficType = cmd.getTrafficType();
+        Boolean isSystem = cmd.getIsSystem();
+        String aclType = cmd.getAclType();
+        Long projectId = cmd.getProjectId();
+        List<Long> permittedAccounts = new ArrayList<Long>();
+        String path = null;
+        Long physicalNetworkId = cmd.getPhysicalNetworkId();
+        List<String> supportedServicesStr = cmd.getSupportedServices();
+        Boolean restartRequired = cmd.getRestartRequired();
+        boolean listAll = cmd.listAll();
+        boolean isRecursive = cmd.isRecursive();
+        Boolean specifyIpRanges = cmd.getSpecifyIpRanges();
+        Long vpcId = cmd.getVpcId();
+        Boolean canUseForDeploy = cmd.canUseForDeploy();
+        Map<String, String> tags = cmd.getTags();
+        Boolean forVpc = cmd.getForVpc();
+
+        // 1) default is system to false if not specified
+        // 2) reset parameter to false if it's specified by the regular user
+        if ((isSystem == null || caller.getType() == Account.ACCOUNT_TYPE_NORMAL) && id == null) {
+            isSystem = false;
+        }
+
+        // Account/domainId parameters and isSystem are mutually exclusive
+        if (isSystem != null && isSystem && (accountName != null || domainId != null)) {
+            throw new InvalidParameterValueException("System network belongs to system, account and domainId parameters can't be specified");
+        }
+
+        if (domainId != null) {
+            DomainVO domain = _domainDao.findById(domainId);
+            if (domain == null) {
+                // see DomainVO.java
+                throw new InvalidParameterValueException("Specified domain id doesn't exist in the system");
+            }
+
+            _accountMgr.checkAccess(caller, domain);
+            if (accountName != null) {
+                Account owner = _accountMgr.getActiveAccountByName(accountName, domainId);
+                if (owner == null) {
+                    // see DomainVO.java
+                    throw new InvalidParameterValueException("Unable to find account " + accountName + " in specified domain");
+                }
+
+                _accountMgr.checkAccess(caller, null, true, owner);
+                permittedAccounts.add(owner.getId());
+            }
+        }
+
+        if (!_accountMgr.isAdmin(caller.getType()) || (!listAll && (projectId != null && projectId.longValue() != -1 && domainId == null))) {
+            permittedAccounts.add(caller.getId());
+            domainId = caller.getDomainId();
+        }
+
+        // set project information
+        boolean skipProjectNetworks = true;
+        if (projectId != null) {
+            if (projectId.longValue() == -1) {
+                if (!_accountMgr.isAdmin(caller.getType())) {
+                    permittedAccounts.addAll(_projectMgr.listPermittedProjectAccounts(caller.getId()));
+                }
+            } else {
+                permittedAccounts.clear();
+                Project project = _projectMgr.getProject(projectId);
+                if (project == null) {                    
+                    throw new InvalidParameterValueException("Unable to find project by specified id");
+                }
+                if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) {
+                    // getProject() returns type ProjectVO.
+                    InvalidParameterValueException ex = new InvalidParameterValueException("Account " + caller + " cannot access specified project id");
+                    ex.addProxyObject(project, projectId, "projectId");                    
+                    throw ex;
+                }
+                permittedAccounts.add(project.getProjectAccountId());
+            }
+            skipProjectNetworks = false;
+        }
+
+        if (domainId != null) {
+            path = _domainDao.findById(domainId).getPath();
+        } else {
+        path = _domainDao.findById(caller.getDomainId()).getPath();
+        } 
+        
+        if (listAll && domainId == null) {
+            isRecursive = true;
+        }
+
+        Filter searchFilter = new Filter(NetworkVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
+        SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder();
+        
+        if (forVpc != null) {
+            if (forVpc) {
+                sb.and("vpc", sb.entity().getVpcId(), Op.NNULL);
+            } else {
+                sb.and("vpc", sb.entity().getVpcId(), Op.NULL);
+            }
+        }
+
+        // Don't display networks created of system network offerings
+        SearchBuilder<NetworkOfferingVO> networkOfferingSearch = _networkOfferingDao.createSearchBuilder();
+        networkOfferingSearch.and("systemOnly", networkOfferingSearch.entity().isSystemOnly(), SearchCriteria.Op.EQ);
+        if (isSystem != null && isSystem) {
+            networkOfferingSearch.and("trafficType", networkOfferingSearch.entity().getTrafficType(), SearchCriteria.Op.EQ);
+        }
+        sb.join("networkOfferingSearch", networkOfferingSearch, sb.entity().getNetworkOfferingId(), networkOfferingSearch.entity().getId(), JoinBuilder.JoinType.INNER);
+
+        SearchBuilder<DataCenterVO> zoneSearch = _dcDao.createSearchBuilder();
+        zoneSearch.and("networkType", zoneSearch.entity().getNetworkType(), SearchCriteria.Op.EQ);
+        sb.join("zoneSearch", zoneSearch, sb.entity().getDataCenterId(), zoneSearch.entity().getId(), JoinBuilder.JoinType.INNER);
+        sb.and("removed", sb.entity().getRemoved(), Op.NULL);
+
+        if (tags != null && !tags.isEmpty()) {
+            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);
+        }
+
+        if (permittedAccounts.isEmpty()) {
+            SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
+            domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
+            sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
+        }
+
+
+            SearchBuilder<AccountVO> accountSearch = _accountDao.createSearchBuilder();
+        accountSearch.and("typeNEQ", accountSearch.entity().getType(), SearchCriteria.Op.NEQ);
+        accountSearch.and("typeEQ", accountSearch.entity().getType(), SearchCriteria.Op.EQ);
+        
+        
+            sb.join("accountSearch", accountSearch, sb.entity().getAccountId(), accountSearch.entity().getId(), JoinBuilder.JoinType.INNER);
+
+        List<NetworkVO> networksToReturn = new ArrayList<NetworkVO>();
+
+        if (isSystem == null || !isSystem) {
+            if (!permittedAccounts.isEmpty()) {
+                //get account level networks
+                networksToReturn.addAll(listAccountSpecificNetworks(
+                        buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, 
+                                physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags), searchFilter,
+                        permittedAccounts));
+                //get domain level networks
+                if (domainId != null) {
+                    networksToReturn
+                    .addAll(listDomainLevelNetworks(
+                            buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType,
+                                    physicalNetworkId, aclType, true, restartRequired, specifyIpRanges, vpcId, tags), searchFilter,
+                                    domainId, false));
+                }
+            } else {
+                //add account specific networks
+                networksToReturn.addAll(listAccountSpecificNetworksByDomainPath(
+                        buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, 
+                                physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags), searchFilter, path,
+                        isRecursive));
+                //add domain specific networks of domain + parent domains
+                networksToReturn.addAll(listDomainSpecificNetworksByDomainPath(
+                        buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, 
+                                physicalNetworkId, aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags), searchFilter, path,
+                                isRecursive));
+                //add networks of subdomains
+                if (domainId == null) {
+                    networksToReturn
+                    .addAll(listDomainLevelNetworks(
+                            buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType,
+                                    physicalNetworkId, aclType, true, restartRequired, specifyIpRanges, vpcId, tags), searchFilter,
+                                    caller.getDomainId(), true));
+                }
+            }
+        } else {
+            networksToReturn = _networksDao.search(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId,
+                    guestIpType, trafficType, physicalNetworkId, null, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags),
+                    searchFilter);
+        }
+
+        if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) {
+            List<NetworkVO> supportedNetworks = new ArrayList<NetworkVO>();
+            Service[] suppportedServices = new Service[supportedServicesStr.size()];
+            int i = 0;
+            for (String supportedServiceStr : supportedServicesStr) {
+                Service service = Service.getService(supportedServiceStr);
+                if (service == null) {
+                    throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
+                } else {
+                    suppportedServices[i] = service;
+                }
+                i++;
+            }
+
+            for (NetworkVO network : networksToReturn) {
+                if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) {
+                    supportedNetworks.add(network);
+                }
+            }
+
+            networksToReturn=supportedNetworks;
+        }
+        
+        if (canUseForDeploy != null) {
+            List<NetworkVO> networksForDeploy = new ArrayList<NetworkVO>();
+            for (NetworkVO network : networksToReturn) {
+                if (_networkMgr.canUseForDeploy(network) == canUseForDeploy) {
+                    networksForDeploy.add(network);
+                }
+            }
+            
+            networksToReturn=networksForDeploy;
+        }
+        
+            return networksToReturn;
+        }
+
+    
+
+    private SearchCriteria<NetworkVO> buildNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long id, 
+            Boolean isSystem, Long zoneId, String guestIpType, String trafficType, Long physicalNetworkId,
+            String aclType, boolean skipProjectNetworks, Boolean restartRequired, Boolean specifyIpRanges, Long vpcId, Map<String, String> tags) {
+
+        SearchCriteria<NetworkVO> sc = sb.create();
+
+        if (isSystem != null) {
+            sc.setJoinParameters("networkOfferingSearch", "systemOnly", isSystem);
+        }
+
+        if (keyword != null) {
+            SearchCriteria<NetworkVO> ssc = _networksDao.createSearchCriteria();
+            ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
+            sc.addAnd("name", SearchCriteria.Op.SC, ssc);
+        }
+
+        if (id != null) {
+            sc.addAnd("id", SearchCriteria.Op.EQ, id);
+        }
+
+        if (zoneId != null) {
+            sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
+        }
+
+        if (guestIpType != null) {
+            sc.addAnd("guestType", SearchCriteria.Op.EQ, guestIpType);
+        }
+
+        if (trafficType != null) {
+            sc.addAnd("trafficType", SearchCriteria.Op.EQ, trafficType);
+        }
+
+        if (aclType != null) {
+            sc.addAnd("aclType", SearchCriteria.Op.EQ, aclType.toString());
+        }
+
+        if (physicalNetworkId != null) {
+            sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, physicalNetworkId);
+        }
+
+        if (skipProjectNetworks) {
+            sc.setJoinParameters("accountSearch", "typeNEQ", Account.ACCOUNT_TYPE_PROJECT);
+        } else {
+            sc.setJoinParameters("accountSearch", "typeEQ", Account.ACCOUNT_TYPE_PROJECT);
+        }
+
+        if (restartRequired != null) {
+            sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
+        }
+
+        if (specifyIpRanges != null) {
+            sc.addAnd("specifyIpRanges", SearchCriteria.Op.EQ, specifyIpRanges);
+        }
+        
+        if (vpcId != null) {
+            sc.addAnd("vpcId", SearchCriteria.Op.EQ, vpcId);
+        }
+        
+        if (tags != null && !tags.isEmpty()) {
+            int count = 0;
+            sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.Network.toString());
+            for (String key : tags.keySet()) {
+                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
+                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
+                count++;
+            }
+        }
+
+        return sc;
+    }
+
+    private List<NetworkVO> listDomainLevelNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) {
+        List<Long> networkIds = new ArrayList<Long>();
+        Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
+        List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
+
+        for (NetworkDomainVO map : maps) {
+            if (map.getDomainId() == domainId && parentDomainsOnly) {
+                continue;
+            }
+            boolean subdomainAccess = (map.isSubdomainAccess() != null) ? map.isSubdomainAccess() : getAllowSubdomainAccessGlobal();
+            if (map.getDomainId() == domainId || subdomainAccess) {
+                networkIds.add(map.getNetworkId());
+            }
+        }
+
+        if (!networkIds.isEmpty()) {
+            SearchCriteria<NetworkVO> domainSC = _networksDao.createSearchCriteria();
+            domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
+            domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
+
+            sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
+            return _networksDao.search(sc, searchFilter);
+        } else {
+            return new ArrayList<NetworkVO>();
+        }
+    }
+
+    private List<NetworkVO> listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) {
+        SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria();
+        if (!permittedAccounts.isEmpty()) {
+            accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray());
+        }
+
+        accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
+
+        sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
+        return _networksDao.search(sc, searchFilter);
+    }
+
+    private List<NetworkVO> listAccountSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) {
+        SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria();
+        accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
+
+        if (path != null) {
+            if (isRecursive) {
+                sc.setJoinParameters("domainSearch", "path", path + "%");
+            } else {
+                sc.setJoinParameters("domainSearch", "path", path);
+            }
+        }
+
+        sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
+        return _networksDao.search(sc, searchFilter);
+    }
+
+    private List<NetworkVO> listDomainSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter,
+            String path, boolean isRecursive) {
+
+        Set<Long> allowedDomains = new HashSet<Long>();
+        if (path != null) {
+            if (isRecursive) {
+                allowedDomains = _domainMgr.getDomainChildrenIds(path);
+            } else {
+                Domain domain = _domainDao.findDomainByPath(path);
+                allowedDomains.add(domain.getId());
+            }
+        }
+
+        List<Long> networkIds = new ArrayList<Long>();
+        
+        List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
+
+        for (NetworkDomainVO map : maps) {
+            networkIds.add(map.getNetworkId());
+        }
+
+        if (!networkIds.isEmpty()) {
+            SearchCriteria<NetworkVO> domainSC = _networksDao.createSearchCriteria();
+            domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
+            domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
+
+            sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
+        return _networksDao.search(sc, searchFilter);
+        } else {
+            return new ArrayList<NetworkVO>();
+        }
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_DELETE, eventDescription = "deleting network", async = true)
+    public boolean deleteNetwork(long networkId) {
+
+        Account caller = UserContext.current().getCaller();
+
+        // Verify network id
+        NetworkVO network = _networksDao.findById(networkId);
+        if (network == null) {
+            // see NetworkVO.java
+            
+            InvalidParameterValueException ex = new InvalidParameterValueException("unable to find network with specified id");
+            ex.addProxyObject(network, networkId, "networkId");            
+            throw ex;
+        }
+
+        // don't allow to delete system network
+        if (isNetworkSystem(network)) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id is system and can't be removed");
+            ex.addProxyObject(network, network.getId(), "networkId");            
+            throw ex;
+        }
+
+        Account owner = _accountMgr.getAccount(network.getAccountId());
+
+        // Perform permission check
+        _accountMgr.checkAccess(caller, null, true, network);
+
+        User callerUser = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
+        ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner);
+
+        return _networkMgr.destroyNetwork(networkId, context);
+    }
+
+    
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
+    public boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        // This method restarts all network elements belonging to the network and re-applies all the rules
+        Long networkId = cmd.getNetworkId();
+
+        User callerUser = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
+        Account callerAccount = _accountMgr.getActiveAccountById(callerUser.getAccountId());
+
+        // Check if network exists
+        NetworkVO network = _networksDao.findById(networkId);
+        if (network == null) {            
+            InvalidParameterValueException ex = new InvalidParameterValueException("Network with specified id doesn't exist");
+            ex.addProxyObject("networks", networkId, "networkId");
+            throw ex;
+        }
+
+        // Don't allow to restart network if it's not in Implemented/Setup state
+        if (!(network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) {
+            throw new InvalidParameterValueException("Network is not in the right state to be restarted. Correct states are: " + Network.State.Implemented + ", " + Network.State.Setup);
+        }
+        
+        if (network.getBroadcastDomainType() == BroadcastDomainType.Lswitch ) {
+        	/** 
+        	 * Unable to restart these networks now.
+        	 * TODO Restarting a SDN based network requires updating the nics and the configuration
+        	 * in the controller. This requires a non-trivial rewrite of the restart procedure.
+        	 */
+        	throw new InvalidParameterException("Unable to restart a running SDN network.");
+        }
+
+        _accountMgr.checkAccess(callerAccount, null, true, network);
+
+        boolean success = _networkMgr.restartNetwork(networkId, callerAccount, callerUser, cleanup);
+
+        if (success) {
+            s_logger.debug("Network id=" + networkId + " is restarted successfully.");
+        } else {
+            s_logger.warn("Network id=" + networkId + " failed to restart.");
+        }
+
+        return success;
+    }
+
+    @Override
+    public int getActiveNicsInNetwork(long networkId) {
+        return _networksDao.getActiveNicsIn(networkId);
+    }
+
+    
+
+   
+
+    //@Override
+    protected Map<Capability, String> getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) {
+
+        if (!areServicesSupportedByNetworkOffering(offering.getId(), service)) {
+            // TBD: We should be sending networkOfferingId and not the offering object itself.  
+            throw new UnsupportedServiceException("Service " + service.getName() + " is not supported by the network offering " + offering);
+        }
+
+        Map<Capability, String> serviceCapabilities = new HashMap<Capability, String>();
+
+        // get the Provider for this Service for this offering
+        List<String> providers = _ntwkOfferingSrvcDao.listProvidersForServiceForNetworkOffering(offering.getId(), service);
+        if (providers.isEmpty()) {
+            // TBD: We should be sending networkOfferingId and not the offering object itself.
+            throw new InvalidParameterValueException("Service " + service.getName() + " is not supported by the network offering " + offering);
+        }
+
+        // FIXME - in post 3.0 we are going to support multiple providers for the same service per network offering, so
+        // we have to calculate capabilities for all of them
+        String provider = providers.get(0);
+
+        // FIXME we return the capabilities of the first provider of the service - what if we have multiple providers
+        // for same Service?
+        NetworkElement element = _networkMgr.getElementImplementingProvider(provider);
+        if (element != null) {
+            Map<Service, Map<Capability, String>> elementCapabilities = element.getCapabilities();
+            ;
+
+            if (elementCapabilities == null || !elementCapabilities.containsKey(service)) {
+                // TBD: We should be sending providerId and not the offering object itself.
+                throw new UnsupportedServiceException("Service " + service.getName() + " is not supported by the element=" + element.getName() + " implementing Provider=" + provider);
+            }
+            serviceCapabilities = elementCapabilities.get(service);
+        }
+
+        return serviceCapabilities;
+    }
+    
+    
+    @Override
+    public IpAddress getIp(long ipAddressId) {
+        return _ipAddressDao.findById(ipAddressId);
+    }
+
+    
+    protected boolean providersConfiguredForExternalNetworking(Collection<String> providers) {
+        for(String providerStr : providers){
+            Provider provider = Network.Provider.getProvider(providerStr);
+            if(provider.isExternal()){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected boolean isSharedNetworkOfferingWithServices(long networkOfferingId) {
+        NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
+        if ( (networkOffering.getGuestType()  == Network.GuestType.Shared) && (
+                areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat) ||
+                areServicesSupportedByNetworkOffering(networkOfferingId, Service.StaticNat) ||
+                areServicesSupportedByNetworkOffering(networkOfferingId, Service.Firewall) ||
+                areServicesSupportedByNetworkOffering(networkOfferingId, Service.PortForwarding) ||
+                areServicesSupportedByNetworkOffering(networkOfferingId, Service.Lb))) {
+            return true;
+        }
+        return false;
+    }
+
+    //@Override
+    protected boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service... services) {
+        return (_ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(networkOfferingId, services));
+    }
+
+    //@Override
+    protected boolean areServicesSupportedInNetwork(long networkId, Service... services) {
+        return (_ntwkSrvcDao.areServicesSupportedInNetwork(networkId, services));
+    }
+
+ 
+        
+   
+
+    @Override
+    public boolean isNetworkAvailableInDomain(long networkId, long domainId) {
+        Long networkDomainId = null;
+        Network network = getNetwork(networkId);
+        if (network.getGuestType() != Network.GuestType.Shared) {
+            s_logger.trace("Network id=" + networkId + " is not shared");
+            return false;
+        }
+
+        NetworkDomainVO networkDomainMap = _networkDomainDao.getDomainNetworkMapByNetworkId(networkId);
+        if (networkDomainMap == null) {
+            s_logger.trace("Network id=" + networkId + " is shared, but not domain specific");
+            return true;
+        } else {
+            networkDomainId = networkDomainMap.getDomainId();
+        }
+
+        if (domainId == networkDomainId.longValue()) {
+            return true;
+        }
+
+        if (networkDomainMap.subdomainAccess) {
+            Set<Long> parentDomains = _domainMgr.getDomainParentIds(domainId);
+
+            if (parentDomains.contains(domainId)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+  
+
+    private boolean checkForNonStoppedVmInNetwork(long networkId) {
+        List<UserVmVO> vms = _userVmDao.listByNetworkIdAndStates(networkId, VirtualMachine.State.Starting, 
+                VirtualMachine.State.Running, VirtualMachine.State.Migrating, VirtualMachine.State.Stopping);
+        return vms.isEmpty();
+    }
+    
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_UPDATE, eventDescription = "updating network", async = true)
+    public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, 
+            User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr) {
+        boolean restartNetwork = false;
+
+        // verify input parameters
+        NetworkVO network = _networksDao.findById(networkId);
+        if (network == null) {
+            // see NetworkVO.java
+            InvalidParameterValueException ex = new InvalidParameterValueException("Specified network id doesn't exist in the system");
+            ex.addProxyObject("networks", networkId, "networkId");
+            throw ex;
+        }
+
+        // don't allow to update network in Destroy state
+        if (network.getState() == Network.State.Destroy) {
+            throw new InvalidParameterValueException("Don't allow to update network in state " + Network.State.Destroy);
+        }
+
+        // Don't allow to update system network
+        NetworkOffering offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
+        if (offering.isSystemOnly()) {
+            throw new InvalidParameterValueException("Can't update system networks");
+        }
+
+        // allow to upgrade only Guest networks
+        if (network.getTrafficType() != Networks.TrafficType.Guest) {
+            throw new InvalidParameterValueException("Can't allow networks which traffic type is not " + TrafficType.Guest);
+        }
+        
+        _accountMgr.checkAccess(callerAccount, null, true, network);
+
+        if (name != null) {
+            network.setName(name);
+        }
+
+        if (displayText != null) {
+            network.setDisplayText(displayText);
+        }
+
+        // network offering and domain suffix can be updated for Isolated networks only in 3.0
+        if ((networkOfferingId != null || domainSuffix != null) && network.getGuestType() != GuestType.Isolated) {
+            throw new InvalidParameterValueException("NetworkOffering and domain suffix upgrade can be perfomed for Isolated networks only");
+        }
+
+        boolean networkOfferingChanged = false;
+
+        long oldNetworkOfferingId = network.getNetworkOfferingId();
+        if (networkOfferingId != null) {
+
+            NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
+            if (networkOffering == null || networkOffering.isSystemOnly()) {
+                InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering with specified id");
+                ex.addProxyObject(networkOffering, networkOfferingId, "networkOfferingId");                
+                throw ex;
+            }
+            
+            // network offering should be in Enabled state
+            if (networkOffering.getState() != NetworkOffering.State.Enabled) {
+                InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id is not in " + NetworkOffering.State.Enabled + " state, can't upgrade to it");
+                ex.addProxyObject(networkOffering, networkOfferingId, "networkOfferingId");                
+                throw ex;
+            }
+            
+            
+            //can't update from vpc to non-vpc network offering
+            boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering);
+            boolean vorVpcOriginal = _configMgr.isOfferingForVpc(_configMgr.getNetworkOffering(oldNetworkOfferingId));
+            if (forVpcNew != vorVpcOriginal) {
+                String errMsg = forVpcNew ? "a vpc offering " : "not a vpc offering";
+                throw new InvalidParameterValueException("Can't update as the new offering is " + errMsg);
+            }
+
+            if (networkOfferingId != oldNetworkOfferingId) {
+                NetworkOffering oldNtwkOff = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+                Collection<String> newProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(networkOffering, network.getPhysicalNetworkId()).values();
+                Collection<String> oldProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(oldNtwkOff, network.getPhysicalNetworkId()).values();
+                
+                if (providersConfiguredForExternalNetworking(newProviders) != providersConfiguredForExternalNetworking(oldProviders)
+                        && !changeCidr) {
+                    throw new InvalidParameterValueException("Updating network failed since guest CIDR needs to be changed!");
+                }
+                if (changeCidr) {
+                    if (!checkForNonStoppedVmInNetwork(network.getId())) {
+                        InvalidParameterValueException ex = new InvalidParameterValueException("All user vm of network of specified id should be stopped before changing CIDR!");
+                        ex.addProxyObject(network, networkId, "networkId");                       
+                        throw ex;
+                    }
+                }
+                // check if the network is upgradable
+                if (!canUpgrade(network, oldNetworkOfferingId, networkOfferingId)) {
+                    throw new InvalidParameterValueException("Can't upgrade from network offering " + oldNetworkOfferingId + " to " + networkOfferingId + "; check logs for more information");
+                }
+                restartNetwork = true;
+                networkOfferingChanged = true;
+            }
+        }
+        Map<String, String> newSvcProviders = new HashMap<String, String>();
+        if (networkOfferingChanged) {
+            newSvcProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(_configMgr.getNetworkOffering(networkOfferingId), network.getPhysicalNetworkId());
+        }
+
+        // don't allow to modify network domain if the service is not supported
+        if (domainSuffix != null) {
+            // validate network domain
+            if (!NetUtils.verifyDomainName(domainSuffix)) {
+                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 \"-\"");
+            }
+
+            long offeringId = oldNetworkOfferingId;
+            if (networkOfferingId != null) {
+                offeringId = networkOfferingId;
+            }
+
+            Map<Network.Capability, String> dnsCapabilities = getNetworkOfferingServiceCapabilities(_configMgr.getNetworkOffering(offeringId), Service.Dns);
+            String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification);
+            if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) {
+                // TBD: use uuid instead of networkOfferingId. May need to hardcode tablename in call to addProxyObject().
+                throw new InvalidParameterValueException("Domain name change is not supported by the network offering id=" + networkOfferingId);
+            }
+
+            network.setNetworkDomain(domainSuffix);
+            // have to restart the network
+            restartNetwork = true;
+        }
+
+        ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount);
+        // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate
+        // states - Shutdown and Implementing
+        boolean validStateToShutdown = (network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup || network.getState() == Network.State.Allocated);
+        if (restartNetwork) {
+            if (validStateToShutdown) {
+                if (!changeCidr) {
+                    s_logger.debug("Shutting down elements and resources for network id=" + networkId + " as a part of network update");
+
+                    if (!_networkMgr.shutdownNetworkElementsAndResources(context, true, network)) {
+                        s_logger.warn("Failed to shutdown the network elements and resources as a part of network restart: " + network);
+                        CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network elements and resources as a part of update to network of specified id");
+                        ex.addProxyObject(network, networkId, "networkId");                       
+                        throw ex;
+                    }
+                } else {
+                    // We need to shutdown the network, since we want to re-implement the network.
+                    s_logger.debug("Shutting down network id=" + networkId + " as a part of network update");
+
+                    if (!_networkMgr.shutdownNetwork(network.getId(), context, true)) {
+                        s_logger.warn("Failed to shutdown the network as a part of update to network with specified id");
+                        CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network as a part of update of specified network id");
+                        ex.addProxyObject(network, networkId, "networkId");                        
+                        throw ex;
+                    }
+                }
+            } else {
+                CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network elements and resources as a part of update to network with specified id; network is in wrong state: " + network.getState());
+                ex.addProxyObject(network, networkId, "networkId");                
+                throw ex;
+            }
+        }
+
+        // 2) Only after all the elements and rules are shutdown properly, update the network VO
+        // get updated network
+        Network.State networkState = _networksDao.findById(networkId).getState();
+        boolean validStateToImplement = (networkState == Network.State.Implemented || networkState == Network.State.Setup || networkState == Network.State.Allocated);
+        if (restartNetwork && !validStateToImplement) {
+            CloudRuntimeException ex = new CloudRuntimeException("Failed to implement the network elements and resources as a part of update to network with specified id; network is in wrong state: " + networkState);
+            ex.addProxyObject(network, networkId, "networkId");            
+            throw ex;
+        }
+
+        if (networkOfferingId != null) {
+            if (networkOfferingChanged) {
+                Transaction txn = Transaction.currentTxn();
+                txn.start();
+                network.setNetworkOfferingId(networkOfferingId);
+                _networksDao.update(networkId, network, newSvcProviders);
+                // get all nics using this network
+                // log remove usage events for old offering
+                // log assign usage events for new offering
+                List<NicVO> nics = _nicDao.listByNetworkId(networkId);
+                for (NicVO nic : nics) {
+                    long vmId = nic.getInstanceId();
+                    VMInstanceVO vm = _vmDao.findById(vmId);
+                    if (vm == null) {
+                        s_logger.error("Vm for nic " + nic.getId() + " not found with Vm Id:" + vmId);
+                        continue;
+                    }
+                    long isDefault = (nic.isDefaultNic()) ? 1 : 0;
+                    UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), null, oldNetworkOfferingId, null, 0L);
+                    _usageEventDao.persist(usageEvent);
+                    usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterIdToDeployIn(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault);
+                    _usageEventDao.persist(usageEvent);
+                }
+                txn.commit();
+            } else {
+                network.setNetworkOfferingId(networkOfferingId);
+                _networksDao.update(networkId, network, _networkMgr.finalizeServicesAndProvidersForNetwork(_configMgr.getNetworkOffering(networkOfferingId), network.getPhysicalNetworkId()));
+            }
+        } else {
+            _networksDao.update(networkId, network);
+        }
+
+        // 3) Implement the elements and rules again
+        if (restartNetwork) {
+            if (network.getState() != Network.State.Allocated) {
+                DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null);
+                s_logger.debug("Implementing the network " + network + " elements and resources as a part of network update");
+                try {
+                    if (!changeCidr) {
+                        _networkMgr.implementNetworkElementsAndResources(dest, context, network, _networkOfferingDao.findById(network.getNetworkOfferingId()));
+                    } else {
+                        _networkMgr.implementNetwork(network.getId(), dest, context);
+                    }
+                } catch (Exception ex) {
+                    s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network update due to ", ex);
+                    CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of network update");
+                    e.addProxyObject(network, networkId, "networkId");                    
+                    throw e;
+                }
+            }
+        }
+
+        return getNetwork(network.getId());
+    }
+
+
+    
+
+    protected Set<Long> getAvailableIps(Network network, String requestedIp) {
+        String[] cidr = network.getCidr().split("/");
+        List<String> ips = _nicDao.listIpAddressInNetwork(network.getId());
+        Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]));
+        Set<Long> usedIps = new TreeSet<Long>(); 
+        
+        for (String ip : ips) {
+            if (requestedIp != null && requestedIp.equals(ip)) {
+                s_logger.warn("Requested ip address " + requestedIp + " is already in use in network" + network);
+                return null;
+            }
+
+            usedIps.add(NetUtils.ip2Long(ip));
+        }
+        if (usedIps.size() != 0) {
+            allPossibleIps.removeAll(usedIps);
+        }
+        return allPossibleIps;
+    }
+
+
+  
+    protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long newNetworkOfferingId) {
+        NetworkOffering oldNetworkOffering = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
+        NetworkOffering newNetworkOffering = _networkOfferingDao.findById(newNetworkOfferingId);
+
+        // can upgrade only Isolated networks
+        if (oldNetworkOffering.getGuestType() != GuestType.Isolated) {
+            throw new InvalidParameterValueException("NetworkOfferingId can be upgraded only for the network of type " + GuestType.Isolated);
+        }
+
+        // security group service should be the same
+        if (areServicesSupportedByNetworkOffering(oldNetworkOfferingId, Service.SecurityGroup) != areServicesSupportedByNetworkOffering(newNetworkOfferingId, Service.SecurityGroup)) {
+            s_logger.debug("Offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different securityGroupProperty, can't upgrade");
+            return false;
+        }
+
+        // Type of the network should be the same
+        if (oldNetworkOffering.getGuestType() != newNetworkOffering.getGuestType()) {
+            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " are of different types, can't upgrade");
+            return false;
+        }
+
+        // tags should be the same
+        if (newNetworkOffering.getTags() != null) {
+            if (oldNetworkOffering.getTags() == null) {
+                s_logger.debug("New network offering id=" + newNetworkOfferingId + " has tags and old network offering id=" + oldNetworkOfferingId + " doesn't, can't upgrade");
+                return false;
+            }
+            if (!oldNetworkOffering.getTags().equalsIgnoreCase(newNetworkOffering.getTags())) {
+                s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different tags, can't upgrade");
+                return false;
+            }
+        }
+
+        // Traffic types should be the same
+        if (oldNetworkOffering.getTrafficType() != newNetworkOffering.getTrafficType()) {
+            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different traffic types, can't upgrade");
+            return false;
+        }
+
+        // specify vlan should be the same
+        if (oldNetworkOffering.getSpecifyVlan() != newNetworkOffering.getSpecifyVlan()) {
+            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different values for specifyVlan, can't upgrade");
+            return false;
+        }
+
+        // specify ipRanges should be the same
+        if (oldNetworkOffering.getSpecifyIpRanges() != newNetworkOffering.getSpecifyIpRanges()) {
+            s_logger.debug("Network offerings " + newNetworkOfferingId + " and " + oldNetworkOfferingId + " have different values for specifyIpRangess, can't upgrade");
+            return false;
+        }
+
+        // Check all ips
+        List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
+        List<PublicIp> publicIps = new ArrayList<PublicIp>();
+        if (userIps != null && !userIps.isEmpty()) {
+            for (IPAddressVO userIp : userIps) {
+                PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress()));
+                publicIps.add(publicIp);
+            }
+        }
+        if (oldNetworkOffering.isConserveMode() && !newNetworkOffering.isConserveMode()) {
+            if (!canIpsUsedForNonConserve(publicIps)) {
+                return false;
+            }
+        }
+
+        return canIpsUseOffering(publicIps, newNetworkOfferingId);
+    }
+
+    
+
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_PHYSICAL_NETWORK_CREATE, eventDescription = "Creating Physical Network", create = true)
+    public PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List<String> 
+    isolationMethods, String broadcastDoma

<TRUNCATED>