| // |
| // 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.element; |
| |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; |
| import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; |
| |
| import com.cloud.agent.AgentManager; |
| import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterAnswer; |
| import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterCommand; |
| import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterAnswer; |
| import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterCommand; |
| import com.cloud.agent.api.ConfigureSharedNetworkUuidAnswer; |
| import com.cloud.agent.api.ConfigureSharedNetworkUuidCommand; |
| import com.cloud.agent.api.ConfigureSharedNetworkVlanIdAnswer; |
| import com.cloud.agent.api.ConfigureSharedNetworkVlanIdCommand; |
| import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterAnswer; |
| import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterCommand; |
| import com.cloud.agent.api.CreateLogicalRouterAnswer; |
| import com.cloud.agent.api.CreateLogicalRouterCommand; |
| import com.cloud.agent.api.CreateLogicalSwitchPortAnswer; |
| import com.cloud.agent.api.CreateLogicalSwitchPortCommand; |
| import com.cloud.agent.api.DeleteLogicalRouterAnswer; |
| import com.cloud.agent.api.DeleteLogicalRouterCommand; |
| import com.cloud.agent.api.DeleteLogicalSwitchPortAnswer; |
| import com.cloud.agent.api.DeleteLogicalSwitchPortCommand; |
| import com.cloud.agent.api.FindLogicalSwitchPortAnswer; |
| import com.cloud.agent.api.FindLogicalSwitchPortCommand; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.StartupNiciraNvpCommand; |
| import com.cloud.agent.api.UpdateLogicalSwitchPortCommand; |
| import com.cloud.agent.api.to.PortForwardingRuleTO; |
| import com.cloud.agent.api.to.StaticNatRuleTO; |
| import com.cloud.api.ApiDBUtils; |
| import com.cloud.api.commands.AddNiciraNvpDeviceCmd; |
| import com.cloud.api.commands.DeleteNiciraNvpDeviceCmd; |
| import com.cloud.api.commands.ListNiciraNvpDeviceNetworksCmd; |
| import com.cloud.api.commands.ListNiciraNvpDevicesCmd; |
| import com.cloud.api.response.NiciraNvpDeviceResponse; |
| import com.cloud.configuration.ConfigurationManager; |
| import com.cloud.dc.Vlan; |
| import com.cloud.dc.VlanVO; |
| import com.cloud.dc.dao.VlanDao; |
| import com.cloud.deploy.DeployDestination; |
| import com.cloud.exception.ConcurrentOperationException; |
| import com.cloud.exception.InsufficientCapacityException; |
| 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.IpAddress; |
| import com.cloud.network.IpAddressManager; |
| import com.cloud.network.Network; |
| import com.cloud.network.Network.Capability; |
| import com.cloud.network.Network.GuestType; |
| import com.cloud.network.Network.Provider; |
| import com.cloud.network.Network.Service; |
| import com.cloud.network.NetworkModel; |
| import com.cloud.network.Networks; |
| import com.cloud.network.Networks.BroadcastDomainType; |
| import com.cloud.network.NiciraNvpDeviceVO; |
| import com.cloud.network.NiciraNvpNicMappingVO; |
| import com.cloud.network.NiciraNvpRouterMappingVO; |
| import com.cloud.network.PhysicalNetwork; |
| import com.cloud.network.PhysicalNetworkServiceProvider; |
| import com.cloud.network.PublicIpAddress; |
| import com.cloud.network.addr.PublicIp; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.dao.NetworkServiceMapDao; |
| import com.cloud.network.dao.NetworkVO; |
| import com.cloud.network.dao.NiciraNvpDao; |
| import com.cloud.network.dao.NiciraNvpNicMappingDao; |
| import com.cloud.network.dao.NiciraNvpRouterMappingDao; |
| 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.resource.NiciraNvpResource; |
| import com.cloud.network.rules.PortForwardingRule; |
| import com.cloud.network.rules.StaticNat; |
| import com.cloud.offering.NetworkOffering; |
| 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.utils.component.AdapterBase; |
| import com.cloud.utils.db.DB; |
| 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.vm.NicProfile; |
| import com.cloud.vm.NicVO; |
| import com.cloud.vm.ReservationContext; |
| import com.cloud.vm.VirtualMachineProfile; |
| import com.cloud.vm.dao.NicDao; |
| |
| @Component |
| public class NiciraNvpElement extends AdapterBase implements ConnectivityProvider, SourceNatServiceProvider, PortForwardingServiceProvider, StaticNatServiceProvider, |
| NiciraNvpElementService, ResourceStateAdapter, IpDeployer { |
| |
| private static final int MAX_PORT = 65535; |
| private static final int MIN_PORT = 0; |
| |
| private static final Logger s_logger = Logger.getLogger(NiciraNvpElement.class); |
| |
| private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities(); |
| |
| @Inject |
| protected NicDao nicDao; |
| @Inject |
| protected ResourceManager resourceMgr; |
| @Inject |
| protected PhysicalNetworkDao physicalNetworkDao; |
| @Inject |
| protected PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao; |
| @Inject |
| protected NiciraNvpDao niciraNvpDao; |
| @Inject |
| protected HostDetailsDao hostDetailsDao; |
| @Inject |
| protected HostDao hostDao; |
| @Inject |
| protected AgentManager agentMgr; |
| @Inject |
| protected NiciraNvpNicMappingDao niciraNvpNicMappingDao; |
| @Inject |
| protected NiciraNvpRouterMappingDao niciraNvpRouterMappingDao; |
| @Inject |
| protected NetworkDao networkDao; |
| @Inject |
| protected NetworkOrchestrationService networkManager; |
| @Inject |
| protected NetworkModel networkModel; |
| @Inject |
| protected ConfigurationManager configMgr; |
| @Inject |
| protected NetworkServiceMapDao ntwkSrvcDao; |
| @Inject |
| protected VlanDao vlanDao; |
| @Inject |
| protected IpAddressManager ipAddrMgr; |
| |
| @Override |
| public Map<Service, Map<Capability, String>> getCapabilities() { |
| return capabilities; |
| } |
| |
| @Override |
| public Provider getProvider() { |
| return Provider.NiciraNvp; |
| } |
| |
| protected boolean canHandle(Network network, Service service) { |
| s_logger.debug("Checking if NiciraNvpElement can handle service " + service.getName() + " on network " + network.getDisplayText()); |
| if (network.getBroadcastDomainType() != BroadcastDomainType.Lswitch) { |
| return false; |
| } |
| |
| if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) { |
| s_logger.debug("NiciraNvpElement is not a provider for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| if (!ntwkSrvcDao.canProviderSupportServiceInNetwork(network.getId(), service, Network.Provider.NiciraNvp)) { |
| s_logger.debug("NiciraNvpElement can't provide the " + service.getName() + " service on network " + network.getDisplayText()); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| super.configure(name, params); |
| resourceMgr.registerResourceStateAdapter(name, this); |
| return true; |
| } |
| |
| @Override |
| public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException, InsufficientCapacityException { |
| s_logger.debug("entering NiciraNvpElement implement function for network " + network.getDisplayText() + " (state " + network.getState() + ")"); |
| |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| |
| if (network.getBroadcastUri() == null) { |
| s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid"); |
| return false; |
| } |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| hostDao.loadDetails(niciraNvpHost); |
| |
| Account owner = context.getAccount(); |
| |
| /* |
| * TODO Shouldn't we lock the network as we might need to do |
| * multiple operations that should be done only once. |
| */ |
| |
| if (network.getGuestType().equals(GuestType.Shared)){ |
| //Support Shared Networks |
| String lSwitchUuid = BroadcastDomainType.getValue(network.getBroadcastUri()); |
| String ownerName = context.getDomain().getName() + "-" + context.getAccount().getAccountName(); |
| return sharedNetworkSupport(network, lSwitchUuid, ownerName, niciraNvpHost); |
| } |
| else if (network.getGuestType().equals(GuestType.Isolated) && networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.NiciraNvp)) { |
| // Implement SourceNat immediately as we have al the info already |
| s_logger.debug("Apparently we are supposed to provide SourceNat on this network"); |
| |
| PublicIp sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); |
| String publicCidr = sourceNatIp.getAddress().addr() + "/" + NetUtils.getCidrSize(sourceNatIp.getVlanNetmask()); |
| String internalCidr = network.getGateway() + "/" + network.getCidr().split("/")[1]; |
| // assuming a vlan: |
| String vtag = sourceNatIp.getVlanTag(); |
| BroadcastDomainType tiep = null; |
| try { |
| tiep = BroadcastDomainType.getTypeOf(vtag); |
| } catch (URISyntaxException use) { |
| throw new CloudRuntimeException("vlantag for sourceNatIp is not valid: " + vtag, use); |
| } |
| if (tiep == BroadcastDomainType.Vlan) { |
| vtag = BroadcastDomainType.Vlan.getValueFrom(BroadcastDomainType.fromString(vtag)); |
| } else if (!(tiep == BroadcastDomainType.UnDecided || tiep == BroadcastDomainType.Native)) { |
| throw new CloudRuntimeException("only vlans are supported for sourceNatIp, at this moment: " + vtag); |
| } |
| long vlanid = (Vlan.UNTAGGED.equals(vtag)) ? 0 : Long.parseLong(vtag); |
| |
| CreateLogicalRouterCommand cmd = |
| new CreateLogicalRouterCommand(niciraNvpHost.getDetail("l3gatewayserviceuuid"), vlanid, BroadcastDomainType.getValue(network.getBroadcastUri()), |
| "router-" + network.getDisplayText(), publicCidr, sourceNatIp.getGateway(), internalCidr, context.getDomain().getName() + "-" + |
| context.getAccount().getAccountName()); |
| CreateLogicalRouterAnswer answer = (CreateLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| if (answer.getResult() == false) { |
| s_logger.error("Failed to create Logical Router for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| NiciraNvpRouterMappingVO routermapping = new NiciraNvpRouterMappingVO(answer.getLogicalRouterUuid(), network.getId()); |
| niciraNvpRouterMappingDao.persist(routermapping); |
| |
| } |
| |
| return true; |
| } |
| |
| private boolean sharedNetworkSupport(Network network, String lSwitchUuid, String ownerName, HostVO niciraNvpHost) { |
| //Support Shared Networks, we won’t be creating logical router, 2 cases: |
| //Case 1) UUID Supplied for VLAN -> This is UUID of the logical router to attach lswitch |
| //Case 2) Numerical ID supplied for VLAN -> lswitch is connected to L2 gateway service that we have as an attribute of the NVP device. If no L2 gateway attribute exists then exception. |
| |
| if (niciraNvpRouterMappingDao.existsMappingForNetworkId(network.getId())){ |
| //Case 1) |
| return sharedNetworkSupportUUIDVlanId(network, lSwitchUuid, ownerName, niciraNvpHost); |
| } |
| else { |
| //Case 2) |
| return sharedNetworkSupportNumericalVlanId(network, lSwitchUuid, ownerName, niciraNvpHost); |
| } |
| } |
| |
| private boolean sharedNetworkSupportUUIDVlanId(Network network, String lSwitchUuid, String ownerName, HostVO niciraNvpHost) { |
| String networkCidr = network.getCidr(); |
| String vlanGateway = network.getGateway(); |
| String portIpAddress = createLogicalRouterPortIpAddress(networkCidr, vlanGateway); |
| NiciraNvpRouterMappingVO mapRouterNetwork = niciraNvpRouterMappingDao.findByNetworkId(network.getId()); |
| String lRouterUuid = mapRouterNetwork.getLogicalRouterUuid(); |
| ConfigureSharedNetworkUuidCommand cmd = |
| new ConfigureSharedNetworkUuidCommand(lRouterUuid, lSwitchUuid, portIpAddress, ownerName, network.getId()); |
| ConfigureSharedNetworkUuidAnswer answer = (ConfigureSharedNetworkUuidAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| if (answer.getResult() == false) { |
| s_logger.error("Failed to configure Logical Router for Shared network " + network.getDisplayText()); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean sharedNetworkSupportNumericalVlanId(Network network, String lSwitchUuid, String ownerName, HostVO niciraNvpHost) { |
| List<VlanVO> networkVlans = vlanDao.listVlansByNetworkId(network.getId()); |
| if (networkVlans.size() == 1){ |
| for (VlanVO vlanVO : networkVlans) { |
| long vlanId = Long.parseLong(vlanVO.getVlanTag()); |
| String l2GatewayServiceUuid = niciraNvpHost.getDetail("l2gatewayserviceuuid"); |
| if (l2GatewayServiceUuid == null){ |
| throw new CloudRuntimeException("No L2 Gateway Service Uuid found on " + niciraNvpHost.getName()); |
| } |
| ConfigureSharedNetworkVlanIdCommand cmd = |
| new ConfigureSharedNetworkVlanIdCommand(lSwitchUuid, l2GatewayServiceUuid , vlanId, ownerName, network.getId()); |
| ConfigureSharedNetworkVlanIdAnswer answer = (ConfigureSharedNetworkVlanIdAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| if (answer.getResult() == false) { |
| s_logger.error("Failed to configure Shared network " + network.getDisplayText()); |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| |
| private String createLogicalRouterPortIpAddress(String networkCidr, String vlanGateway) { |
| if (networkCidr != null && vlanGateway != null){ |
| return networkCidr.replaceFirst("[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,3}", vlanGateway); |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { |
| |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| |
| if (network.getBroadcastUri() == null) { |
| s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid"); |
| return false; |
| } |
| |
| NicVO nicVO = nicDao.findById(nic.getId()); |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| |
| NiciraNvpNicMappingVO existingNicMap = niciraNvpNicMappingDao.findByNicUuid(nicVO.getUuid()); |
| if (existingNicMap != null) { |
| FindLogicalSwitchPortCommand findCmd = new FindLogicalSwitchPortCommand(existingNicMap.getLogicalSwitchUuid(), existingNicMap.getLogicalSwitchPortUuid()); |
| FindLogicalSwitchPortAnswer answer = (FindLogicalSwitchPortAnswer)agentMgr.easySend(niciraNvpHost.getId(), findCmd); |
| |
| if (answer.getResult()) { |
| s_logger.warn("Existing Logical Switchport found for nic " + nic.getName() + " with uuid " + existingNicMap.getLogicalSwitchPortUuid()); |
| UpdateLogicalSwitchPortCommand cmd = |
| new UpdateLogicalSwitchPortCommand(existingNicMap.getLogicalSwitchPortUuid(), BroadcastDomainType.getValue(network.getBroadcastUri()), |
| nicVO.getUuid(), context.getDomain().getName() + "-" + context.getAccount().getAccountName(), nic.getName()); |
| agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| return true; |
| } else { |
| s_logger.error("Stale entry found for nic " + nic.getName() + " with logical switchport uuid " + existingNicMap.getLogicalSwitchPortUuid()); |
| niciraNvpNicMappingDao.remove(existingNicMap.getId()); |
| } |
| } |
| |
| CreateLogicalSwitchPortCommand cmd = |
| new CreateLogicalSwitchPortCommand(BroadcastDomainType.getValue(network.getBroadcastUri()), nicVO.getUuid(), context.getDomain().getName() + "-" + |
| context.getAccount().getAccountName(), nic.getName()); |
| CreateLogicalSwitchPortAnswer answer = (CreateLogicalSwitchPortAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| |
| if (answer == null || !answer.getResult()) { |
| s_logger.error("CreateLogicalSwitchPortCommand failed"); |
| return false; |
| } |
| |
| NiciraNvpNicMappingVO nicMap = |
| new NiciraNvpNicMappingVO(BroadcastDomainType.getValue(network.getBroadcastUri()), answer.getLogicalSwitchPortUuid(), nicVO.getUuid()); |
| niciraNvpNicMappingDao.persist(nicMap); |
| |
| return true; |
| } |
| |
| @Override |
| public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| |
| if (network.getBroadcastUri() == null) { |
| s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid"); |
| return false; |
| } |
| |
| NicVO nicVO = nicDao.findById(nic.getId()); |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| |
| NiciraNvpNicMappingVO nicMap = niciraNvpNicMappingDao.findByNicUuid(nicVO.getUuid()); |
| if (nicMap == null) { |
| s_logger.error("No mapping for nic " + nic.getName()); |
| return false; |
| } |
| |
| DeleteLogicalSwitchPortCommand cmd = new DeleteLogicalSwitchPortCommand(nicMap.getLogicalSwitchUuid(), nicMap.getLogicalSwitchPortUuid()); |
| DeleteLogicalSwitchPortAnswer answer = (DeleteLogicalSwitchPortAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| |
| if (answer == null || !answer.getResult()) { |
| s_logger.error("DeleteLogicalSwitchPortCommand failed"); |
| return false; |
| } |
| |
| niciraNvpNicMappingDao.remove(nicMap.getId()); |
| |
| return true; |
| } |
| |
| @Override |
| public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| |
| //Dont destroy logical router when removing Shared Networks |
| if (! network.getGuestType().equals(GuestType.Shared) && networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.NiciraNvp)) { |
| s_logger.debug("Apparently we were providing SourceNat on this network"); |
| |
| // Deleting the LogicalRouter will also take care of all provisioned |
| // nat rules. |
| NiciraNvpRouterMappingVO routermapping = niciraNvpRouterMappingDao.findByNetworkId(network.getId()); |
| if (routermapping == null) { |
| s_logger.warn("No logical router uuid found for network " + network.getDisplayText()); |
| // This might be cause by a failed deployment, so don't make shutdown fail as well. |
| return true; |
| } |
| |
| DeleteLogicalRouterCommand cmd = new DeleteLogicalRouterCommand(routermapping.getLogicalRouterUuid()); |
| DeleteLogicalRouterAnswer answer = (DeleteLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| if (answer.getResult() == false) { |
| s_logger.error("Failed to delete LogicalRouter for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| niciraNvpRouterMappingDao.remove(routermapping.getId()); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean isReady(PhysicalNetworkServiceProvider provider) { |
| return true; |
| } |
| |
| @Override |
| public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| // Nothing to do here. |
| return true; |
| } |
| |
| @Override |
| public boolean canEnableIndividualServices() { |
| return true; |
| } |
| |
| @Override |
| public boolean verifyServicesCombination(Set<Service> services) { |
| // This element can only function in a Nicra Nvp based |
| // SDN network, so Connectivity needs to be present here |
| if (!services.contains(Service.Connectivity)) { |
| s_logger.warn("Unable to provide services without Connectivity service enabled for this element"); |
| return false; |
| } |
| if ((services.contains(Service.PortForwarding) || services.contains(Service.StaticNat)) && !services.contains(Service.SourceNat)) { |
| s_logger.warn("Unable to provide StaticNat and/or PortForwarding without the SourceNat service"); |
| return false; |
| } |
| return true; |
| } |
| |
| private static Map<Service, Map<Capability, String>> setCapabilities() { |
| Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>(); |
| |
| // L2 Support : SDN provisioning |
| capabilities.put(Service.Connectivity, null); |
| |
| // L3 Support : Generic? |
| capabilities.put(Service.Gateway, null); |
| |
| // L3 Support : SourceNat |
| Map<Capability, String> sourceNatCapabilities = new HashMap<Capability, String>(); |
| sourceNatCapabilities.put(Capability.SupportedSourceNatTypes, "peraccount"); |
| sourceNatCapabilities.put(Capability.RedundantRouter, "false"); |
| capabilities.put(Service.SourceNat, sourceNatCapabilities); |
| |
| // L3 Support : Port Forwarding |
| capabilities.put(Service.PortForwarding, null); |
| |
| // L3 support : StaticNat |
| capabilities.put(Service.StaticNat, null); |
| |
| return capabilities; |
| } |
| |
| @Override |
| public List<Class<?>> getCommands() { |
| List<Class<?>> cmdList = new ArrayList<Class<?>>(); |
| cmdList.add(AddNiciraNvpDeviceCmd.class); |
| cmdList.add(DeleteNiciraNvpDeviceCmd.class); |
| cmdList.add(ListNiciraNvpDeviceNetworksCmd.class); |
| cmdList.add(ListNiciraNvpDevicesCmd.class); |
| return cmdList; |
| } |
| |
| @Override |
| @DB |
| public NiciraNvpDeviceVO addNiciraNvpDevice(AddNiciraNvpDeviceCmd cmd) { |
| ServerResource resource = new NiciraNvpResource(); |
| final String deviceName = Network.Provider.NiciraNvp.getName(); |
| NetworkDevice networkDevice = NetworkDevice.getNetworkDevice(deviceName); |
| if (networkDevice == null) { |
| throw new CloudRuntimeException("No network device found for " + deviceName); |
| } |
| final Long physicalNetworkId = cmd.getPhysicalNetworkId(); |
| PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); |
| if (physicalNetwork == null) { |
| throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); |
| } |
| long zoneId = physicalNetwork.getDataCenterId(); |
| |
| final PhysicalNetworkServiceProviderVO ntwkSvcProvider = |
| physicalNetworkServiceProviderDao.findByServiceProvider(physicalNetwork.getId(), networkDevice.getNetworkServiceProvder()); |
| if (ntwkSvcProvider == null) { |
| throw new CloudRuntimeException("Network Service Provider: " + networkDevice.getNetworkServiceProvder() + " is not enabled in the physical network: " + |
| physicalNetworkId + "to add this device"); |
| } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) { |
| throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() + " is in shutdown state in the physical network: " + |
| physicalNetworkId + "to add this device"); |
| } |
| |
| if (niciraNvpDao.listByPhysicalNetwork(physicalNetworkId).size() != 0) { |
| throw new CloudRuntimeException("A NiciraNvp device is already configured on this physical network"); |
| } |
| |
| Map<String, String> params = new HashMap<String, String>(); |
| params.put("guid", UUID.randomUUID().toString()); |
| params.put("zoneId", String.valueOf(physicalNetwork.getDataCenterId())); |
| params.put("physicalNetworkId", String.valueOf(physicalNetwork.getId())); |
| params.put("name", "Nicira Controller - " + cmd.getHost()); |
| params.put("ip", cmd.getHost()); |
| params.put("adminuser", cmd.getUsername()); |
| params.put("adminpass", cmd.getPassword()); |
| params.put("transportzoneuuid", cmd.getTransportzoneUuid()); |
| // FIXME What to do with multiple isolation types |
| params.put("transportzoneisotype", physicalNetwork.getIsolationMethods().get(0).toLowerCase()); |
| if (cmd.getL3GatewayServiceUuid() != null) { |
| params.put("l3gatewayserviceuuid", cmd.getL3GatewayServiceUuid()); |
| } |
| if (cmd.getL2GatewayServiceUuid() != null) { |
| params.put("l2gatewayserviceuuid", cmd.getL2GatewayServiceUuid()); |
| } |
| |
| Map<String, Object> hostdetails = new HashMap<String, Object>(); |
| hostdetails.putAll(params); |
| |
| try { |
| resource.configure(cmd.getHost(), hostdetails); |
| |
| final Host host = resourceMgr.addHost(zoneId, resource, Host.Type.L2Networking, params); |
| if (host != null) { |
| return Transaction.execute(new TransactionCallback<NiciraNvpDeviceVO>() { |
| @Override |
| public NiciraNvpDeviceVO doInTransaction(TransactionStatus status) { |
| NiciraNvpDeviceVO niciraNvpDevice = new NiciraNvpDeviceVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), deviceName); |
| niciraNvpDao.persist(niciraNvpDevice); |
| |
| DetailVO detail = new DetailVO(host.getId(), "niciranvpdeviceid", String.valueOf(niciraNvpDevice.getId())); |
| hostDetailsDao.persist(detail); |
| |
| return niciraNvpDevice; |
| } |
| }); |
| } else { |
| throw new CloudRuntimeException("Failed to add Nicira Nvp Device due to internal error."); |
| } |
| } catch (ConfigurationException e) { |
| throw new CloudRuntimeException(e.getMessage()); |
| } |
| } |
| |
| @Override |
| public NiciraNvpDeviceResponse createNiciraNvpDeviceResponse(NiciraNvpDeviceVO niciraNvpDeviceVO) { |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDeviceVO.getHostId()); |
| hostDao.loadDetails(niciraNvpHost); |
| |
| NiciraNvpDeviceResponse response = new NiciraNvpDeviceResponse(); |
| response.setDeviceName(niciraNvpDeviceVO.getDeviceName()); |
| PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(niciraNvpDeviceVO.getPhysicalNetworkId()); |
| if (pnw != null) { |
| response.setPhysicalNetworkId(pnw.getUuid()); |
| } |
| response.setId(niciraNvpDeviceVO.getUuid()); |
| response.setProviderName(niciraNvpDeviceVO.getProviderName()); |
| response.setHostName(niciraNvpHost.getDetail("ip")); |
| response.setTransportZoneUuid(niciraNvpHost.getDetail("transportzoneuuid")); |
| response.setL3GatewayServiceUuid(niciraNvpHost.getDetail("l3gatewayserviceuuid")); |
| response.setL2GatewayServiceUuid(niciraNvpHost.getDetail("l2gatewayserviceuuid")); |
| response.setObjectName("niciranvpdevice"); |
| return response; |
| } |
| |
| @Override |
| public boolean deleteNiciraNvpDevice(DeleteNiciraNvpDeviceCmd cmd) { |
| Long niciraDeviceId = cmd.getNiciraNvpDeviceId(); |
| NiciraNvpDeviceVO niciraNvpDevice = niciraNvpDao.findById(niciraDeviceId); |
| if (niciraNvpDevice == null) { |
| throw new InvalidParameterValueException("Could not find a nicira device with id " + niciraDeviceId); |
| } |
| |
| // Find the physical network we work for |
| Long physicalNetworkId = niciraNvpDevice.getPhysicalNetworkId(); |
| PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); |
| if (physicalNetwork != null) { |
| // Lets see if there are networks that use us |
| // Find the nicira networks on this physical network |
| List<NetworkVO> networkList = networkDao.listByPhysicalNetwork(physicalNetworkId); |
| if (networkList != null) { |
| // Networks with broadcast type lswitch are ours |
| for (NetworkVO network : networkList) { |
| if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Lswitch) { |
| if ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy)) { |
| throw new CloudRuntimeException("This Nicira Nvp device can not be deleted as there are one or more logical networks provisioned by cloudstack."); |
| } |
| } |
| } |
| } |
| } |
| |
| HostVO niciraHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| Long hostId = niciraHost.getId(); |
| |
| niciraHost.setResourceState(ResourceState.Maintenance); |
| hostDao.update(hostId, niciraHost); |
| resourceMgr.deleteHost(hostId, false, false); |
| |
| niciraNvpDao.remove(niciraDeviceId); |
| return true; |
| } |
| |
| @Override |
| public List<NiciraNvpDeviceVO> listNiciraNvpDevices(ListNiciraNvpDevicesCmd cmd) { |
| Long physicalNetworkId = cmd.getPhysicalNetworkId(); |
| Long niciraNvpDeviceId = cmd.getNiciraNvpDeviceId(); |
| List<NiciraNvpDeviceVO> responseList = new ArrayList<NiciraNvpDeviceVO>(); |
| |
| if (physicalNetworkId == null && niciraNvpDeviceId == null) { |
| throw new InvalidParameterValueException("Either physical network Id or nicira device Id must be specified"); |
| } |
| |
| if (niciraNvpDeviceId != null) { |
| NiciraNvpDeviceVO niciraNvpDevice = niciraNvpDao.findById(niciraNvpDeviceId); |
| if (niciraNvpDevice == null) { |
| throw new InvalidParameterValueException("Could not find Nicira Nvp device with id: " + niciraNvpDevice); |
| } |
| responseList.add(niciraNvpDevice); |
| } else { |
| PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); |
| if (physicalNetwork == null) { |
| throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId); |
| } |
| responseList = niciraNvpDao.listByPhysicalNetwork(physicalNetworkId); |
| } |
| |
| return responseList; |
| } |
| |
| @Override |
| public List<? extends Network> listNiciraNvpDeviceNetworks(ListNiciraNvpDeviceNetworksCmd cmd) { |
| Long niciraDeviceId = cmd.getNiciraNvpDeviceId(); |
| NiciraNvpDeviceVO niciraNvpDevice = niciraNvpDao.findById(niciraDeviceId); |
| if (niciraNvpDevice == null) { |
| throw new InvalidParameterValueException("Could not find a nicira device with id " + niciraDeviceId); |
| } |
| |
| // Find the physical network we work for |
| Long physicalNetworkId = niciraNvpDevice.getPhysicalNetworkId(); |
| PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); |
| if (physicalNetwork == null) { |
| // No such physical network, so no provisioned networks |
| return Collections.emptyList(); |
| } |
| |
| // Find the nicira networks on this physical network |
| List<NetworkVO> networkList = networkDao.listByPhysicalNetwork(physicalNetworkId); |
| if (networkList == null) { |
| return Collections.emptyList(); |
| } |
| |
| // Networks with broadcast type lswitch are ours |
| List<NetworkVO> responseList = new ArrayList<NetworkVO>(); |
| for (NetworkVO network : networkList) { |
| if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Lswitch) { |
| responseList.add(network); |
| } |
| } |
| |
| return responseList; |
| } |
| |
| @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 StartupNiciraNvpCommand)) { |
| return null; |
| } |
| host.setType(Host.Type.L2Networking); |
| return host; |
| } |
| |
| @Override |
| public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { |
| if (!(host.getType() == Host.Type.L2Networking)) { |
| return null; |
| } |
| return new DeleteHostAnswer(true); |
| } |
| |
| /** |
| * From interface SourceNatServiceProvider |
| */ |
| @Override |
| public IpDeployer getIpDeployer(Network network) { |
| return this; |
| } |
| |
| /** |
| * From interface IpDeployer |
| * |
| * @param network |
| * @param ipAddress |
| * @param services |
| * @return |
| * @throws ResourceUnavailableException |
| */ |
| @Override |
| public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> services) throws ResourceUnavailableException { |
| if (services.contains(Service.SourceNat)) { |
| // Only if we need to provide SourceNat we need to configure the logical router |
| // SourceNat is required for StaticNat and PortForwarding |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| hostDao.loadDetails(niciraNvpHost); |
| |
| NiciraNvpRouterMappingVO routermapping = niciraNvpRouterMappingDao.findByNetworkId(network.getId()); |
| if (routermapping == null) { |
| s_logger.error("No logical router uuid found for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| List<String> cidrs = new ArrayList<String>(); |
| for (PublicIpAddress ip : ipAddress) { |
| if (ip.getState() == IpAddress.State.Releasing) { |
| // If we are releasing we don't need to push this ip to |
| // the Logical Router |
| continue; |
| } |
| cidrs.add(ip.getAddress().addr() + "/" + NetUtils.getCidrSize(ip.getNetmask())); |
| } |
| ConfigurePublicIpsOnLogicalRouterCommand cmd = |
| new ConfigurePublicIpsOnLogicalRouterCommand(routermapping.getLogicalRouterUuid(), niciraNvpHost.getDetail("l3gatewayserviceuuid"), cidrs); |
| ConfigurePublicIpsOnLogicalRouterAnswer answer = (ConfigurePublicIpsOnLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| //FIXME answer can be null if the host is down |
| return answer.getResult(); |
| } else { |
| s_logger.debug("No need to provision ip addresses as we are not providing L3 services."); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * From interface StaticNatServiceProvider |
| */ |
| @Override |
| public boolean applyStaticNats(Network network, List<? extends StaticNat> rules) throws ResourceUnavailableException { |
| if (!canHandle(network, Service.StaticNat)) { |
| return false; |
| } |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| |
| NiciraNvpRouterMappingVO routermapping = niciraNvpRouterMappingDao.findByNetworkId(network.getId()); |
| if (routermapping == null) { |
| s_logger.error("No logical router uuid found for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>(); |
| for (StaticNat rule : rules) { |
| IpAddress sourceIp = networkModel.getIp(rule.getSourceIpAddressId()); |
| // Force the nat rule into the StaticNatRuleTO, no use making a new TO object |
| // we only need the source and destination ip. Unfortunately no mention if a rule |
| // is new. |
| StaticNatRuleTO ruleTO = |
| new StaticNatRuleTO(1, sourceIp.getAddress().addr(), MIN_PORT, MAX_PORT, rule.getDestIpAddress(), MIN_PORT, MAX_PORT, "any", rule.isForRevoke(), false); |
| staticNatRules.add(ruleTO); |
| } |
| |
| ConfigureStaticNatRulesOnLogicalRouterCommand cmd = new ConfigureStaticNatRulesOnLogicalRouterCommand(routermapping.getLogicalRouterUuid(), staticNatRules); |
| ConfigureStaticNatRulesOnLogicalRouterAnswer answer = (ConfigureStaticNatRulesOnLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| |
| return answer.getResult(); |
| } |
| |
| /** |
| * From interface PortForwardingServiceProvider |
| */ |
| @Override |
| public boolean applyPFRules(Network network, List<PortForwardingRule> rules) throws ResourceUnavailableException { |
| if (!canHandle(network, Service.PortForwarding)) { |
| return false; |
| } |
| |
| List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); |
| if (devices.isEmpty()) { |
| s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); |
| return false; |
| } |
| NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); |
| HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId()); |
| |
| NiciraNvpRouterMappingVO routermapping = niciraNvpRouterMappingDao.findByNetworkId(network.getId()); |
| if (routermapping == null) { |
| s_logger.error("No logical router uuid found for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| List<PortForwardingRuleTO> portForwardingRules = 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()); |
| portForwardingRules.add(ruleTO); |
| } |
| |
| ConfigurePortForwardingRulesOnLogicalRouterCommand cmd = |
| new ConfigurePortForwardingRulesOnLogicalRouterCommand(routermapping.getLogicalRouterUuid(), portForwardingRules); |
| ConfigurePortForwardingRulesOnLogicalRouterAnswer answer = (ConfigurePortForwardingRulesOnLogicalRouterAnswer)agentMgr.easySend(niciraNvpHost.getId(), cmd); |
| |
| return answer.getResult(); |
| } |
| |
| } |