| // |
| // 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.util.ArrayList; |
| 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.network.ExternalNetworkDeviceManager.NetworkDevice; |
| import org.apache.commons.net.util.SubnetUtils; |
| |
| import com.cloud.agent.AgentManager; |
| import com.cloud.agent.api.BcfAnswer; |
| import com.cloud.agent.api.UpdateBcfRouterCommand; |
| import com.cloud.agent.api.CreateBcfAttachmentCommand; |
| import com.cloud.agent.api.CreateBcfStaticNatCommand; |
| import com.cloud.agent.api.DeleteBcfAttachmentCommand; |
| import com.cloud.agent.api.DeleteBcfStaticNatCommand; |
| import com.cloud.agent.api.StartupBigSwitchBcfCommand; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.api.ApiDBUtils; |
| import com.cloud.api.commands.AddBigSwitchBcfDeviceCmd; |
| import com.cloud.api.commands.DeleteBigSwitchBcfDeviceCmd; |
| import com.cloud.api.commands.ListBigSwitchBcfDevicesCmd; |
| import com.cloud.api.commands.BcfConstants; |
| import com.cloud.api.response.BigSwitchBcfDeviceResponse; |
| import com.cloud.configuration.ConfigurationManager; |
| import com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.dao.DataCenterDao; |
| 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.hypervisor.Hypervisor.HypervisorType; |
| import com.cloud.network.BigSwitchBcfDeviceVO; |
| import com.cloud.network.IpAddressManager; |
| import com.cloud.network.Network; |
| import com.cloud.network.Network.Capability; |
| import com.cloud.network.Network.Provider; |
| import com.cloud.network.Network.Service; |
| import com.cloud.network.NetworkModel; |
| import com.cloud.network.Networks.BroadcastDomainType; |
| import com.cloud.network.PhysicalNetwork; |
| import com.cloud.network.PhysicalNetworkServiceProvider; |
| import com.cloud.network.PublicIpAddress; |
| import com.cloud.network.bigswitch.AclData; |
| import com.cloud.network.bigswitch.BigSwitchBcfApi; |
| import com.cloud.network.bigswitch.BigSwitchBcfUtils; |
| import com.cloud.network.bigswitch.TopologyData; |
| import com.cloud.network.dao.BigSwitchBcfDao; |
| import com.cloud.network.dao.FirewallRulesCidrsDao; |
| import com.cloud.network.dao.FirewallRulesDao; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.NetworkDao; |
| 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.PhysicalNetworkVO; |
| import com.cloud.network.resource.BigSwitchBcfResource; |
| import com.cloud.network.rules.FirewallRule; |
| import com.cloud.network.rules.StaticNat; |
| import com.cloud.network.vpc.NetworkACLItem; |
| import com.cloud.network.vpc.NetworkACLItemCidrsDao; |
| import com.cloud.network.vpc.NetworkACLItemDao; |
| import com.cloud.network.vpc.Vpc; |
| import com.cloud.network.vpc.dao.VpcDao; |
| 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.dao.AccountDao; |
| 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.vm.NicProfile; |
| import com.cloud.vm.ReservationContext; |
| import com.cloud.vm.VirtualMachineProfile; |
| import com.cloud.vm.dao.DomainRouterDao; |
| import com.cloud.vm.dao.NicDao; |
| import com.cloud.vm.dao.VMInstanceDao; |
| |
| /** |
| * BigSwitchBcfElement is responsible for creating and plugging a nic into a BCF Segment network. |
| * When a VM is created and needs to be plugged into a BCF Segment network, BigSwitchBcfElement is |
| * called by NetworkOrchestrator to create a "port" and an "attachment" for each nic, and |
| * register them with the controller to be plugged into the corresponding network. It also |
| * removes them when the VM is destroyed. |
| */ |
| @Component |
| public class BigSwitchBcfElement extends AdapterBase implements BigSwitchBcfElementService, |
| ConnectivityProvider, IpDeployer, SourceNatServiceProvider, StaticNatServiceProvider, |
| NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter { |
| private static final Logger s_logger = Logger.getLogger(BigSwitchBcfElement.class); |
| |
| private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities(); |
| |
| @Inject |
| ResourceManager _resourceMgr; |
| @Inject |
| PhysicalNetworkDao _physicalNetworkDao; |
| @Inject |
| PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; |
| @Inject |
| BigSwitchBcfDao _bigswitchBcfDao; |
| @Inject |
| HostDetailsDao _hostDetailsDao; |
| @Inject |
| HostDao _hostDao; |
| @Inject |
| AgentManager _agentMgr; |
| @Inject |
| NetworkDao _networkDao; |
| @Inject |
| DomainRouterDao _routerDao; |
| @Inject |
| NicDao _nicDao; |
| @Inject |
| VMInstanceDao _vmDao; |
| @Inject |
| AccountDao _accountDao; |
| @Inject |
| VpcDao _vpcDao; |
| @Inject |
| NetworkModel _networkModel; |
| @Inject |
| ConfigurationManager _configMgr; |
| @Inject |
| NetworkServiceMapDao _ntwkSrvcDao; |
| @Inject |
| DataCenterDao _zoneDao; |
| @Inject |
| IPAddressDao _ipAddressDao; |
| @Inject |
| IpAddressManager _ipAddrMgr; |
| @Inject |
| VlanDao _vlanDao; |
| @Inject |
| FirewallRulesDao _fwRulesDao; |
| @Inject |
| FirewallRulesCidrsDao _fwCidrsDao; |
| @Inject |
| NetworkACLItemDao _aclItemDao; |
| @Inject |
| NetworkACLItemCidrsDao _aclItemCidrsDao; |
| |
| private BigSwitchBcfUtils _bcfUtils = null; |
| |
| @Override |
| public Map<Service, Map<Capability, String>> getCapabilities() { |
| return capabilities; |
| } |
| |
| @Override |
| public Provider getProvider() { |
| return Provider.BigSwitchBcf; |
| } |
| |
| private boolean canHandle(Network network, Service service) { |
| s_logger.debug("Checking if BigSwitchBcfElement can handle service " + service.getName() + " on network " + network.getDisplayText()); |
| if (network.getBroadcastDomainType() != BroadcastDomainType.Vlan) { |
| return false; |
| } |
| |
| if (!_networkModel.isProviderForNetwork(getProvider(), network.getId())) { |
| s_logger.debug("BigSwitchBcfElement is not a provider for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| if (!_ntwkSrvcDao.canProviderSupportServiceInNetwork(network.getId(), service, BcfConstants.BIG_SWITCH_BCF)) { |
| s_logger.debug("BigSwitchBcfElement 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(this.getClass().getSimpleName(), this); |
| return true; |
| } |
| |
| @Override |
| public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException, InsufficientCapacityException { |
| updateBcfRouter(network); |
| return true; |
| } |
| |
| @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; |
| } |
| |
| bcfUtilsInit(); |
| |
| // get arguments for CreateBcfAttachmentCommand |
| // determine whether this is VPC network or stand-alone network |
| Vpc vpc = null; |
| if(network.getVpcId()!=null){ |
| vpc = _vpcDao.acquireInLockTable(network.getVpcId()); |
| } |
| |
| String tenantId; |
| String tenantName; |
| if (vpc != null) { |
| tenantId = vpc.getUuid(); |
| tenantName = vpc.getName(); |
| _vpcDao.releaseFromLockTable(vpc.getId()); |
| } else { |
| // use account in CS as tenant in BSN |
| // use network id/name as tenant id/name for non-VPC networks |
| tenantId = network.getUuid(); |
| tenantName = network.getName(); |
| } |
| |
| String networkId = network.getUuid(); |
| String hostname = dest.getHost().getName(); |
| String nicId = nic.getUuid(); |
| Integer vlan = Integer.valueOf(BroadcastDomainType.getValue(nic.getIsolationUri())); |
| String ipv4 = nic.getIPv4Address(); |
| String mac = nic.getMacAddress(); |
| long zoneId = network.getDataCenterId(); |
| String vmwareVswitchLabel = _networkModel.getDefaultGuestTrafficLabel(zoneId, HypervisorType.VMware); |
| String[] labelArray = null; |
| String vswitchName = null; |
| if(vmwareVswitchLabel!=null){ |
| labelArray=vmwareVswitchLabel.split(","); |
| vswitchName = labelArray[0]; |
| } |
| |
| // hypervisor type: |
| // kvm: ivs port name |
| // vmware: specific portgroup naming convention |
| String pgName = ""; |
| if (dest.getHost().getHypervisorType() == HypervisorType.KVM){ |
| pgName = hostname; |
| } else if (dest.getHost().getHypervisorType() == HypervisorType.VMware){ |
| pgName = hostname + "-" + vswitchName; |
| } |
| |
| CreateBcfAttachmentCommand cmd = new CreateBcfAttachmentCommand(tenantId, |
| tenantName, networkId, pgName, nicId, vlan, ipv4, mac); |
| |
| _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network); |
| |
| 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"); |
| return false; |
| } |
| |
| bcfUtilsInit(); |
| |
| String networkId = network.getUuid(); |
| String nicId = nic.getUuid(); |
| |
| String tenantId; |
| if(network.getVpcId()!=null) { |
| tenantId = network.getNetworkDomain(); |
| } else { |
| tenantId = networkId; |
| } |
| |
| DeleteBcfAttachmentCommand cmd = new DeleteBcfAttachmentCommand(tenantId, networkId, nicId); |
| |
| _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network); |
| return true; |
| } |
| |
| @Override |
| public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { |
| if (!canHandle(network, Service.Connectivity)) { |
| return false; |
| } |
| 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 { |
| return true; |
| } |
| |
| @Override |
| public boolean canEnableIndividualServices() { |
| return true; |
| } |
| |
| @Override |
| public boolean verifyServicesCombination(Set<Service> services) { |
| if (!services.contains(Service.Connectivity)) { |
| s_logger.warn("Unable to provide services without Connectivity service enabled for this element"); |
| 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 |
| capabilities.put(Service.Connectivity, null); |
| |
| // L3 Support |
| 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 : StaticNat |
| capabilities.put(Service.StaticNat, null); |
| |
| //add network ACL capability |
| Map<Network.Capability, String> networkACLCapabilities = new HashMap<Network.Capability, String>(); |
| networkACLCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,icmp"); |
| capabilities.put(Network.Service.NetworkACL, networkACLCapabilities); |
| |
| // Set capabilities for Firewall service |
| Map<Capability, String> firewallCapabilities = new HashMap<Capability, String>(); |
| firewallCapabilities.put(Capability.TrafficStatistics, "per public ip"); |
| firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp"); |
| firewallCapabilities.put(Capability.SupportedEgressProtocols, "tcp,udp,icmp, all"); |
| firewallCapabilities.put(Capability.SupportedTrafficDirection, "ingress, egress"); |
| firewallCapabilities.put(Capability.MultipleIps, "true"); |
| capabilities.put(Service.Firewall, firewallCapabilities); |
| |
| return capabilities; |
| } |
| |
| @Override |
| @DB |
| public BigSwitchBcfDeviceVO addBigSwitchBcfDevice(AddBigSwitchBcfDeviceCmd cmd) { |
| BigSwitchBcfDeviceVO newBcfDevice; |
| |
| bcfUtilsInit(); |
| |
| ServerResource resource = new BigSwitchBcfResource(); |
| |
| final String deviceName = BcfConstants.BIG_SWITCH_BCF.getName(); |
| NetworkDevice networkDevice = NetworkDevice.getNetworkDevice(deviceName); |
| final Long physicalNetworkId = cmd.getPhysicalNetworkId(); |
| final String hostname = cmd.getHost(); |
| final String username = cmd.getUsername(); |
| final String password = cmd.getPassword(); |
| final Boolean nat = cmd.getNat(); |
| |
| 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"); |
| } |
| ntwkSvcProvider.setFirewallServiceProvided(true); |
| ntwkSvcProvider.setGatewayServiceProvided(true); |
| ntwkSvcProvider.setNetworkAclServiceProvided(true); |
| ntwkSvcProvider.setSourcenatServiceProvided(true); |
| ntwkSvcProvider.setStaticnatServiceProvided(true); |
| |
| if (_bigswitchBcfDao.listByPhysicalNetwork(physicalNetworkId).size() > 1) { |
| throw new CloudRuntimeException("At most two BCF controllers can be configured"); |
| } |
| |
| DataCenterVO zone = _zoneDao.findById(physicalNetwork.getDataCenterId()); |
| String zoneName; |
| if(zone!= null){ |
| zoneName = zone.getName(); |
| } else { |
| zoneName = String.valueOf(zoneId); |
| } |
| |
| Boolean natNow = _bcfUtils.isNatEnabled(); |
| if (!nat && natNow){ |
| throw new CloudRuntimeException("NAT is enabled in existing controller. Enable NAT for new controller or remove existing controller first."); |
| } else if (nat && !natNow){ |
| throw new CloudRuntimeException("NAT is disabled in existing controller. Disable NAT for new controller or remove existing controller first."); |
| } |
| |
| Map<String, String> params = new HashMap<String, String>(); |
| params.put("guid", UUID.randomUUID().toString()); |
| params.put("zoneId", zoneName); |
| params.put("physicalNetworkId", String.valueOf(physicalNetwork.getId())); |
| params.put("name", "BigSwitch Controller - " + cmd.getHost()); |
| params.put("hostname", cmd.getHost()); |
| params.put("username", username); |
| params.put("password", password); |
| params.put("nat", nat.toString()); |
| |
| // FIXME What to do with multiple isolation types |
| params.put("transportzoneisotype", physicalNetwork.getIsolationMethods().get(0).toLowerCase()); |
| Map<String, Object> hostdetails = new HashMap<String, Object>(); |
| hostdetails.putAll(params); |
| |
| try { |
| resource.configure(cmd.getHost(), hostdetails); |
| |
| // store current topology in bcf resource |
| TopologyData topo = _bcfUtils.getTopology(physicalNetwork.getId()); |
| ((BigSwitchBcfResource) resource).setTopology(topo); |
| |
| final Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.L2Networking, params); |
| if (host != null) { |
| newBcfDevice = Transaction.execute(new TransactionCallback<BigSwitchBcfDeviceVO>() { |
| @Override |
| public BigSwitchBcfDeviceVO doInTransaction(TransactionStatus status) { |
| BigSwitchBcfDeviceVO bigswitchBcfDevice = |
| new BigSwitchBcfDeviceVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), |
| deviceName, hostname, username, password, nat, BigSwitchBcfApi.HASH_IGNORE); |
| _bigswitchBcfDao.persist(bigswitchBcfDevice); |
| |
| DetailVO detail = new DetailVO(host.getId(), "bigswitchbcfdeviceid", String.valueOf(bigswitchBcfDevice.getId())); |
| _hostDetailsDao.persist(detail); |
| |
| return bigswitchBcfDevice; |
| } |
| }); |
| } else { |
| throw new CloudRuntimeException("Failed to add BigSwitch BCF Controller Device due to internal error."); |
| } |
| } catch (ConfigurationException e) { |
| throw new CloudRuntimeException(e.getMessage()); |
| } |
| |
| // initial topology sync to newly added BCF controller |
| HostVO bigswitchBcfHost = _hostDao.findById(newBcfDevice.getHostId()); |
| _bcfUtils.syncTopologyToBcfHost(bigswitchBcfHost, nat); |
| |
| return newBcfDevice; |
| } |
| |
| @Override |
| public BigSwitchBcfDeviceResponse createBigSwitchBcfDeviceResponse(BigSwitchBcfDeviceVO bigswitchBcfDeviceVO) { |
| HostVO bigswitchBcfHost = _hostDao.findById(bigswitchBcfDeviceVO.getHostId()); |
| _hostDao.loadDetails(bigswitchBcfHost); |
| |
| BigSwitchBcfDeviceResponse response = new BigSwitchBcfDeviceResponse(); |
| response.setDeviceName(bigswitchBcfDeviceVO.getDeviceName()); |
| PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(bigswitchBcfDeviceVO.getPhysicalNetworkId()); |
| if (pnw != null) { |
| response.setPhysicalNetworkId(pnw.getUuid()); |
| } |
| response.setId(bigswitchBcfDeviceVO.getUuid()); |
| response.setProviderName(bigswitchBcfDeviceVO.getProviderName()); |
| response.setHostName(bigswitchBcfHost.getDetail("hostname")); |
| response.setObjectName("bigswitchbcfdevice"); |
| return response; |
| } |
| |
| @Override |
| public boolean deleteBigSwitchBcfDevice(DeleteBigSwitchBcfDeviceCmd cmd) { |
| Long bigswitchBcfDeviceId = cmd.getBigSwitchBcfDeviceId(); |
| BigSwitchBcfDeviceVO bigswitchBcfDevice = _bigswitchBcfDao.findById(bigswitchBcfDeviceId); |
| if (bigswitchBcfDevice == null) { |
| throw new InvalidParameterValueException("Could not find a BigSwitch Controller with id " + bigswitchBcfDevice); |
| } |
| |
| HostVO bigswitchHost = _hostDao.findById(bigswitchBcfDevice.getHostId()); |
| Long hostId = bigswitchHost.getId(); |
| |
| bigswitchHost.setResourceState(ResourceState.Maintenance); |
| _hostDao.update(hostId, bigswitchHost); |
| _resourceMgr.deleteHost(hostId, false, false); |
| |
| _bigswitchBcfDao.remove(bigswitchBcfDeviceId); |
| return true; |
| } |
| |
| @Override |
| public List<BigSwitchBcfDeviceVO> listBigSwitchBcfDevices(ListBigSwitchBcfDevicesCmd cmd) { |
| Long physicalNetworkId = cmd.getPhysicalNetworkId(); |
| Long bigswitchBcfDeviceId = cmd.getBigSwitchBcfDeviceId(); |
| List<BigSwitchBcfDeviceVO> responseList = new ArrayList<BigSwitchBcfDeviceVO>(); |
| |
| if (physicalNetworkId == null && bigswitchBcfDeviceId == null) { |
| throw new InvalidParameterValueException("Either physical network Id or bigswitch device Id must be specified"); |
| } |
| |
| if (bigswitchBcfDeviceId != null) { |
| BigSwitchBcfDeviceVO bigswitchBcfDevice = _bigswitchBcfDao.findById(bigswitchBcfDeviceId); |
| if (bigswitchBcfDevice == null) { |
| throw new InvalidParameterValueException("Could not find BigSwitch controller with id: " + bigswitchBcfDevice); |
| } |
| responseList.add(bigswitchBcfDevice); |
| } else { |
| PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); |
| if (physicalNetwork == null) { |
| throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId); |
| } |
| responseList = _bigswitchBcfDao.listByPhysicalNetwork(physicalNetworkId); |
| } |
| |
| return responseList; |
| } |
| |
| @Override |
| public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { |
| return null; |
| } |
| |
| @Override |
| public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details, List<String> hostTags) { |
| if (!(startup[0] instanceof StartupBigSwitchBcfCommand)) { |
| return null; |
| } |
| |
| BigSwitchBcfResource bcfResource = (BigSwitchBcfResource) resource; |
| bcfUtilsInit(); |
| |
| if(_bcfUtils.getTopology()!=null){ |
| bcfResource.setTopology(_bcfUtils.getTopology()); |
| } |
| |
| 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); |
| } |
| |
| @Override |
| public List<Class<?>> getCommands() { |
| List<Class<?>> cmdList = new ArrayList<Class<?>>(); |
| cmdList.add(AddBigSwitchBcfDeviceCmd.class); |
| cmdList.add(DeleteBigSwitchBcfDeviceCmd.class); |
| cmdList.add(ListBigSwitchBcfDevicesCmd.class); |
| return cmdList; |
| } |
| |
| @Override |
| public IpDeployer getIpDeployer(Network network) { |
| return this; |
| } |
| |
| @Override |
| public boolean applyStaticNats(Network network, |
| List<? extends StaticNat> rules) |
| throws ResourceUnavailableException { |
| bcfUtilsInit(); |
| |
| _bcfUtils.listACLbyNetwork(network); |
| |
| Vpc vpc = null; |
| if(network.getVpcId()!=null){ |
| vpc = _vpcDao.acquireInLockTable(network.getVpcId()); |
| } |
| |
| String tenantId; |
| if (vpc != null) { |
| tenantId = vpc.getUuid(); |
| _vpcDao.releaseFromLockTable(vpc.getId()); |
| } else { |
| // use account in CS as tenant in BSN |
| // use network uuid as tenantId for non-VPC networks |
| tenantId = network.getUuid(); |
| } |
| |
| for (StaticNat rule: rules){ |
| String srcIp = _ipAddressDao.findById(rule.getSourceIpAddressId()).getAddress().addr(); |
| String dstIp = rule.getDestIpAddress(); |
| String mac = rule.getSourceMacAddress(); |
| if(!rule.isForRevoke()) { |
| s_logger.debug("BCF enables static NAT for public IP: " + srcIp + " private IP " + dstIp |
| + " mac " + mac); |
| CreateBcfStaticNatCommand cmd = new CreateBcfStaticNatCommand( |
| tenantId, network.getUuid(), dstIp, srcIp, mac); |
| |
| _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network); |
| } else { |
| s_logger.debug("BCF removes static NAT for public IP: " + srcIp + " private IP " + dstIp |
| + " mac " + mac); |
| DeleteBcfStaticNatCommand cmd = new DeleteBcfStaticNatCommand(tenantId, srcIp); |
| |
| _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network); |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean applyIps(Network network, |
| List<? extends PublicIpAddress> ipAddress, Set<Service> services) |
| throws ResourceUnavailableException { |
| return false; |
| } |
| |
| @Override |
| public boolean applyNetworkACLs(Network network, |
| List<? extends NetworkACLItem> rules) |
| throws ResourceUnavailableException { |
| SubnetUtils utils; |
| String cidr = null; |
| List<String> cidrList; |
| for(NetworkACLItem r: rules){ |
| if(r.getState()==NetworkACLItem.State.Revoke){ |
| continue; |
| } |
| cidrList = r.getSourceCidrList(); |
| if(cidrList != null){ |
| if(cidrList.size()>1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())){ |
| throw new ResourceUnavailableException("One CIDR and one port only please.", |
| Network.class, network.getId()); |
| } else { |
| cidr = cidrList.get(0); |
| } |
| } |
| if (cidr == null || cidr.equalsIgnoreCase("0.0.0.0/0")) { |
| cidr = ""; |
| } else { |
| utils = new SubnetUtils(cidr); |
| if(!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())){ |
| throw new ResourceUnavailableException("Invalid CIDR in Network ACL rule.", |
| Network.class, network.getId()); |
| } |
| } |
| } |
| updateBcfRouter(network); |
| return true; |
| } |
| |
| @Override |
| public boolean applyFWRules(Network network, |
| List<? extends FirewallRule> rules) |
| throws ResourceUnavailableException { |
| SubnetUtils utils; |
| String cidr = null; |
| List<String> cidrList; |
| for(FirewallRule r: rules){ |
| if(r.getState()==FirewallRule.State.Revoke){ |
| continue; |
| } |
| cidrList = r.getSourceCidrList(); |
| if(cidrList != null){ |
| if(cidrList.size()>1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())){ |
| throw new ResourceUnavailableException("One CIDR and one port only please.", |
| Network.class, network.getId()); |
| } else { |
| cidr = cidrList.get(0); |
| } |
| } |
| if (cidr == null || cidr.equalsIgnoreCase("0.0.0.0/0")) { |
| cidr = ""; |
| } else { |
| utils = new SubnetUtils(cidr); |
| if(!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())){ |
| throw new ResourceUnavailableException("Invalid CIDR in Firewall rule.", |
| Network.class, network.getId()); |
| } |
| } |
| } |
| updateBcfRouter(network); |
| return true; |
| } |
| |
| private void updateBcfRouter(Network network) throws IllegalArgumentException{ |
| bcfUtilsInit(); |
| |
| Vpc vpc = null; |
| if(network.getVpcId()!=null){ |
| vpc = _vpcDao.acquireInLockTable(network.getVpcId()); |
| } |
| |
| String tenantId; |
| if (vpc != null) { |
| tenantId = vpc.getUuid(); |
| _vpcDao.releaseFromLockTable(vpc.getId()); |
| } else { |
| tenantId = network.getUuid(); |
| } |
| |
| UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand(tenantId); |
| |
| List<AclData> aclList = _bcfUtils.listACLbyNetwork(network); |
| for(AclData acl: aclList){ |
| cmd.addAcl(acl); |
| } |
| |
| if(vpc != null){ |
| cmd.setPublicIp(_bcfUtils.getPublicIpByVpc(vpc)); |
| } else { |
| cmd.setPublicIp(_bcfUtils.getPublicIpByNetwork(network)); |
| } |
| |
| BcfAnswer answer = _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network); |
| if(answer != null && !answer.getResult()){ |
| throw new IllegalArgumentException("Illegal router update arguments"); |
| } |
| } |
| |
| private void bcfUtilsInit(){ |
| if (_bcfUtils == null) { |
| _bcfUtils = new BigSwitchBcfUtils(_networkDao, _nicDao, |
| _vmDao, _hostDao, _vpcDao, _bigswitchBcfDao, |
| _agentMgr, _vlanDao, _ipAddressDao, _fwRulesDao, |
| _fwCidrsDao, _aclItemDao, _aclItemCidrsDao, _networkModel); |
| } |
| } |
| } |