| // 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.net.URI; | |
| import java.util.ArrayList; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import javax.inject.Inject; | |
| import javax.naming.ConfigurationException; | |
| import org.apache.cloudstack.api.ApiConstants; | |
| import org.apache.cloudstack.api.response.ExternalFirewallResponse; | |
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | |
| import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; | |
| import com.cloud.agent.AgentManager; | |
| import com.cloud.agent.api.Answer; | |
| import com.cloud.agent.api.StartupCommand; | |
| import com.cloud.agent.api.StartupExternalFirewallCommand; | |
| import com.cloud.agent.api.routing.IpAssocCommand; | |
| import com.cloud.agent.api.routing.NetworkElementCommand; | |
| import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; | |
| import com.cloud.agent.api.routing.SetFirewallRulesCommand; | |
| import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; | |
| import com.cloud.agent.api.routing.SetStaticNatRulesCommand; | |
| import com.cloud.agent.api.routing.VpnUsersCfgCommand; | |
| import com.cloud.agent.api.to.FirewallRuleTO; | |
| import com.cloud.agent.api.to.IpAddressTO; | |
| import com.cloud.agent.api.to.PortForwardingRuleTO; | |
| import com.cloud.agent.api.to.StaticNatRuleTO; | |
| import com.cloud.configuration.Config; | |
| import com.cloud.dc.DataCenter; | |
| import com.cloud.dc.DataCenterVO; | |
| import com.cloud.dc.Vlan; | |
| import com.cloud.dc.VlanVO; | |
| import com.cloud.dc.dao.DataCenterDao; | |
| import com.cloud.dc.dao.VlanDao; | |
| import com.cloud.exception.InsufficientCapacityException; | |
| import com.cloud.exception.InsufficientNetworkCapacityException; | |
| import com.cloud.exception.InvalidParameterValueException; | |
| import com.cloud.exception.ResourceUnavailableException; | |
| import com.cloud.host.DetailVO; | |
| import com.cloud.host.Host; | |
| import com.cloud.host.HostVO; | |
| import com.cloud.host.dao.HostDao; | |
| import com.cloud.host.dao.HostDetailsDao; | |
| import com.cloud.network.Networks.BroadcastDomainType; | |
| import com.cloud.network.Networks.TrafficType; | |
| import com.cloud.network.dao.ExternalFirewallDeviceDao; | |
| import com.cloud.network.dao.ExternalFirewallDeviceVO; | |
| import com.cloud.network.dao.FirewallRulesDao; | |
| import com.cloud.network.dao.IPAddressDao; | |
| import com.cloud.network.dao.IPAddressVO; | |
| import com.cloud.network.dao.InlineLoadBalancerNicMapDao; | |
| import com.cloud.network.dao.InlineLoadBalancerNicMapVO; | |
| import com.cloud.network.dao.LoadBalancerDao; | |
| import com.cloud.network.dao.NetworkDao; | |
| import com.cloud.network.dao.NetworkExternalFirewallDao; | |
| import com.cloud.network.dao.NetworkExternalFirewallVO; | |
| import com.cloud.network.dao.NetworkServiceMapDao; | |
| import com.cloud.network.dao.NetworkVO; | |
| import com.cloud.network.dao.PhysicalNetworkDao; | |
| import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; | |
| import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; | |
| import com.cloud.network.dao.PhysicalNetworkVO; | |
| import com.cloud.network.dao.VpnUserDao; | |
| import com.cloud.network.rules.FirewallRule; | |
| import com.cloud.network.rules.FirewallRule.Purpose; | |
| import com.cloud.network.rules.FirewallRuleVO; | |
| import com.cloud.network.rules.PortForwardingRule; | |
| import com.cloud.network.rules.StaticNat; | |
| import com.cloud.network.rules.dao.PortForwardingRulesDao; | |
| import com.cloud.offering.NetworkOffering; | |
| import com.cloud.offerings.NetworkOfferingVO; | |
| import com.cloud.offerings.dao.NetworkOfferingDao; | |
| import com.cloud.resource.ResourceManager; | |
| import com.cloud.resource.ResourceState; | |
| import com.cloud.resource.ResourceStateAdapter; | |
| import com.cloud.resource.ServerResource; | |
| import com.cloud.resource.UnableDeleteHostException; | |
| import com.cloud.user.Account; | |
| import com.cloud.user.AccountManager; | |
| import com.cloud.user.dao.AccountDao; | |
| import com.cloud.user.dao.UserStatisticsDao; | |
| import com.cloud.utils.NumbersUtil; | |
| import com.cloud.utils.Pair; | |
| import com.cloud.utils.component.AdapterBase; | |
| import com.cloud.utils.db.DB; | |
| import com.cloud.utils.db.GlobalLock; | |
| import com.cloud.utils.db.Transaction; | |
| import com.cloud.utils.db.TransactionCallback; | |
| import com.cloud.utils.db.TransactionStatus; | |
| import com.cloud.utils.exception.CloudRuntimeException; | |
| import com.cloud.utils.net.NetUtils; | |
| import com.cloud.utils.net.UrlUtil; | |
| import com.cloud.vm.Nic.ReservationStrategy; | |
| import com.cloud.vm.NicVO; | |
| import com.cloud.vm.dao.DomainRouterDao; | |
| import com.cloud.vm.dao.NicDao; | |
| public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase implements ExternalFirewallDeviceManager, ResourceStateAdapter { | |
| @Inject | |
| HostDao _hostDao; | |
| @Inject | |
| NetworkServiceMapDao _ntwkSrvcProviderDao; | |
| @Inject | |
| DataCenterDao _dcDao; | |
| @Inject | |
| NetworkModel _networkModel; | |
| @Inject | |
| NetworkOrchestrationService _networkMgr; | |
| @Inject | |
| InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; | |
| @Inject | |
| NicDao _nicDao; | |
| @Inject | |
| AgentManager _agentMgr; | |
| @Inject | |
| ResourceManager _resourceMgr; | |
| @Inject | |
| IPAddressDao _ipAddressDao; | |
| @Inject | |
| VlanDao _vlanDao; | |
| @Inject | |
| NetworkOfferingDao _networkOfferingDao; | |
| @Inject | |
| AccountDao _accountDao; | |
| @Inject | |
| PhysicalNetworkDao _physicalNetworkDao; | |
| @Inject | |
| PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; | |
| @Inject | |
| AccountManager _accountMgr; | |
| @Inject | |
| UserStatisticsDao _userStatsDao; | |
| @Inject | |
| NetworkDao _networkDao; | |
| @Inject | |
| DomainRouterDao _routerDao; | |
| @Inject | |
| LoadBalancerDao _loadBalancerDao; | |
| @Inject | |
| PortForwardingRulesDao _portForwardingRulesDao; | |
| @Inject | |
| ConfigurationDao _configDao; | |
| @Inject | |
| ExternalFirewallDeviceDao _externalFirewallDeviceDao; | |
| @Inject | |
| NetworkExternalFirewallDao _networkExternalFirewallDao; | |
| @Inject | |
| VpnUserDao _vpnUsersDao; | |
| @Inject | |
| HostDetailsDao _hostDetailDao; | |
| @Inject | |
| FirewallRulesDao _fwRulesDao; | |
| private long _defaultFwCapacity; | |
| @Override | |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { | |
| super.configure(name, params); | |
| _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); | |
| _defaultFwCapacity = NumbersUtil.parseLong(_configDao.getValue(Config.DefaultExternalFirewallCapacity.key()), 50); | |
| return true; | |
| } | |
| @Override | |
| @DB | |
| public ExternalFirewallDeviceVO addExternalFirewall(long physicalNetworkId, String url, String username, String password, final String deviceName, | |
| ServerResource resource) { | |
| String guid; | |
| PhysicalNetworkVO pNetwork = null; | |
| NetworkDevice ntwkDevice = NetworkDevice.getNetworkDevice(deviceName); | |
| long zoneId; | |
| if ((ntwkDevice == null) || (url == null) || (username == null) || (resource == null) || (password == null)) { | |
| throw new InvalidParameterValueException("Atleast one of the required parameters (url, username, password," | |
| + " server resource, zone id/physical network id) is not specified or a valid parameter."); | |
| } | |
| pNetwork = _physicalNetworkDao.findById(physicalNetworkId); | |
| if (pNetwork == null) { | |
| throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); | |
| } | |
| zoneId = pNetwork.getDataCenterId(); | |
| final PhysicalNetworkServiceProviderVO ntwkSvcProvider = | |
| _physicalNetworkServiceProviderDao.findByServiceProvider(pNetwork.getId(), ntwkDevice.getNetworkServiceProvder()); | |
| if (ntwkSvcProvider == null) { | |
| throw new CloudRuntimeException(String.format("Network Service Provider: %s is not enabled in the physical network: %s to add this device", ntwkDevice.getNetworkServiceProvder(), pNetwork)); | |
| } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) { | |
| throw new CloudRuntimeException(String.format("Network Service Provider: %s is not added or in shutdown state in the physical network: %s to add this device", ntwkSvcProvider.getProviderName(), pNetwork)); | |
| } | |
| URI uri; | |
| try { | |
| uri = new URI(url); | |
| } catch (Exception e) { | |
| logger.debug(e); | |
| throw new InvalidParameterValueException(e.getMessage()); | |
| } | |
| String ipAddress = uri.getHost(); | |
| Map hostDetails = new HashMap<String, String>(); | |
| guid = getExternalNetworkResourceGuid(pNetwork.getId(), deviceName, ipAddress); | |
| hostDetails.put("name", guid); | |
| hostDetails.put("guid", guid); | |
| hostDetails.put("zoneId", String.valueOf(pNetwork.getDataCenterId())); | |
| hostDetails.put("ip", ipAddress); | |
| hostDetails.put("physicalNetworkId", String.valueOf(pNetwork.getId())); | |
| hostDetails.put("username", username); | |
| hostDetails.put("password", password); | |
| hostDetails.put("deviceName", deviceName); | |
| final Map<String, String> configParams = new HashMap<String, String>(); | |
| UrlUtil.parseQueryParameters(uri.getQuery(), false, configParams); | |
| hostDetails.putAll(configParams); | |
| // let the server resource to do parameters validation | |
| try { | |
| resource.configure(guid, hostDetails); | |
| } catch (ConfigurationException e) { | |
| throw new CloudRuntimeException(e.getMessage()); | |
| } | |
| final Host externalFirewall = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails); | |
| if (externalFirewall != null) { | |
| final PhysicalNetworkVO pNetworkFinal = pNetwork; | |
| return Transaction.execute(new TransactionCallback<ExternalFirewallDeviceVO>() { | |
| @Override | |
| public ExternalFirewallDeviceVO doInTransaction(TransactionStatus status) { | |
| boolean dedicatedUse = | |
| (configParams.get(ApiConstants.FIREWALL_DEVICE_DEDICATED) != null) ? Boolean.parseBoolean(configParams.get(ApiConstants.FIREWALL_DEVICE_DEDICATED)) | |
| : false; | |
| long capacity = NumbersUtil.parseLong(configParams.get(ApiConstants.FIREWALL_DEVICE_CAPACITY), 0); | |
| if (capacity == 0) { | |
| capacity = _defaultFwCapacity; | |
| } | |
| ExternalFirewallDeviceVO fwDevice = | |
| new ExternalFirewallDeviceVO(externalFirewall.getId(), pNetworkFinal.getId(), ntwkSvcProvider.getProviderName(), deviceName, capacity, | |
| dedicatedUse); | |
| _externalFirewallDeviceDao.persist(fwDevice); | |
| DetailVO hostDetail = new DetailVO(externalFirewall.getId(), ApiConstants.FIREWALL_DEVICE_ID, String.valueOf(fwDevice.getId())); | |
| _hostDetailDao.persist(hostDetail); | |
| return fwDevice; | |
| } | |
| }); | |
| } else { | |
| return null; | |
| } | |
| } | |
| @Override | |
| public boolean deleteExternalFirewall(Long hostId) { | |
| HostVO externalFirewall = _hostDao.findById(hostId); | |
| if (externalFirewall == null) { | |
| throw new InvalidParameterValueException("Could not find an external firewall with ID: " + hostId); | |
| } | |
| DetailVO fwHostDetails = _hostDetailDao.findDetail(hostId, ApiConstants.FIREWALL_DEVICE_ID); | |
| long fwDeviceId = Long.parseLong(fwHostDetails.getValue()); | |
| // check if any networks are using this balancer device | |
| List<NetworkExternalFirewallVO> networks = _networkExternalFirewallDao.listByFirewallDeviceId(fwDeviceId); | |
| if ((networks != null) && !networks.isEmpty()) { | |
| throw new CloudRuntimeException("Delete can not be done as there are networks using the firewall device "); | |
| } | |
| try { | |
| // put the host in maintenance state in order for it to be deleted | |
| externalFirewall.setResourceState(ResourceState.Maintenance); | |
| _hostDao.update(hostId, externalFirewall); | |
| _resourceMgr.deleteHost(hostId, false, false); | |
| // delete the external load balancer entry | |
| _externalFirewallDeviceDao.remove(fwDeviceId); | |
| return true; | |
| } catch (Exception e) { | |
| logger.debug("Failed to delete external firewall device due to " + e.getMessage()); | |
| return false; | |
| } | |
| } | |
| @Override | |
| public List<Host> listExternalFirewalls(long physicalNetworkId, String deviceName) { | |
| List<Host> firewallHosts = new ArrayList<Host>(); | |
| NetworkDevice fwNetworkDevice = NetworkDevice.getNetworkDevice(deviceName); | |
| PhysicalNetworkVO pNetwork = null; | |
| pNetwork = _physicalNetworkDao.findById(physicalNetworkId); | |
| if (pNetwork == null) { | |
| throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); | |
| } | |
| if ((pNetwork == null) || (fwNetworkDevice == null)) { | |
| throw new InvalidParameterValueException("Atleast one of ther required parameter physical networkId, device name is missing or invalid."); | |
| } | |
| PhysicalNetworkServiceProviderVO ntwkSvcProvider = | |
| _physicalNetworkServiceProviderDao.findByServiceProvider(pNetwork.getId(), fwNetworkDevice.getNetworkServiceProvder()); | |
| if (ntwkSvcProvider == null) { | |
| return null; | |
| } | |
| List<ExternalFirewallDeviceVO> fwDevices = _externalFirewallDeviceDao.listByPhysicalNetworkAndProvider(physicalNetworkId, ntwkSvcProvider.getProviderName()); | |
| for (ExternalFirewallDeviceVO fwDevice : fwDevices) { | |
| firewallHosts.add(_hostDao.findById(fwDevice.getHostId())); | |
| } | |
| return firewallHosts; | |
| } | |
| @Override | |
| public ExternalFirewallDeviceVO getExternalFirewallForNetwork(Network network) { | |
| NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId()); | |
| if (fwDeviceForNetwork != null) { | |
| long fwDeviceId = fwDeviceForNetwork.getExternalFirewallDeviceId(); | |
| ExternalFirewallDeviceVO fwDevice = _externalFirewallDeviceDao.findById(fwDeviceId); | |
| assert (fwDevice != null); | |
| return fwDevice; | |
| } | |
| return null; | |
| } | |
| public void setExternalFirewallForNetwork(Network network, long externalFWDeviceID) { | |
| NetworkExternalFirewallVO fwDeviceForNetwork = new NetworkExternalFirewallVO(network.getId(), externalFWDeviceID); | |
| _networkExternalFirewallDao.persist(fwDeviceForNetwork); | |
| } | |
| @Override | |
| public ExternalFirewallDeviceVO findSuitableFirewallForNetwork(Network network) throws InsufficientCapacityException { | |
| long physicalNetworkId = network.getPhysicalNetworkId(); | |
| List<ExternalFirewallDeviceVO> fwDevices = _externalFirewallDeviceDao.listByPhysicalNetwork(physicalNetworkId); | |
| // loop through the firewall device in the physical network and pick the first-fit | |
| for (ExternalFirewallDeviceVO fwDevice : fwDevices) { | |
| // max number of guest networks that can be mapped to this device | |
| long fullCapacity = fwDevice.getCapacity(); | |
| if (fullCapacity == 0) { | |
| fullCapacity = _defaultFwCapacity; // if capacity not configured then use the default | |
| } | |
| // get the list of guest networks that are mapped to this load balancer | |
| List<NetworkExternalFirewallVO> mappedNetworks = _networkExternalFirewallDao.listByFirewallDeviceId(fwDevice.getId()); | |
| long usedCapacity = (mappedNetworks == null) ? 0 : mappedNetworks.size(); | |
| if ((fullCapacity - usedCapacity) > 0) { | |
| return fwDevice; | |
| } | |
| } | |
| throw new InsufficientNetworkCapacityException("Unable to find a firewall provider with sufficient capcity " + " to implement the network", DataCenter.class, | |
| network.getDataCenterId()); | |
| } | |
| @DB | |
| protected boolean freeFirewallForNetwork(Network network) { | |
| GlobalLock deviceMapLock = GlobalLock.getInternLock("NetworkFirewallDeviceMap"); | |
| try { | |
| if (deviceMapLock.lock(120)) { | |
| try { | |
| NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId()); | |
| if (fwDeviceForNetwork != null) { | |
| _networkExternalFirewallDao.remove(fwDeviceForNetwork.getId()); | |
| } | |
| } catch (Exception exception) { | |
| logger.error("Failed to release firewall device for the network {} due to {}", network, exception.getMessage()); | |
| return false; | |
| } finally { | |
| deviceMapLock.unlock(); | |
| } | |
| } | |
| } finally { | |
| deviceMapLock.releaseRef(); | |
| } | |
| return true; | |
| } | |
| public String getExternalNetworkResourceGuid(long physicalNetworkId, String deviceName, String ip) { | |
| return physicalNetworkId + "-" + deviceName + "-" + ip; | |
| } | |
| public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall) { | |
| Map<String, String> fwDetails = _hostDetailDao.findDetails(externalFirewall.getId()); | |
| ExternalFirewallResponse response = new ExternalFirewallResponse(); | |
| response.setId(externalFirewall.getUuid()); | |
| response.setIpAddress(externalFirewall.getPrivateIpAddress()); | |
| response.setUsername(fwDetails.get("username")); | |
| response.setPublicInterface(fwDetails.get("publicInterface")); | |
| response.setUsageInterface(fwDetails.get("usageInterface")); | |
| response.setPrivateInterface(fwDetails.get("privateInterface")); | |
| response.setPublicZone(fwDetails.get("publicZone")); | |
| response.setPrivateZone(fwDetails.get("privateZone")); | |
| response.setNumRetries(fwDetails.get("numRetries")); | |
| response.setTimeout(fwDetails.get("timeout")); | |
| return response; | |
| } | |
| @Override | |
| public boolean manageGuestNetworkWithExternalFirewall(boolean add, Network network) throws ResourceUnavailableException, InsufficientCapacityException { | |
| if (network.getTrafficType() != TrafficType.Guest) { | |
| logger.trace("External firewall can only be used for add/remove guest networks."); | |
| return false; | |
| } | |
| long zoneId = network.getDataCenterId(); | |
| DataCenterVO zone = _dcDao.findById(zoneId); | |
| HostVO externalFirewall = null; | |
| if (add) { | |
| GlobalLock deviceMapLock = GlobalLock.getInternLock("NetworkFirewallDeviceMap"); | |
| try { | |
| if (deviceMapLock.lock(120)) { | |
| try { | |
| ExternalFirewallDeviceVO device = findSuitableFirewallForNetwork(network); | |
| long externalFirewallId = device.getId(); | |
| NetworkExternalFirewallVO networkFW = new NetworkExternalFirewallVO(network.getId(), externalFirewallId); | |
| _networkExternalFirewallDao.persist(networkFW); | |
| externalFirewall = _hostDao.findById(device.getHostId()); | |
| } finally { | |
| deviceMapLock.unlock(); | |
| } | |
| } | |
| } finally { | |
| deviceMapLock.releaseRef(); | |
| } | |
| } else { | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| if (fwDeviceVO == null) { | |
| logger.warn("Network shutdown requested on external firewall element, which did not implement the network." | |
| + " Either network implement failed half way through or already network shutdown is completed."); | |
| return true; | |
| } | |
| externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| } | |
| Account account = _accountDao.findByIdIncludingRemoved(network.getAccountId()); | |
| NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); | |
| boolean sharedSourceNat = offering.isSharedSourceNat(); | |
| IPAddressVO sourceNatIp = null; | |
| if (!sharedSourceNat) { | |
| // Get the source NAT IP address for this network | |
| List<? extends IpAddress> sourceNatIps = _networkModel.listPublicIpsAssignedToAccount(network.getAccountId(), zoneId, true); | |
| for (IpAddress ipAddress : sourceNatIps) { | |
| if (ipAddress.getAssociatedWithNetworkId().longValue() == network.getId()) { | |
| sourceNatIp = _ipAddressDao.findById(ipAddress.getId()); | |
| break; | |
| } | |
| } | |
| if (sourceNatIp == null) { | |
| String errorMsg = "External firewall was unable to find the source NAT IP address for network " + network.getName(); | |
| logger.error(errorMsg); | |
| return true; | |
| } | |
| } | |
| // Send a command to the external firewall to implement or shutdown the guest network | |
| long guestVlanTag = Long.parseLong(BroadcastDomainType.getValue(network.getBroadcastUri())); | |
| String guestVlanGateway = network.getGateway(); | |
| String guestVlanCidr = network.getCidr(); | |
| String sourceNatIpAddress = null; | |
| String publicVlanTag = null; | |
| if (sourceNatIp != null) { | |
| sourceNatIpAddress = sourceNatIp.getAddress().addr(); | |
| VlanVO publicVlan = _vlanDao.findById(sourceNatIp.getVlanId()); | |
| publicVlanTag = publicVlan.getVlanTag(); | |
| } | |
| // Get network rate | |
| Integer networkRate = _networkModel.getNetworkRate(network.getId(), null); | |
| IpAddressTO ip = new IpAddressTO(account.getAccountId(), sourceNatIpAddress, add, false, !sharedSourceNat, publicVlanTag, null, null, null, networkRate, false); | |
| IpAddressTO[] ips = new IpAddressTO[1]; | |
| ips[0] = ip; | |
| IpAssocCommand cmd = new IpAssocCommand(ips); | |
| cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, guestVlanGateway); | |
| cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, guestVlanCidr); | |
| cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); | |
| Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd); | |
| List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId()); | |
| if (answer == null || !answer.getResult()) { | |
| String action = add ? "implement" : "shutdown"; | |
| String answerDetails = (answer != null) ? answer.getDetails() : "answer was null"; | |
| String msg = | |
| "External firewall was unable to " + action + " the guest network on the external firewall in zone " + zone.getName() + " due to " + answerDetails; | |
| logger.error(msg); | |
| if (!add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) { | |
| // If we failed the implementation as well, then just return, no complain | |
| logger.error("Skip the shutdown of guest network on SRX because it seems we didn't implement it as well"); | |
| return true; | |
| } | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zoneId); | |
| } | |
| if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) { | |
| // Insert a new NIC for this guest network to reserve the gateway address | |
| _networkMgr.savePlaceholderNic(network, network.getGateway(), null, null); | |
| } | |
| // Delete any mappings used for inline external load balancers in this network | |
| List<NicVO> nicsInNetwork = _nicDao.listByNetworkId(network.getId()); | |
| for (NicVO nic : nicsInNetwork) { | |
| InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByNicId(nic.getId()); | |
| if (mapping != null) { | |
| _nicDao.expunge(mapping.getNicId()); | |
| _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); | |
| } | |
| } | |
| // on network shutdown, delete placeHolder nics used for the firewall device | |
| if (!add) { | |
| List<NicVO> nics = _nicDao.listByNetworkId(network.getId()); | |
| for (NicVO nic : nics) { | |
| if (nic.getVmType() == null && ReservationStrategy.PlaceHolder.equals(nic.getReservationStrategy()) && nic.getIPv4Address().equals(network.getGateway())) { | |
| logger.debug("Removing placeholder nic " + nic + " for the network " + network); | |
| _nicDao.remove(nic.getId()); | |
| } | |
| } | |
| freeFirewallForNetwork(network); | |
| } | |
| String action = add ? "implemented" : "shut down"; | |
| logger.debug("External firewall has {} the guest network for account {} with VLAN tag {}", action, account, guestVlanTag); | |
| return true; | |
| } | |
| @Override | |
| public boolean applyFirewallRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException { | |
| // Find the external firewall in this zone | |
| long zoneId = network.getDataCenterId(); | |
| DataCenterVO zone = _dcDao.findById(zoneId); | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| // During destroy, device reference may already been clean up, then we just return true | |
| if (fwDeviceVO == null) { | |
| return true; | |
| } | |
| HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| assert (externalFirewall != null); | |
| if (network.getState() == Network.State.Allocated) { | |
| logger.debug("External firewall was asked to apply firewall rules for network {}; " + | |
| "this network is not implemented. Skipping backend commands.", network); | |
| return true; | |
| } | |
| List<FirewallRuleTO> rulesTO = new ArrayList<FirewallRuleTO>(); | |
| NetworkVO networkVO = _networkDao.findById(network.getId()); | |
| NetworkOfferingVO offering = _networkOfferingDao.findById(networkVO.getNetworkOfferingId()); | |
| Boolean defaultEgressPolicy = offering.isEgressDefaultPolicy(); | |
| for (FirewallRule rule : rules) { | |
| if (rule.getSourceCidrList() == null && (rule.getPurpose() == Purpose.Firewall || rule.getPurpose() == Purpose.NetworkACL)) { | |
| _fwRulesDao.loadSourceCidrs((FirewallRuleVO)rule); | |
| } | |
| FirewallRuleTO ruleTO; | |
| if (rule.getPurpose() == Purpose.Firewall && rule.getTrafficType() == FirewallRule.TrafficType.Egress) { | |
| String guestVlanTag = BroadcastDomainType.getValue(network.getBroadcastUri()); | |
| String guestCidr = network.getCidr(); | |
| ruleTO = new FirewallRuleTO(rule, guestVlanTag, rule.getTrafficType(), guestCidr, defaultEgressPolicy, rule.getType()); | |
| } else { | |
| IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); | |
| Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); | |
| ruleTO = new FirewallRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); | |
| } | |
| rulesTO.add(ruleTO); | |
| } | |
| //Firewall rules configured for staticNAT/PF | |
| sendFirewallRules(rulesTO, zone, externalFirewall.getId()); | |
| return true; | |
| } | |
| public boolean applyStaticNatRules(Network network, List<? extends StaticNat> rules) throws ResourceUnavailableException { | |
| long zoneId = network.getDataCenterId(); | |
| DataCenterVO zone = _dcDao.findById(zoneId); | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| assert (externalFirewall != null); | |
| if (network.getState() == Network.State.Allocated) { | |
| logger.debug("External firewall was asked to apply firewall rules for network {}; " + | |
| "this network is not implemented. Skipping backend commands.", network); | |
| return true; | |
| } | |
| List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>(); | |
| for (StaticNat rule : rules) { | |
| IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); | |
| Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); | |
| StaticNatRuleTO ruleTO = | |
| new StaticNatRuleTO(0, vlan.getVlanTag(), sourceIp.getAddress().addr(), -1, -1, rule.getDestIpAddress(), -1, -1, "any", rule.isForRevoke(), false); | |
| staticNatRules.add(ruleTO); | |
| } | |
| sendStaticNatRules(staticNatRules, zone, externalFirewall.getId()); | |
| return true; | |
| } | |
| protected void sendFirewallRules(List<FirewallRuleTO> firewallRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { | |
| if (!firewallRules.isEmpty()) { | |
| SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(firewallRules); | |
| Answer answer = _agentMgr.easySend(externalFirewallId, cmd); | |
| if (answer == null || !answer.getResult()) { | |
| String details = (answer != null) ? answer.getDetails() : "details unavailable"; | |
| String msg = "External firewall was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + "."; | |
| logger.error(msg); | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); | |
| } | |
| } | |
| } | |
| protected void sendStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { | |
| if (!staticNatRules.isEmpty()) { | |
| SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules, null); | |
| Answer answer = _agentMgr.easySend(externalFirewallId, cmd); | |
| if (answer == null || !answer.getResult()) { | |
| String details = (answer != null) ? answer.getDetails() : "details unavailable"; | |
| String msg = "External firewall was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + "."; | |
| logger.error(msg); | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); | |
| } | |
| } | |
| } | |
| protected void sendPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { | |
| if (!portForwardingRules.isEmpty()) { | |
| SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(portForwardingRules); | |
| Answer answer = _agentMgr.easySend(externalFirewallId, cmd); | |
| if (answer == null || !answer.getResult()) { | |
| String details = (answer != null) ? answer.getDetails() : "details unavailable"; | |
| String msg = "External firewall was unable to apply port forwarding rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + "."; | |
| logger.error(msg); | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); | |
| } | |
| } | |
| } | |
| public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddresses) throws ResourceUnavailableException { | |
| return true; | |
| } | |
| public boolean manageRemoteAccessVpn(boolean create, Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException { | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| if (externalFirewall == null) { | |
| return false; | |
| } | |
| // Create/delete VPN | |
| IpAddress ip = _networkModel.getIp(vpn.getServerAddressId()); | |
| // Mask the IP range with the network's VLAN tag | |
| String[] ipRange = vpn.getIpRange().split("-"); | |
| DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); | |
| int vlanTag = Integer.parseInt(BroadcastDomainType.getValue(network.getBroadcastUri())); | |
| int offset = getVlanOffset(network.getPhysicalNetworkId(), vlanTag); | |
| int cidrSize = getGloballyConfiguredCidrSize(); | |
| for (int i = 0; i < 2; i++) { | |
| ipRange[i] = NetUtils.long2Ip((NetUtils.ip2Long(ipRange[i]) & 0xff000000) | (offset << (32 - cidrSize))); | |
| } | |
| String maskedIpRange = ipRange[0] + "-" + ipRange[1]; | |
| RemoteAccessVpnCfgCommand createVpnCmd = | |
| new RemoteAccessVpnCfgCommand(create, ip.getAddress().addr(), vpn.getLocalIp(), maskedIpRange, vpn.getIpsecPresharedKey(), false); | |
| createVpnCmd.setAccessDetail(NetworkElementCommand.ACCOUNT_ID, String.valueOf(network.getAccountId())); | |
| createVpnCmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, network.getCidr()); | |
| Answer answer = _agentMgr.easySend(externalFirewall.getId(), createVpnCmd); | |
| if (answer == null || !answer.getResult()) { | |
| String details = (answer != null) ? answer.getDetails() : "details unavailable"; | |
| String msg = "External firewall was unable to create a remote access VPN in zone " + zone.getName() + " due to: " + details + "."; | |
| logger.error(msg); | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); | |
| } | |
| // Add/delete users | |
| List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); | |
| return manageRemoteAccessVpnUsers(network, vpn, vpnUsers); | |
| } | |
| public boolean manageRemoteAccessVpnUsers(Network network, RemoteAccessVpn vpn, List<? extends VpnUser> vpnUsers) throws ResourceUnavailableException { | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| if (externalFirewall == null) { | |
| return false; | |
| } | |
| List<VpnUser> addUsers = new ArrayList<VpnUser>(); | |
| List<VpnUser> removeUsers = new ArrayList<VpnUser>(); | |
| for (VpnUser user : vpnUsers) { | |
| if (user.getState() == VpnUser.State.Add || user.getState() == VpnUser.State.Active) { | |
| addUsers.add(user); | |
| } else if (user.getState() == VpnUser.State.Revoke) { | |
| removeUsers.add(user); | |
| } | |
| } | |
| VpnUsersCfgCommand addUsersCmd = new VpnUsersCfgCommand(addUsers, removeUsers); | |
| addUsersCmd.setAccessDetail(NetworkElementCommand.ACCOUNT_ID, String.valueOf(network.getAccountId())); | |
| addUsersCmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, network.getCidr()); | |
| Answer answer = _agentMgr.easySend(externalFirewall.getId(), addUsersCmd); | |
| if (answer == null || !answer.getResult()) { | |
| String details = (answer != null) ? answer.getDetails() : "details unavailable"; | |
| DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); | |
| String msg = "External firewall was unable to add remote access users in zone " + zone.getName() + " due to: " + details + "."; | |
| logger.error(msg); | |
| throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); | |
| } | |
| return true; | |
| } | |
| public int getVlanOffset(long physicalNetworkId, int vlanTag) { | |
| PhysicalNetworkVO pNetwork = _physicalNetworkDao.findById(physicalNetworkId); | |
| if (pNetwork == null) { | |
| throw new CloudRuntimeException("Could not find the physical Network " + physicalNetworkId + "."); | |
| } | |
| if (pNetwork.getVnet() == null) { | |
| throw new CloudRuntimeException("Could not find vlan range for physical Network " + pNetwork + "."); | |
| } | |
| Integer lowestVlanTag = null; | |
| List<Pair<Integer, Integer>> vnetList = pNetwork.getVnet(); | |
| //finding the vlanrange in which the vlanTag lies. | |
| for (Pair<Integer, Integer> vnet : vnetList) { | |
| if (vlanTag >= vnet.first() && vlanTag <= vnet.second()) { | |
| lowestVlanTag = vnet.first(); | |
| } | |
| } | |
| if (lowestVlanTag == null) { | |
| throw new InvalidParameterValueException("The vlan tag does not belong to any of the existing vlan ranges"); | |
| } | |
| return vlanTag - lowestVlanTag; | |
| } | |
| public int getGloballyConfiguredCidrSize() { | |
| try { | |
| String globalVlanBits = _configDao.getValue(Config.GuestVlanBits.key()); | |
| return 8 + Integer.parseInt(globalVlanBits); | |
| } catch (Exception e) { | |
| throw new CloudRuntimeException("Failed to read the globally configured VLAN bits size."); | |
| } | |
| } | |
| @Override | |
| public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { | |
| // TODO Auto-generated method stub | |
| return null; | |
| } | |
| @Override | |
| public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details, List<String> hostTags) { | |
| if (!(startup[0] instanceof StartupExternalFirewallCommand)) { | |
| return null; | |
| } | |
| host.setType(Host.Type.ExternalFirewall); | |
| return host; | |
| } | |
| @Override | |
| public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { | |
| if (host.getType() != com.cloud.host.Host.Type.ExternalFirewall) { | |
| return null; | |
| } | |
| return new DeleteHostAnswer(true); | |
| } | |
| @Override | |
| public boolean applyPortForwardingRules(Network network, List<? extends PortForwardingRule> rules) throws ResourceUnavailableException { | |
| // Find the external firewall in this zone | |
| long zoneId = network.getDataCenterId(); | |
| DataCenterVO zone = _dcDao.findById(zoneId); | |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); | |
| HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); | |
| assert (externalFirewall != null); | |
| if (network.getState() == Network.State.Allocated) { | |
| logger.debug("External firewall was asked to apply firewall rules for network {}; " + | |
| "this network is not implemented. Skipping backend commands.", network); | |
| return true; | |
| } | |
| List<PortForwardingRuleTO> pfRules = new ArrayList<PortForwardingRuleTO>(); | |
| for (PortForwardingRule rule : rules) { | |
| IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); | |
| Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); | |
| PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); | |
| pfRules.add(ruleTO); | |
| } | |
| sendPortForwardingRules(pfRules, zone, externalFirewall.getId()); | |
| return true; | |
| } | |
| } |