// Copyright 2012 Citrix Systems, Inc. Licensed under the // Apache License, Version 2.0 (the "License"); you may not use this // file except in compliance with the License. Citrix Systems, Inc. // reserves all rights not expressly granted by 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. // // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.router; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.PlugNicAnswer; import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.SetSourceNatAnswer; import com.cloud.agent.api.SetupGuestNetworkAnswer; import com.cloud.agent.api.SetupGuestNetworkCommand; import com.cloud.agent.api.UnPlugNicAnswer; import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.api.routing.IpAssocVpcCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetSourceNatCommand; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NetworkACLTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; import com.cloud.dc.DataCenterVO; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkService; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; import com.cloud.network.VirtualRouterProvider; import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.firewall.NetworkACLService; import com.cloud.network.rules.NetworkACL; import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.Dao.VpcDao; import com.cloud.network.vpc.Dao.VpcOfferingDao; import com.cloud.user.Account; import com.cloud.utils.Pair; import com.cloud.utils.component.Inject; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile.Param; import com.cloud.vm.dao.VMInstanceDao; /** * @author Alena Prokharchyk */ @Local(value = {VpcVirtualNetworkApplianceManager.class, VpcVirtualNetworkApplianceService.class}) public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplianceManagerImpl implements VpcVirtualNetworkApplianceManager{ private static final Logger s_logger = Logger.getLogger(VpcVirtualNetworkApplianceManagerImpl.class); @Inject VpcDao _vpcDao = null; @Inject VpcOfferingDao _vpcOffDao = null; @Inject PhysicalNetworkDao _pNtwkDao = null; @Inject NetworkService _ntwkService = null; @Inject NetworkACLService _networkACLService = null; @Inject VMInstanceDao _vmDao; @Override public List deployVirtualRouterInVpc(Vpc vpc, DeployDestination dest, Account owner, Map params) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { List routers = findOrDeployVirtualRouterInVpc(vpc, dest, owner, params); return startRouters(params, routers); } @DB protected List findOrDeployVirtualRouterInVpc(Vpc vpc, DeployDestination dest, Account owner, Map params) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { s_logger.debug("Deploying Virtual Router in VPC "+ vpc); Vpc vpcLock = _vpcDao.acquireInLockTable(vpc.getId()); if (vpcLock == null) { throw new ConcurrentOperationException("Unable to lock vpc " + vpc.getId()); } //1) Get deployment plan and find out the list of routers Pair> planAndRouters = getDeploymentPlanAndRouters(vpc.getId(), dest); DeploymentPlan plan = planAndRouters.first(); List routers = planAndRouters.second(); try { //2) Return routers if exist if (routers.size() >= 1) { return routers; } Long offeringId = _vpcOffDao.findById(vpc.getVpcOfferingId()).getServiceOfferingId(); if (offeringId == null) { offeringId = _offering.getId(); } //3) Deploy Virtual Router List pNtwks = _pNtwkDao.listByZone(vpc.getZoneId()); VirtualRouterProvider vpcVrProvider = null; for (PhysicalNetwork pNtwk : pNtwks) { PhysicalNetworkServiceProvider provider = _physicalProviderDao.findByServiceProvider(pNtwk.getId(), VirtualRouterProviderType.VPCVirtualRouter.toString()); if (provider == null) { throw new CloudRuntimeException("Cannot find service provider " + VirtualRouterProviderType.VPCVirtualRouter.toString() + " in physical network " + pNtwk.getId()); } vpcVrProvider = _vrProviderDao.findByNspIdAndType(provider.getId(), VirtualRouterProviderType.VPCVirtualRouter); if (vpcVrProvider != null) { break; } } PublicIp sourceNatIp = _networkMgr.assignSourceNatIpAddressToVpc(owner, vpc); DomainRouterVO router = deployVpcRouter(owner, dest, plan, params, false, vpcVrProvider, offeringId, vpc.getId(), sourceNatIp); routers.add(router); } finally { if (vpcLock != null) { _vpcDao.releaseFromLockTable(vpc.getId()); } } return routers; } protected Pair> getDeploymentPlanAndRouters(long vpcId, DeployDestination dest) { long dcId = dest.getDataCenter().getId(); DeploymentPlan plan = new DataCenterDeployment(dcId); List routers = _routerDao.listRoutersByVpcId(vpcId); return new Pair>(plan, routers); } @Override public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { if (network.getTrafficType() != TrafficType.Guest) { s_logger.warn("Network " + network + " is not of type " + TrafficType.Guest); return false; } //Add router to the Guest network boolean result = true; try { if (!_routerDao.isRouterPartOfGuestNetwork(router.getId(), network.getId())) { DomainRouterVO routerVO = _routerDao.findById(router.getId()); _routerDao.addRouterToGuestNetwork(routerVO, network); } NicProfile guestNic = _itMgr.addVmToNetwork(router, network, null); //setup guest network if (guestNic != null) { result = setupVpcGuestNetwork(network, router, true, guestNic); } else { s_logger.warn("Failed to add router " + router + " to guest network " + network); result = false; } } catch (Exception ex) { s_logger.warn("Failed to add router " + router + " to network " + network + " due to ", ex); result = false; } finally { if (!result) { s_logger.debug("Removing the router " + router + " from network " + network + " as a part of cleanup"); if (removeRouterFromGuestNetwork(router, network, isRedundant)) { s_logger.debug("Removed the router " + router + " from network " + network + " as a part of cleanup"); } else { s_logger.warn("Failed to remove the router " + router + " from network " + network + " as a part of cleanup"); } } } return result; } @Override public boolean removeRouterFromGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, ResourceUnavailableException { if (network.getTrafficType() != TrafficType.Guest) { s_logger.warn("Network " + network + " is not of type " + TrafficType.Guest); return false; } //Check if router is a part of the Guest network if (!_networkMgr.isVmPartOfNetwork(router.getId(), network.getId())) { s_logger.debug("Router " + router + " is not a part of the Guest network " + network); return true; } boolean result = setupVpcGuestNetwork(network, router, false, _networkMgr.getNicProfile(router, network.getId())); if (!result) { s_logger.warn("Failed to destroy guest network config " + network + " on router " + router); return false; } result = result && _itMgr.removeVmFromNetwork(router, network, null); if (result) { if (result) { //check if router is already part of network if (_routerDao.isRouterPartOfGuestNetwork(router.getId(), network.getId())) { s_logger.debug("Removing router " + router + " from network" + network); _routerDao.removeRouterFromNetwork(router.getId(), network.getId()); } } } return result; } protected boolean addPublicIpToVpc(VirtualRouter router, Network publicNetwork, PublicIp ipAddress) throws ConcurrentOperationException,ResourceUnavailableException, InsufficientCapacityException { if (publicNetwork.getTrafficType() != TrafficType.Public) { s_logger.warn("Network " + publicNetwork + " is not of type " + TrafficType.Public); return false; } //Add router to the Public network boolean result = true; try { NicProfile defaultNic = new NicProfile(); if (ipAddress.isSourceNat()) { defaultNic.setDefaultNic(true); } defaultNic.setIp4Address(ipAddress.getAddress().addr()); defaultNic.setGateway(ipAddress.getGateway()); defaultNic.setNetmask(ipAddress.getNetmask()); defaultNic.setMacAddress(ipAddress.getMacAddress()); defaultNic.setBroadcastType(BroadcastDomainType.Vlan); defaultNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ipAddress.getVlanTag())); defaultNic.setIsolationUri(IsolationType.Vlan.toUri(ipAddress.getVlanTag())); NicProfile publicNic = _itMgr.addVmToNetwork(router, publicNetwork, defaultNic); //setup public network if (publicNic != null) { publicNic.setDefaultNic(true); if (ipAddress != null) { IPAddressVO ipVO = _ipAddressDao.findById(ipAddress.getId()); PublicIp publicIp = new PublicIp(ipVO, _vlanDao.findById(ipVO.getVlanId()), NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress())); result = associtePublicIpInVpc(publicNetwork, router, false, publicIp); } } else { result = false; s_logger.warn("Failed to plug nic for " + ipAddress + " to VPC router " + router); } } catch (Exception ex) { s_logger.warn("Failed to add ip address " + ipAddress + " from the public network " + publicNetwork + " to VPC router " + router + " due to ", ex); result = false; } return result; } protected boolean removePublicIpFromVpcRouter(VirtualRouter router, Network publicNetwork, PublicIp ipAddress) throws ConcurrentOperationException, ResourceUnavailableException { if (publicNetwork.getTrafficType() != TrafficType.Public) { s_logger.warn("Network " + publicNetwork + " is not of type " + TrafficType.Public); return false; } boolean result = true; IPAddressVO ipVO = _ipAddressDao.findById(ipAddress.getId()); _networkMgr.markIpAsUnavailable(ipVO.getId()); PublicIp publicIp = new PublicIp(ipVO, _vlanDao.findById(ipVO.getVlanId()), NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress())); result = associtePublicIpInVpc(publicNetwork, router, false, publicIp); if (!result) { s_logger.warn("Failed to disassociate public ip " + ipAddress + " from router " + router); return false; } URI broadcastUri = BroadcastDomainType.Vlan.toUri(ipAddress.getVlanTag()); if (_itMgr.removeVmFromNetwork(router, publicNetwork, broadcastUri)) { s_logger.debug("Successfully removed router " + router + " from vlan " + ipAddress.getVlanTag() +" of public network " + publicNetwork); return true; } else { s_logger.warn("Failed to remove router " + router + " from vlan " + ipAddress.getVlanTag() +" of public network " + publicNetwork); return false; } } protected boolean associtePublicIpInVpc(Network network, VirtualRouter router, boolean add, PublicIp ipAddress) throws ConcurrentOperationException, ResourceUnavailableException{ List publicIps = new ArrayList(1); publicIps.add(ipAddress); Commands cmds = new Commands(OnError.Stop); createVpcAssociateIPCommands(router, publicIps, cmds); if (sendCommandsToRouter(router, cmds)) { s_logger.debug("Successfully applied ip association for ip " + ipAddress + " in vpc network " + network); return true; } else { s_logger.warn("Failed to associate ip address " + ipAddress + " in vpc network " + network); return false; } } protected DomainRouterVO deployVpcRouter(Account owner, DeployDestination dest, DeploymentPlan plan, Map params, boolean isRedundant, VirtualRouterProvider vrProvider, long svcOffId, Long vpcId, PublicIp sourceNatIp) throws ConcurrentOperationException, InsufficientAddressCapacityException, InsufficientServerCapacityException, InsufficientCapacityException, StorageUnavailableException, ResourceUnavailableException { DomainRouterVO router = super.deployRouter(owner, dest, plan, params, isRedundant, vrProvider, svcOffId, vpcId, sourceNatIp, false, true, null, null); //Plug public nic if (router != null && sourceNatIp != null) { Network publicNetwork = _networkDao.listByZoneAndTrafficType(dest.getDataCenter().getId(), TrafficType.Public).get(0); if (!addPublicIpToVpc(router, publicNetwork, sourceNatIp)) { s_logger.warn("Failed to add router " + router + " to public network in zone " + dest.getDataCenter() + " cleaninig up"); destroyRouter(router.getId()); return null; } } return router; } @Override public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { boolean result = true; try { PlugNicCommand plugNicCmd = new PlugNicCommand(vm, nic); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("plugnic", plugNicCmd); _agentMgr.send(dest.getHost().getId(), cmds); PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class); if (!(plugNicAnswer != null && plugNicAnswer.getResult())) { s_logger.warn("Unable to plug nic for vm " + vm.getHostName()); result = false; } } catch (OperationTimedoutException e) { throw new AgentUnavailableException("Unable to plug nic for router " + vm.getHostName() + " in network " + network, dest.getHost().getId(), e); } return result; } @Override public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException { boolean result = true; DomainRouterVO router = _routerDao.findById(vm.getId()); try { UnPlugNicCommand unplugNicCmd = new UnPlugNicCommand(vm, nic); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("unplugnic", unplugNicCmd); _agentMgr.send(dest.getHost().getId(), cmds); UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class); if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) { s_logger.warn("Unable to unplug nic from router " + router); result = false; } } catch (OperationTimedoutException e) { throw new AgentUnavailableException("Unable to unplug nic from rotuer " + router + " from network " + network, dest.getHost().getId(), e); } return result; } protected boolean setupVpcGuestNetwork(Network network, VirtualRouter router, boolean add, NicProfile guestNic) throws ConcurrentOperationException, ResourceUnavailableException{ boolean result = true; SetupGuestNetworkCommand setupCmd = createSetupGuestNetworkCommand(router, add, guestNic); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("setupguestnetwork", setupCmd); sendCommandsToRouter(router, cmds); SetupGuestNetworkAnswer setupAnswer = cmds.getAnswer(SetupGuestNetworkAnswer.class); String setup = add ? "set" : "destroy"; if (!(setupAnswer != null && setupAnswer.getResult())) { s_logger.warn("Unable to " + setup + " guest network on router " + router); result = false; } return result; } protected SetupGuestNetworkCommand createSetupGuestNetworkCommand(VirtualRouter router, boolean add, NicProfile guestNic) { Network network = _networkMgr.getNetwork(guestNic.getNetworkId()); String defaultDns1 = null; String defaultDns2 = null; boolean dnsProvided = _networkMgr.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, Provider.VPCVirtualRouter); boolean dhcpProvided = _networkMgr.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, Provider.VPCVirtualRouter); boolean setupDns = dnsProvided || dhcpProvided; if (setupDns) { defaultDns1 = guestNic.getDns1(); defaultDns2 = guestNic.getDns2(); } Nic nic = _nicDao.findByInstanceIdAndNetworkId(network.getId(), router.getId()); String networkDomain = network.getNetworkDomain(); String dhcpRange = getGuestDhcpRange(guestNic, network, _configMgr.getZone(network.getDataCenterId())); VirtualMachine vm = _vmDao.findById(router.getId()); NicProfile nicProfile = _networkMgr.getNicProfile(router, nic.getNetworkId()); SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, false, null, defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile, router.getHypervisorType())); long guestVlanTag = Long.parseLong(network.getBroadcastUri().getHost()); String brd = NetUtils.long2Ip(NetUtils.ip2Long(guestNic.getIp4Address()) | ~NetUtils.ip2Long(guestNic.getNetmask())); setupCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); setupCmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(network.getId(), router.getId())); setupCmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); setupCmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, network.getGateway()); setupCmd.setAccessDetail(NetworkElementCommand.GUEST_BRIDGE, brd); setupCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); return setupCmd; } private void createVpcAssociateIPCommands(final VirtualRouter router, final List ips, Commands cmds) { Pair sourceNatIpAdd = null; Boolean addSourceNat = null; // Ensure that in multiple vlans case we first send all ip addresses of vlan1, then all ip addresses of vlan2, etc.. Map> vlanIpMap = new HashMap>(); for (final PublicIpAddress ipAddress : ips) { String vlanTag = ipAddress.getVlanTag(); ArrayList ipList = vlanIpMap.get(vlanTag); if (ipList == null) { ipList = new ArrayList(); } //VR doesn't support release for sourceNat IP address; so reset the state if (ipAddress.isSourceNat() && ipAddress.getState() == IpAddress.State.Releasing) { ipAddress.setState(IpAddress.State.Allocated); } ipList.add(ipAddress); vlanIpMap.put(vlanTag, ipList); } for (Map.Entry> vlanAndIp : vlanIpMap.entrySet()) { List ipAddrList = vlanAndIp.getValue(); // Get network rate - required for IpAssoc Integer networkRate = _networkMgr.getNetworkRate(ipAddrList.get(0).getNetworkId(), router.getId()); Network network = _networkMgr.getNetwork(ipAddrList.get(0).getNetworkId()); IpAddressTO[] ipsToSend = new IpAddressTO[ipAddrList.size()]; int i = 0; for (final PublicIpAddress ipAddr : ipAddrList) { boolean add = (ipAddr.getState() == IpAddress.State.Releasing ? false : true); IpAddressTO ip = new IpAddressTO(ipAddr.getAccountId(), ipAddr.getAddress().addr(), add, false, ipAddr.isSourceNat(), ipAddr.getVlanTag(), ipAddr.getGateway(), ipAddr.getNetmask(), ipAddr.getMacAddress(), null, networkRate, ipAddr.isOneToOneNat()); ip.setTrafficType(network.getTrafficType()); ip.setNetworkName(_networkMgr.getNetworkTag(router.getHypervisorType(), network)); ipsToSend[i++] = ip; if (ipAddr.isSourceNat()) { sourceNatIpAdd = new Pair(ip, ipAddr.getNetworkId()); addSourceNat = add; } } IpAssocVpcCommand cmd = new IpAssocVpcCommand(ipsToSend); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(ipAddrList.get(0).getNetworkId(), router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); cmds.addCommand("IPAssocVpcCommand", cmd); } //set source nat ip if (sourceNatIpAdd != null) { IpAddressTO sourceNatIp = sourceNatIpAdd.first(); SetSourceNatCommand cmd = new SetSourceNatCommand(sourceNatIp, addSourceNat); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); cmds.addCommand("SetSourceNatCommand", cmd); } } protected NicTO getNicTO(final VirtualRouter router, Long guestNetworkId) { VirtualMachine vm = _vmDao.findById(router.getId()); NicProfile nicProfile = _networkMgr.getNicProfile(router, guestNetworkId); return _itMgr.toNicTO(nicProfile, router.getHypervisorType()); } @Override public boolean associateIP(Network network, final List ipAddress, List routers) throws ResourceUnavailableException { if (ipAddress == null || ipAddress.isEmpty()) { s_logger.debug("No ip association rules to be applied for network " + network.getId()); return true; } //1) check which nics need to be plugged and plug them for (PublicIpAddress ip : ipAddress) { for (VirtualRouter router : routers) { URI broadcastUri = BroadcastDomainType.Vlan.toUri(ip.getVlanTag()); Nic nic = _nicDao.findByInstanceIdNetworkIdAndBroadcastUri(network.getId(), router.getId(), broadcastUri.toString()); if (nic != null) { //have to plug the nic(s) NicProfile defaultNic = new NicProfile(); if (ip.isSourceNat()) { defaultNic.setDefaultNic(true); } defaultNic.setIp4Address(ip.getAddress().addr()); defaultNic.setGateway(ip.getGateway()); defaultNic.setNetmask(ip.getNetmask()); defaultNic.setMacAddress(ip.getMacAddress()); defaultNic.setBroadcastType(BroadcastDomainType.Vlan); defaultNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); defaultNic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); NicProfile publicNic = null; Network publicNtwk = null; try { publicNtwk = _networkMgr.getNetwork(ip.getNetworkId()); publicNic = _itMgr.addVmToNetwork(router, publicNtwk, defaultNic); } catch (ConcurrentOperationException e) { s_logger.warn("Failed to add router " + router + " to vlan " + ip.getVlanTag() + " in public network " + publicNtwk + " due to ", e); } catch (InsufficientCapacityException e) { s_logger.warn("Failed to add router " + router + " to vlan " + ip.getVlanTag() + " in public network " + publicNtwk + " due to ", e); } finally { if (publicNic == null) { s_logger.warn("Failed to add router " + router + " to vlan " + ip.getVlanTag() + " in public network " + publicNtwk); return false; } } } } } //2) apply the ips return applyRules(network, routers, "vpc ip association", false, null, false, new RuleApplier() { @Override public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { Commands cmds = new Commands(OnError.Continue); createVpcAssociateIPCommands(router, ipAddress, cmds); return sendCommandsToRouter(router, cmds); } }); } @Override public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { if (profile.getVirtualMachine().getVpcId() != null) { //remove public and guest nics as we will plug them later Iterator it = profile.getNics().iterator(); while (it.hasNext()) { NicProfile nic = it.next(); if (nic.getTrafficType() == TrafficType.Public || nic.getTrafficType() == TrafficType.Guest) { s_logger.debug("Removing nic of type " + nic.getTrafficType() + " from the nics passed on vm start. " + "The nic will be plugged later"); it.remove(); } } } return super.finalizeVirtualMachineProfile(profile, dest, context); } @Override public boolean applyNetworkACLs(Network network, final List rules, List routers) throws ResourceUnavailableException { if (rules == null || rules.isEmpty()) { s_logger.debug("No network ACLs to be applied for network " + network.getId()); return true; } return applyRules(network, routers, "network acls", false, null, false, new RuleApplier() { @Override public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { return sendNetworkACLs(router, (List)rules, network.getId()); } }); } protected boolean sendNetworkACLs(VirtualRouter router, List rules, long guestNetworkId) throws ResourceUnavailableException { Commands cmds = new Commands(OnError.Continue); createNetworkACLsCommands(rules, router, cmds, guestNetworkId); return sendCommandsToRouter(router, cmds); } private void createNetworkACLsCommands(List rules, VirtualRouter router, Commands cmds, long guestNetworkId) { List rulesTO = null; String guestVlan = null; Network guestNtwk = _networkDao.findById(guestNetworkId); URI uri = guestNtwk.getBroadcastUri(); if (uri != null) { guestVlan = guestNtwk.getBroadcastUri().getHost(); } if (rules != null) { rulesTO = new ArrayList(); for (NetworkACL rule : rules) { NetworkACLTO ruleTO = new NetworkACLTO(rule, guestVlan, rule.getTrafficType()); rulesTO.add(ruleTO); } } SetNetworkACLCommand cmd = new SetNetworkACLCommand(rulesTO, getNicTO(router, guestNetworkId)); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(guestNetworkId, router.getId())); cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, guestVlan); cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); cmds.addCommand(cmd); } @Override public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile profile) { DomainRouterVO router = profile.getVirtualMachine(); boolean isVpc = (router.getVpcId() != null); if (!isVpc) { return super.finalizeCommandsOnStart(cmds, profile); } //1) FORM SSH CHECK COMMAND NicProfile controlNic = getControlNic(profile); if (controlNic == null) { s_logger.error("Control network doesn't exist for the router " + router); return false; } finalizeSshAndVersionAndNetworkUsageOnStart(cmds, profile, router, controlNic); //2) FORM PLUG NIC COMMANDS Map guestNics = new HashMap(); Map publicNics = new HashMap(); List routerNics = _nicDao.listByVmId(profile.getId()); for (Nic routerNic : routerNics) { Network network = _networkMgr.getNetwork(routerNic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest) { guestNics.put(routerNic, network); } else if (network.getTrafficType() == TrafficType.Public) { publicNics.put(routerNic, network); } } try { //add VPC router to public networks List publicIps = new ArrayList(1); for (Nic publicNic : publicNics.keySet()) { Network publicNtwk = publicNics.get(publicNic); IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(publicNtwk.getId(), publicNic.getIp4Address()); if (userIp.isSourceNat()) { PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress())); publicIps.add(publicIp); } PlugNicCommand plugNicCmd = new PlugNicCommand(_itMgr.toVmTO(profile), getNicTO(router, publicNic.getNetworkId())); cmds.addCommand(plugNicCmd); } // create ip assoc for source nat if (!publicIps.isEmpty()) { createVpcAssociateIPCommands(router, publicIps, cmds); } for (Nic guestNic : guestNics.keySet()) { //plug guest nic PlugNicCommand plugNicCmd = new PlugNicCommand(_itMgr.toVmTO(profile), getNicTO(router, guestNic.getNetworkId())); cmds.addCommand(plugNicCmd); if (!_networkMgr.isPrivateGateway(guestNic)) { //set guest network VirtualMachine vm = _vmDao.findById(router.getId()); NicProfile nicProfile = _networkMgr.getNicProfile(vm, guestNic.getNetworkId()); SetupGuestNetworkCommand setupCmd = createSetupGuestNetworkCommand(router, true, nicProfile); cmds.addCommand(setupCmd); } else { //set source nat Integer networkRate = _networkMgr.getNetworkRate(guestNic.getNetworkId(), router.getId()); IpAddressTO ip = new IpAddressTO(Account.ACCOUNT_ID_SYSTEM, guestNic.getIp4Address(), true, false, true, guestNic.getBroadcastUri().getHost(), guestNic.getGateway(), guestNic.getNetmask(), guestNic.getMacAddress(), null, networkRate, false); Network network = _networkMgr.getNetwork(guestNic.getNetworkId()); ip.setTrafficType(network.getTrafficType()); SetSourceNatCommand cmd = new SetSourceNatCommand(ip, true); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); cmds.addCommand(cmd); } } } catch (Exception ex) { s_logger.warn("Failed to add router " + router + " to network due to exception ", ex); return false; } //3) REPROGRAM GUEST NETWORK boolean reprogramGuestNtwks = true; if (profile.getParameter(Param.ReProgramGuestNetworks) != null && (Boolean) profile.getParameter(Param.ReProgramGuestNetworks) == false) { reprogramGuestNtwks = false; } VirtualRouterProvider vrProvider = _vrProviderDao.findById(router.getElementId()); if (vrProvider == null) { throw new CloudRuntimeException("Cannot find related virtual router provider of router: " + router.getHostName()); } Provider provider = Network.Provider.getProvider(vrProvider.getType().toString()); if (provider == null) { throw new CloudRuntimeException("Cannot find related provider of virtual router provider: " + vrProvider.getType().toString()); } List routerGuestNtwkIds = _routerDao.getRouterNetworks(router.getId()); for (Long guestNetworkId : routerGuestNtwkIds) { if (reprogramGuestNtwks) { finalizeIpAssocForNetwork(cmds, router, provider, guestNetworkId); finalizeNetworkRulesForNetwork(cmds, router, provider, guestNetworkId); } finalizeUserDataAndDhcpOnStart(cmds, router, provider, guestNetworkId); } return true; } @Override protected void finalizeNetworkRulesForNetwork(Commands cmds, DomainRouterVO router, Provider provider, Long guestNetworkId) { super.finalizeNetworkRulesForNetwork(cmds, router, provider, guestNetworkId); if (_networkMgr.isProviderSupportServiceInNetwork(guestNetworkId, Service.Firewall, Provider.VPCVirtualRouter)) { List networkACLs = _networkACLService.listNetworkACLs(guestNetworkId); s_logger.debug("Found " + networkACLs.size() + " network ACLs to apply as a part of VPC VR " + router + " start for guest network id=" + guestNetworkId); if (!networkACLs.isEmpty()) { createNetworkACLsCommands((List)networkACLs, router, cmds, guestNetworkId); } } } @Override public boolean setupPrivateGateway(PrivateGateway gateway, VirtualRouter router) throws ConcurrentOperationException, ResourceUnavailableException { boolean result = true; try { Network network = _networkMgr.getNetwork(gateway.getNetworkId()); NicProfile guestNic = _itMgr.addVmToNetwork(router, network, null); //setup source nat if (guestNic != null) { result = setupVpcPrivateNetwork(router, true, guestNic); } else { s_logger.warn("Failed to setup gateway " + gateway + " on router " + router + " with the source nat"); result = false; } } catch (Exception ex) { s_logger.warn("Failed to create private gateway " + gateway + " on router " + router + " due to ", ex); result = false; } finally { if (!result) { s_logger.debug("Removing gateway " + gateway + " from router " + router + " as a part of cleanup"); if (destroyPrivateGateway(gateway, router)) { s_logger.debug("Removed the gateway " + gateway + " from router " + router + " as a part of cleanup"); } else { s_logger.warn("Failed to remove the gateway " + gateway + " from router " + router + " as a part of cleanup"); } } } return result; } /** * @param router * @param add * @param privateNic * @return * @throws AgentUnavailableException */ protected boolean setupVpcPrivateNetwork(VirtualRouter router, boolean add, NicProfile privateNic) throws AgentUnavailableException { boolean result = true; Commands cmds = new Commands(OnError.Stop); Integer networkRate = _networkMgr.getNetworkRate(privateNic.getNetworkId(), router.getId()); IpAddressTO ip = new IpAddressTO(Account.ACCOUNT_ID_SYSTEM, privateNic.getIp4Address(), add, false, true, privateNic.getBroadCastUri().getHost(), privateNic.getGateway(), privateNic.getNetmask(), privateNic.getMacAddress(), null, networkRate, false); Network network = _networkMgr.getNetwork(privateNic.getNetworkId()); ip.setTrafficType(network.getTrafficType()); SetSourceNatCommand cmd = new SetSourceNatCommand(ip, add); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); cmds.addCommand("SetSourceNatCommand", cmd); sendCommandsToRouter(router, cmds); SetSourceNatAnswer setupAnswer = cmds.getAnswer(SetSourceNatAnswer.class); String setup = add ? "set" : "destroy"; if (!(setupAnswer != null && setupAnswer.getResult())) { s_logger.warn("Unable to " + setup + " source nat for private gateway " + privateNic + " on router " + router); result = false; } return result; } @Override public boolean destroyPrivateGateway(PrivateGateway gateway, VirtualRouter router) throws ConcurrentOperationException, ResourceUnavailableException { if (!_networkMgr.isVmPartOfNetwork(router.getId(), gateway.getNetworkId())) { s_logger.debug("Router doesn't have nic for gateway " + gateway + " so no need to removed it"); return true; } Network privateNetwork = _networkMgr.getNetwork(gateway.getNetworkId()); s_logger.debug("Unsetting source nat for " + router + "'s private gateway " + gateway + " as a part of delete private gateway"); boolean result = setupVpcPrivateNetwork(router, false, _networkMgr.getNicProfile(router, privateNetwork.getId())); if (!result) { s_logger.warn("Failed to delete private gateway " + gateway + " on router " + router); return false; } s_logger.debug("Removing router " + router + " from private network " + privateNetwork + " as a part of delete private gateway"); result = result && _itMgr.removeVmFromNetwork(router, privateNetwork, null); s_logger.debug("Private gateawy " + gateway + " is removed from router " + router); return result; } @Override protected void finalizeIpAssocForNetwork(Commands cmds, VirtualRouter router, Provider provider, Long guestNetworkId) { ArrayList publicIps = getPublicIpsToApply(router, provider, guestNetworkId); if (publicIps != null && !publicIps.isEmpty()) { s_logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + router + " start."); // Re-apply public ip addresses - should come before PF/LB/VPN if (_networkMgr.isProviderSupportServiceInNetwork(guestNetworkId, Service.Firewall, provider)) { createVpcAssociateIPCommands(router, publicIps, cmds); } } } }