diff --git a/api/src/com/cloud/agent/api/to/DnsmasqTO.java b/api/src/com/cloud/agent/api/to/DhcpTO.java similarity index 93% rename from api/src/com/cloud/agent/api/to/DnsmasqTO.java rename to api/src/com/cloud/agent/api/to/DhcpTO.java index c7be04d4900..b0d6c7a1c18 100644 --- a/api/src/com/cloud/agent/api/to/DnsmasqTO.java +++ b/api/src/com/cloud/agent/api/to/DhcpTO.java @@ -16,13 +16,13 @@ // under the License. package com.cloud.agent.api.to; -public class DnsmasqTO { +public class DhcpTO { String routerIp; String gateway; String netmask; String startIpOfSubnet; - public DnsmasqTO(String routerIp, String gateway, String netmask, String StartIpOfSubnet) { + public DhcpTO(String routerIp, String gateway, String netmask, String StartIpOfSubnet) { this.routerIp = routerIp; this.startIpOfSubnet = StartIpOfSubnet; this.gateway = gateway; diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index a06208b2565..9be61713e9a 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -180,6 +180,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability SupportedEgressProtocols = new Capability("SupportedEgressProtocols"); public static final Capability HealthCheckPolicy = new Capability("HealthCheckPolicy"); public static final Capability LbSchemes = new Capability("LbSchemes"); + public static final Capability DhcpAccrossMultipleSubnets = new Capability("DhcpAccrossMultipleSubnets"); private String name; diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 405cecd8847..59ccdbf754d 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -17,7 +17,9 @@ package com.cloud.network; import java.util.List; +import java.util.Map; +import com.cloud.offering.NetworkOffering; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; @@ -180,4 +182,5 @@ public interface NetworkService { /* lists the nic informaton */ List listNics(ListNicsCmd listNicsCmd); + Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service); } diff --git a/api/src/com/cloud/network/element/DhcpServiceProvider.java b/api/src/com/cloud/network/element/DhcpServiceProvider.java index 83008ca801f..6363d7cd22e 100644 --- a/api/src/com/cloud/network/element/DhcpServiceProvider.java +++ b/api/src/com/cloud/network/element/DhcpServiceProvider.java @@ -29,5 +29,5 @@ import com.cloud.vm.VirtualMachineProfile; public interface DhcpServiceProvider extends NetworkElement { boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException; boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException; - boolean removeDhcpSupportForSubnet(Network network); + boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException; } diff --git a/core/src/com/cloud/agent/api/routing/DnsMasqConfigCommand.java b/core/src/com/cloud/agent/api/routing/DnsMasqConfigCommand.java index a52af90fb10..521ad70fb08 100644 --- a/core/src/com/cloud/agent/api/routing/DnsMasqConfigCommand.java +++ b/core/src/com/cloud/agent/api/routing/DnsMasqConfigCommand.java @@ -16,7 +16,7 @@ // under the License. package com.cloud.agent.api.routing; -import com.cloud.agent.api.to.DnsmasqTO; +import com.cloud.agent.api.to.DhcpTO; import java.util.List; @@ -26,11 +26,14 @@ public class DnsMasqConfigCommand extends NetworkElementCommand { String dns2; String internal_dns1; String internal_dns2; - List dnsmasqTOs; + List dhcpTOs; + boolean useExternal_dns; + String domain_suffix; + boolean dns; - public DnsMasqConfigCommand(String domain, List dnsmasqTOs, String dns1, String dns2, String internal_dns1, String internal_dns2) { + public DnsMasqConfigCommand(String domain, List dhcpTOs, String dns1, String dns2, String internal_dns1, String internal_dns2) { this.domain = domain; - this.dnsmasqTOs = dnsmasqTOs; + this.dhcpTOs = dhcpTOs; this.dns1= dns1; this.dns2= dns2; this.internal_dns1 = internal_dns1; @@ -38,8 +41,8 @@ public class DnsMasqConfigCommand extends NetworkElementCommand { } - public List getIps() { - return dnsmasqTOs; + public List getIps() { + return dhcpTOs; } public String getDomain() { @@ -62,4 +65,29 @@ public class DnsMasqConfigCommand extends NetworkElementCommand { return internal_dns2; } + public void setUseExternalDns(boolean useExternal_dns) { + this.useExternal_dns = useExternal_dns; + } + + public void setDomainSuffix(String domain_suffix) { + this.domain_suffix = domain_suffix; + } + + public void setIfDnsProvided(boolean dns) { + this.dns =dns; + } + + public String getDomainSuffix() { + return this.domain_suffix; + } + + public boolean getUseExternalDns() { + return useExternal_dns; + } + + public boolean isDnsProvided() { + return dns; + } + + } diff --git a/core/src/com/cloud/network/DnsMasqConfigurator.java b/core/src/com/cloud/network/DnsMasqConfigurator.java index dd349263c0c..3fc61df8fb2 100644 --- a/core/src/com/cloud/network/DnsMasqConfigurator.java +++ b/core/src/com/cloud/network/DnsMasqConfigurator.java @@ -17,7 +17,7 @@ package com.cloud.network; import com.cloud.agent.api.routing.DnsMasqConfigCommand; -import com.cloud.agent.api.to.DnsmasqTO; +import com.cloud.agent.api.to.DhcpTO; import org.apache.log4j.Logger; import java.util.Arrays; @@ -74,11 +74,10 @@ import java.util.List; "dhcp-option=6,router_ip,external_dns\n", "dhcp-optsfile=/etc/dhcpopts.txt\n", - }; public String[] generateConfiguration(DnsMasqConfigCommand dnsMasqconfigcmd) { - List dnsmasqTOs = dnsMasqconfigcmd.getIps(); + List dhcpTOs = dnsMasqconfigcmd.getIps(); List dnsMasqconf = Arrays.asList(Dnsmasq_config); String range=""; String gateway=""; @@ -95,15 +94,42 @@ import java.util.List; dns_external = dns_external + "*"; dns_external = dns_external.replace(",*",""); int i=0; - for (; i< dnsmasqTOs.size(); i++) { - range=range + "dhcp-range=set:range"+i+","+dnsmasqTOs.get(i).getStartIpOfSubnet()+",static\n"; - gateway=gateway +"dhcp-option=tag:range"+i+",3,"+dnsmasqTOs.get(i).getGateway()+"\n"; - netmask=netmask +"dhcp-option=tag:range"+i+",1,"+dnsmasqTOs.get(i).getNetmask()+"\n"; - dnsServers=dnsServers+"dhcp-option=tag:range"+i+",6,"+dnsmasqTOs.get(i).getRouterIp()+","+dns_external+"\n"; + for (; i< dhcpTOs.size(); i++) { + range=range + "dhcp-range=set:range"+i+","+ dhcpTOs.get(i).getStartIpOfSubnet()+",static\n"; + gateway=gateway +"dhcp-option=tag:range"+i+",3,"+ dhcpTOs.get(i).getGateway()+"\n"; + netmask=netmask +"dhcp-option=tag:range"+i+",1,"+ dhcpTOs.get(i).getNetmask()+"\n"; + if (!dnsMasqconfigcmd.isDnsProvided()) { + dnsServers = dnsServers+"dhcp-option=tag:range"+i+",6,"+dns_external+"\n"; + } + else { + dnsServers=dnsServers+"dhcp-option=tag:range"+i+",6,"+ dhcpTOs.get(i).getRouterIp()+","+dns_external+"\n"; + } + } - dnsMasqconf.set(12, "domain="+domain+"\n"); - dnsMasqconf.set(14, "domain="+domain+"\n"); - dnsMasqconf.set(16,"domain="+domain+"\n"); + String domain_suffix= dnsMasqconfigcmd.getDomainSuffix(); + + if (domain != null) { + if (domain_suffix != null) { + + dnsMasqconf.get(5).replace(" local=/cs1cloud.internal/"," local=/"+domain+"/"); + dnsMasqconf.set(12, "domain="+domain_suffix+domain+"\n"); + dnsMasqconf.set(14, "domain="+domain_suffix+domain+"\n"); + dnsMasqconf.set(16,"domain="+domain_suffix+domain+"\n"); + } else { + dnsMasqconf.get(5).replace(" local=/cs1cloud.internal/"," local=/"+domain+"/"); + dnsMasqconf.set(12, "domain="+domain+"\n"); + dnsMasqconf.set(14, "domain="+domain+"\n"); + dnsMasqconf.set(16,"domain="+domain+"\n"); + } + } + ///if no domain is specified. this happens when dns service is not provided by the virtualrouter. + else { + dnsMasqconf.get(5).replace(" local=/cs1cloud.internal/"," local=/"+domain+"/"); + dnsMasqconf.set(12, "domain="+"cloudnine.internal\n"); + dnsMasqconf.set(14, "domain="+"cloudnine.internal\n"); + dnsMasqconf.set(16,"domain="+"cloudnine.internal\n"); + } + dnsMasqconf.set(18, range); dnsMasqconf.set(22, gateway); dnsMasqconf.set(23, netmask); diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java index cecc145ed8b..dc2899f06ff 100755 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -387,7 +387,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements SummedCapacitySearch.and("clusterId", SummedCapacitySearch.entity().getClusterId(), Op.EQ); } if (capacityType != null){ - SummedCapacitySearch.and("capacityType", SummedCapacitySearch.entity().getCapacityType(), Op.EQ); + SummedCapacitySearch.and("capacityType", SummedCapacitySearch.entity().getCapacityType(), Op.EQ); } SummedCapacitySearch.done(); diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/com/cloud/network/dao/IPAddressDao.java index 3eba6d802d9..314ae18ef80 100755 --- a/engine/schema/src/com/cloud/network/dao/IPAddressDao.java +++ b/engine/schema/src/com/cloud/network/dao/IPAddressDao.java @@ -75,7 +75,9 @@ public interface IPAddressDao extends GenericDao { long countFreeIpsInVlan(long vlanDbId); - boolean deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp) throws SQLException; + void deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp); - boolean deletePublicIPRange(long vlanDbId) throws SQLException; + boolean deletePublicIPRange(long vlanDbId) ; + + void lockRange(long vlandbId); } diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java index 1051b694d3d..9f5f403631b 100755 --- a/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.dao; +import com.cloud.dc.DataCenterVnetVO; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.VlanDao; @@ -54,7 +55,8 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen protected SearchBuilder VlanDbIdSearchUnallocated; protected GenericSearchBuilder AllIpCount; protected GenericSearchBuilder AllocatedIpCount; - protected GenericSearchBuilder AllIpCountForDashboard; + protected GenericSearchBuilder AllIpCountForDashboard; + protected SearchBuilder DeleteAllExceptGivenIp; protected GenericSearchBuilder AllocatedIpCountForAccount; @Inject protected VlanDao _vlanDao; protected GenericSearchBuilder CountFreePublicIps; @@ -128,6 +130,10 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen join.and("vlanType", join.entity().getVlanType(), Op.EQ); CountFreePublicIps.join("vlans", join, CountFreePublicIps.entity().getVlanId(), join.entity().getId(), JoinBuilder.JoinType.INNER); CountFreePublicIps.done(); + + DeleteAllExceptGivenIp = createSearchBuilder(); + DeleteAllExceptGivenIp.and("vlanDbId", DeleteAllExceptGivenIp.entity().getVlanId(), Op.EQ); + DeleteAllExceptGivenIp.and("ip", DeleteAllExceptGivenIp.entity().getAddress(), Op.NEQ); } @Override @@ -366,21 +372,15 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen } @Override - public boolean deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp) throws SQLException { - Transaction txn = Transaction.currentTxn(); - String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE vlan_db_id = ? and public_ip_address!=?"; - - txn.start(); - PreparedStatement stmt = txn.prepareAutoCloseStatement(deleteSql); - stmt.setLong(1, vlanDbId); - stmt.setString(2, aliasIp); - stmt.executeUpdate(); - txn.commit(); - return true; + public void deletePublicIPRangeExceptAliasIP(long vlanDbId, String aliasIp) { + SearchCriteria sc =DeleteAllExceptGivenIp .create(); + sc.setParameters("vlan", vlanDbId); + sc.setParameters("ip", aliasIp); + remove(sc); } @Override - public boolean deletePublicIPRange(long vlanDbId) throws SQLException{ + public boolean deletePublicIPRange(long vlanDbId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("vlan", vlanDbId); remove(sc); @@ -408,4 +408,11 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen sc.setParameters("associatedVmIp", vmIp); return findOneBy(sc); } + + @Override + public void lockRange(long vlandbId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vlan", vlandbId); + lockRows(sc,null,true); + } } diff --git a/engine/schema/src/com/cloud/vm/dao/NicDao.java b/engine/schema/src/com/cloud/vm/dao/NicDao.java index 83f280e9032..37249dd909e 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicDao.java +++ b/engine/schema/src/com/cloud/vm/dao/NicDao.java @@ -20,6 +20,7 @@ import com.cloud.utils.db.GenericDao; import com.cloud.vm.NicVO; import com.cloud.vm.VirtualMachine; +import java.net.URI; import java.util.List; public interface NicDao extends GenericDao { @@ -68,4 +69,6 @@ public interface NicDao extends GenericDao { List listPlaceholderNicsByNetworkIdAndVmType(long networkId, VirtualMachine.Type vmType); NicVO findByInstanceIdAndIpAddressAndVmtype(long instanceId, String ipaddress, VirtualMachine.Type type); + + List listByNetworkIdTypeAndGatewayAndBroadcastUri(long networkId, VirtualMachine.Type vmType, String gateway, URI broadcastUri); } diff --git a/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java index 420643f7363..d6433a45ffb 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java @@ -29,6 +29,7 @@ import com.cloud.vm.VirtualMachine; import org.springframework.stereotype.Component; import javax.ejb.Local; +import java.net.URI; import java.util.List; @Component @@ -151,7 +152,17 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { sc.setParameters("gateway", gateway); return findOneBy(sc); } - + + @Override + public List listByNetworkIdTypeAndGatewayAndBroadcastUri(long networkId, VirtualMachine.Type vmType, String gateway, URI broadcasturi) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + sc.setParameters("vmType", vmType); + sc.setParameters("gateway", gateway); + sc.setParameters("broadcastUri", broadcasturi); + return listBy(sc); + } + @Override public NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/patches/systemvm/debian/config/root/createIpAlias.sh b/patches/systemvm/debian/config/root/createIpAlias.sh index 1db210b6860..54981954214 100755 --- a/patches/systemvm/debian/config/root/createIpAlias.sh +++ b/patches/systemvm/debian/config/root/createIpAlias.sh @@ -19,8 +19,16 @@ usage() { printf " %s \n" $(basename $0) >&2 } +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + -set -x var="$1" cert="/root/.ssh/id_rsa.cloud" @@ -35,4 +43,4 @@ do done #restaring the password service to enable it on the ip aliases /etc/init.d/cloud-passwd-srvr restart -exit $? \ No newline at end of file +unlock_exit $? $lock $locked \ No newline at end of file diff --git a/patches/systemvm/debian/config/root/deleteIpAlias.sh b/patches/systemvm/debian/config/root/deleteIpAlias.sh index cf6d4de5269..fa228fb694f 100755 --- a/patches/systemvm/debian/config/root/deleteIpAlias.sh +++ b/patches/systemvm/debian/config/root/deleteIpAlias.sh @@ -20,7 +20,15 @@ usage() { printf " %s \n" $(basename $0) >&2 } -set -x +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + var="$1" cert="/root/.ssh/id_rsa.cloud" @@ -32,12 +40,8 @@ do var=$( echo $var | sed "s/${var1}-//" ) done -#recreating the active ip aliases -sh /root/createIpAlias.sh $2 -result=$? -if [ "$result" -ne "0" ] -then - exit $result -fi +releaseLockFile $lock $locked -exit 0 +#recreating the active ip aliases +/root/createIpAlias.sh $2 +unlock_exit $? $lock $locked diff --git a/patches/systemvm/debian/config/root/dnsmasq.sh b/patches/systemvm/debian/config/root/dnsmasq.sh index 656fd3c320f..b70e2d3c8bb 100755 --- a/patches/systemvm/debian/config/root/dnsmasq.sh +++ b/patches/systemvm/debian/config/root/dnsmasq.sh @@ -20,6 +20,15 @@ usage() { printf "Usage: %s: \n" $(basename $0) >&2 } +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + set -x #backup the old config file cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak @@ -37,7 +46,7 @@ then echo "reverting to the old config" cp /etc/dnsmasq.config.bak /etc/dnsmasq.conf service dnsmasq restart - exit 2 + unlock_exit $? $lock $locked fi rm $1 -echo "success" +unlock_exit $? $lock $locked diff --git a/scripts/network/domr/call_dnsmasq.sh b/scripts/network/domr/call_dnsmasq.sh index 097e18572a2..81c218d0e7b 100755 --- a/scripts/network/domr/call_dnsmasq.sh +++ b/scripts/network/domr/call_dnsmasq.sh @@ -20,8 +20,6 @@ usage() { printf "Usage: %s: \n" $(basename $0) >&2 } -set -x - cert="/root/.ssh/id_rsa.cloud" ssh -p 3922 -q -o StrictHostKeyChecking=no -i $cert root@$1 "/root/dnsmasq.sh $2" diff --git a/scripts/vm/hypervisor/xenserver/createipAlias.sh b/scripts/vm/hypervisor/xenserver/createipAlias.sh index c35658e6679..4ef6618794b 100755 --- a/scripts/vm/hypervisor/xenserver/createipAlias.sh +++ b/scripts/vm/hypervisor/xenserver/createipAlias.sh @@ -21,6 +21,5 @@ usage() { printf " %s routerip \n" $(basename $0) >&2 } -set -x cert="/root/.ssh/id_rsa.cloud" ssh -p 3922 -q -o StrictHostKeyChecking=no -i $cert root@$1 "/root/createIpAlias.sh $2" diff --git a/scripts/vm/hypervisor/xenserver/deleteipAlias.sh b/scripts/vm/hypervisor/xenserver/deleteipAlias.sh index 6816edd524c..7604172910a 100644 --- a/scripts/vm/hypervisor/xenserver/deleteipAlias.sh +++ b/scripts/vm/hypervisor/xenserver/deleteipAlias.sh @@ -20,6 +20,5 @@ usage() { printf " %s routerip \n" $(basename $0) >&2 } -set -x cert="/root/.ssh/id_rsa.cloud" ssh -p 3922 -q -o StrictHostKeyChecking=no -i $cert root@$1 "/root/deleteIpAlias.sh $2 $3" diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 801028d7ba3..92178c9966c 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2738,9 +2738,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Transaction txn = Transaction.currentTxn(); txn.start(); - if (sameSubnet == null || sameSubnet.first() == false) { + if ((sameSubnet == null || sameSubnet.first() == false) && (network.getTrafficType()== TrafficType.Guest) && (network.getGuestType() == GuestType.Shared) && (_vlanDao.listVlansByNetworkId(networkId) != null)) { + Map dhcpCapabilities = _networkSvc.getNetworkOfferingServiceCapabilities(_networkOfferingDao.findById(network.getNetworkOfferingId()), Service.Dhcp); + String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets); + if (supportsMultipleSubnets == null || !Boolean.valueOf(supportsMultipleSubnets)) { + throw new InvalidParameterValueException("The Dhcp serivice provider for this network dose not support the dhcp across multiple subnets"); + } s_logger.info("adding a new subnet to the network " + network.getId()); - } else { + } else if (sameSubnet != null) { // if it is same subnet the user might not send the vlan and the // netmask details. so we are // figuring out while validation and setting them here. @@ -2757,7 +2762,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return vlan; } - public int checkIfSubsetOrSuperset(String newVlanGateway, String newVlanNetmask, VlanVO vlan, String startIP, + public NetUtils.supersetOrSubset checkIfSubsetOrSuperset(String newVlanGateway, String newVlanNetmask, VlanVO vlan, String startIP, String endIP) { if (newVlanGateway == null && newVlanNetmask == null) { newVlanGateway = vlan.getVlanGateway(); @@ -2765,10 +2770,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // this means he is trying to add to the existing subnet. if (NetUtils.sameSubnet(startIP, newVlanGateway, newVlanNetmask)) { if (NetUtils.sameSubnet(endIP, newVlanGateway, newVlanNetmask)) { - return 3; + return NetUtils.supersetOrSubset.sameSubnet; } } - return 0; + return NetUtils.supersetOrSubset.neitherSubetNorSuperset; } else if (newVlanGateway == null || newVlanGateway == null) { throw new InvalidParameterValueException( "either both netmask and gateway should be passed or both should me omited."); @@ -2798,25 +2803,30 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati vlanGateway = vlan.getVlanGateway(); vlanNetmask = vlan.getVlanNetmask(); // check if subset or super set or neither. - int val = checkIfSubsetOrSuperset(newVlanGateway, newVlanNetmask, vlan, startIP, endIP); - if (val == 1) { + NetUtils.supersetOrSubset val = checkIfSubsetOrSuperset(newVlanGateway, newVlanNetmask, vlan, startIP, endIP); + if (val == NetUtils.supersetOrSubset.isSuperset) { // this means that new cidr is a superset of the // existing subnet. throw new InvalidParameterValueException( "The subnet you are trying to add is a superset of the existing subnet having gateway" + vlan.getVlanGateway() + " and netmask " + vlan.getVlanNetmask()); - } else if (val == 0) { + } else if (val == NetUtils.supersetOrSubset.neitherSubetNorSuperset) { // this implies the user is trying to add a new subnet // which is not a superset or subset of this subnet. // checking with the other subnets. continue; - } else if (val == 2) { + } else if (val == NetUtils.supersetOrSubset.isSubset) { // this means he is trying to add to the same subnet. throw new InvalidParameterValueException( "The subnet you are trying to add is a subset of the existing subnet having gateway" + vlan.getVlanGateway() + " and netmask " + vlan.getVlanNetmask()); - } else if (val == 3) { + } else if (val == NetUtils.supersetOrSubset.sameSubnet) { sameSubnet = true; + //check if the gateway provided by the user is same as that of the subnet. + if (newVlanGateway != null && !newVlanGateway.equals(vlanGateway)) { + throw new InvalidParameterValueException("The gateway of the subnet should be unique. The subnet alreaddy has a gateway "+ vlanGateway); + } + break; } } if (ipv6) { @@ -3021,7 +3031,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (otherVlanGateway == null) { continue; } - String otherVlanSubnet = NetUtils.getSubNet(vlan.getVlanGateway(), vlan.getVlanNetmask()); + String otherVlanSubnet = NetUtils.getSubNet(vlan.getVlanGateway(), vlan.getVlanNetmask()); String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); String otherVlanStartIP = otherVlanIpRange[0]; String otherVlanEndIP = null; @@ -3149,15 +3159,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return vlan; } - @DB - public void deleteVLANFromDb(long vlanDbId) throws SQLException { - Transaction txn = Transaction.currentTxn(); - txn.start(); - _publicIpAddressDao.deletePublicIPRange(vlanDbId); - _vlanDao.expunge(vlanDbId); - txn.commit(); - } - @Override @DB public boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller) { @@ -3222,102 +3223,38 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati s_logger.warn("Some ip addresses failed to be released as a part of vlan " + vlanDbId + " removal"); } + else { + for (IPAddressVO ip : ips) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getId(), ip + .getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlanRange + .getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } + } } finally { _vlanDao.releaseFromLockTable(vlanDbId); } } + else { // !isAccountSpecific + NicIpAliasVO ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(vlanRange.getVlanGateway(), vlanRange.getNetworkId(), NicIpAlias.state.active); + //check if the ipalias belongs to the vlan range being deleted. + if (ipAlias != null && vlanDbId == _publicIpAddressDao.findByIpAndSourceNetworkId(vlanRange.getNetworkId(), ipAlias.getIp4Address()).getVlanId()) { + throw new InvalidParameterValueException("Cannot delete vlan range "+vlanDbId+" as "+ipAlias.getIp4Address() + + "is being used for providing dhcp service in this subnet. Delete all VMs in this subnet and try again"); + } + allocIpCount = _publicIpAddressDao.countIPs(vlanRange.getDataCenterId(), vlanDbId, true); + if (allocIpCount > 0) { + throw new InvalidParameterValueException(allocIpCount + " Ips are in use. Cannot delete this vlan"); + } + } } - if (success) { - // Delete all public IPs in the VLAN - // if ip range is dedicated to an account generate usage events for - // release of every ip in the range - if (isAccountSpecific) { - for (IPAddressVO ip : ips) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getId(), ip - .getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlanRange - .getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); - } - } - try { - if (_networkModel.areServicesSupportedInNetwork(vlanRange.getNetworkId(), Service.Dhcp)) { - Network network = _networkDao.findById(vlanRange.getNetworkId()); - DhcpServiceProvider dhcpServiceProvider = _networkMgr.getDhcpServiceProvider(network); - if (!dhcpServiceProvider.getProvider().getName().equalsIgnoreCase(Provider.VirtualRouter.getName())) { - deleteVLANFromDb(vlanDbId); - } else { - return handleIpAliasDeletion(vlanRange, vlanDbId, dhcpServiceProvider, network); - } - } - else { - deleteVLANFromDb(vlanDbId); - } - } - catch ( SQLException e) { - throw new CloudRuntimeException(e.getMessage()); - } - - } - return true; - } - - @DB - private boolean handleIpAliasDeletion(VlanVO vlanRange, long vlanDbId, DhcpServiceProvider dhcpServiceProvider, Network network) throws SQLException { Transaction txn = Transaction.currentTxn(); txn.start(); - IPAddressVO ip = null; - NicIpAliasVO ipAlias = null; - try{ - Integer allocIpCount=0; - //search if the vlan has any allocated ips. - allocIpCount = _publicIpAddressDao.countIPs(vlanRange.getDataCenterId(), vlanDbId, true); - if (allocIpCount > 1) { - throw new InvalidParameterValueException ("Cannot delete this range as some of the vlans are in use."); - } - else if (allocIpCount == 0){ - deleteVLANFromDb(vlanDbId); - } - else { - ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(vlanRange.getVlanGateway(), vlanRange.getNetworkId(), NicIpAlias.state.active); - if (ipAlias == null) { - throw new InvalidParameterValueException ("Cannot delete this range as some of the Ips are in use."); - } - - //check if this ip belongs to this vlan and is allocated. - ip = _publicIpAddressDao.findByIpAndVlanId(ipAlias.getIp4Address(), vlanDbId); - if (ip != null && ip.getState() == IpAddress.State.Allocated) { - //check if there any other vlan ranges in the same subnet having free ips - List vlanRanges = _vlanDao.listVlansByNetworkIdAndGateway(vlanRange.getNetworkId(), vlanRange.getVlanGateway()); - //if there is no other vlanrage in this subnet. free the ip and delete the vlan. - if (vlanRanges.size() == 1) { - ipAlias.setState(NicIpAlias.state.revoked); - _nicIpAliasDao.update(ipAlias.getId(), ipAlias); - if (!dhcpServiceProvider.removeDhcpSupportForSubnet(network)) { - s_logger.debug("Failed to delete the vlan range as we could not free the ip used to provide the dhcp service."); - //setting the state back to active - ipAlias.setState(NicIpAlias.state.active); - _nicIpAliasDao.update(ipAlias.getId(), ipAlias); - } - else { - _publicIpAddressDao.unassignIpAddress(ip.getId()); - deleteVLANFromDb(vlanDbId); - } - } else { - // if there are more vlans in the subnet, free all the ips in the range except the ip alias. - s_logger.info("vlan Range"+vlanRange.getId()+" id being deleted, one of the Ips in this range is used to provide the dhcp service, will free the rest of the IPs in range."); - _publicIpAddressDao.deletePublicIPRangeExceptAliasIP(vlanDbId, ipAlias.getIp4Address()); - VlanVO vlan = _vlanDao.findById(vlanDbId); - vlan.setIpRange(ipAlias.getIp4Address()+"-"+ipAlias.getIp4Address()); - _vlanDao.update(vlan.getId(), vlan); - } - } - } - } catch (CloudRuntimeException e) { - txn.rollback(); - throw e; - } + _publicIpAddressDao.deletePublicIPRange(vlanDbId); + _vlanDao.expunge(vlanDbId); txn.commit(); + return true; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index db375c3dbdc..0fa58be50bf 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2002,9 +2002,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (vmProfile.getType() == Type.User && element.getProvider() != null) { if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) && - element instanceof DhcpServiceProvider) { + element instanceof DhcpServiceProvider ) { DhcpServiceProvider sp = (DhcpServiceProvider) element; - if (profile.getIp6Address() == null) { + Map dhcpCapabilities = element.getCapabilities().get(Service.Dhcp); + String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets); + if ((supportsMultipleSubnets != null || Boolean.valueOf(supportsMultipleSubnets)) && profile.getIp6Address() == null) { if (!sp.configDhcpSupportForSubnet(network, profile, vmProfile, dest, context)) { return false; } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index ccd23bff262..ad437e5b240 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1822,11 +1822,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } - - - - - protected Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) { + @Override + public Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) { if (!areServicesSupportedByNetworkOffering(offering.getId(), service)) { // TBD: We should be sending networkOfferingId and not the offering object itself. @@ -2676,8 +2673,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } - - if (newVnetRangeString != null) { for (Pair vnetRange : existingRanges ){ value=vnetMap.get(vnetRange.first()); diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 19166787e9b..d26c1e111cd 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -614,7 +614,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl capabilities.put(Service.Dns, dnsCapabilities); capabilities.put(Service.UserData, null); - capabilities.put(Service.Dhcp, null); + + Map dhcpCapabilities = new HashMap(); + dhcpCapabilities.put(Capability.DhcpAccrossMultipleSubnets, "true"); + capabilities.put(Service.Dhcp, dhcpCapabilities); capabilities.put(Service.Gateway, null); @@ -873,24 +876,18 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl } @Override - public boolean removeDhcpSupportForSubnet(Network network) { + public boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException{ if (canHandle(network, Service.Dhcp)) { List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); - try { - if ((routers == null) || (routers.size() == 0)) { + if ((routers == null) || (routers.size() == 0)) { throw new ResourceUnavailableException("Can't find at least one router!", DataCenter.class, network.getDataCenterId()); - } - } - catch (ResourceUnavailableException e) { - s_logger.debug("could not find any router on this network"); - } + } try { return _routerMgr.removeDhcpSupportForSubnet(network, routers); } catch (ResourceUnavailableException e) { s_logger.debug("Router resource unavailable "); } - } return false; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index e437af68f52..66d904c03da 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -85,7 +85,7 @@ import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; -import com.cloud.agent.api.to.DnsmasqTO; +import com.cloud.agent.api.to.DhcpTO; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; @@ -141,6 +141,7 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkService; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; @@ -356,6 +357,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V Site2SiteVpnManager _s2sVpnMgr; @Inject UserIpv6AddressDao _ipv6Dao; + @Inject + NetworkService _networkSvc; int _routerRamSize; @@ -2497,23 +2500,31 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } //Reapply dhcp and dns configuration. if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.Dhcp, provider)) { - List revokedIpAliasVOs = _nicIpAliasDao.listByNetworkIdAndState(guestNetworkId, NicIpAlias.state.revoked); - s_logger.debug("Found" + revokedIpAliasVOs.size() + "ip Aliases to revoke on the router as a part of dhcp configuration"); - List revokedIpAliasTOs = new ArrayList(); - for (NicIpAliasVO revokedAliasVO : revokedIpAliasVOs) { - revokedIpAliasTOs.add(new IpAliasTO(revokedAliasVO.getIp4Address(), revokedAliasVO.getNetmask(), revokedAliasVO.getAliasCount().toString())); - } - List aliasVOs = _nicIpAliasDao.listByNetworkIdAndState(guestNetworkId, NicIpAlias.state.active); - s_logger.debug("Found" + aliasVOs.size() + "ip Aliases to apply on the router as a part of dhcp configuration"); - List activeIpAliasTOs = new ArrayList(); - for (NicIpAliasVO aliasVO : aliasVOs) { - activeIpAliasTOs.add(new IpAliasTO(aliasVO.getIp4Address(), aliasVO.getNetmask(), aliasVO.getAliasCount().toString())); - } - if (revokedIpAliasTOs.size() != 0 || activeIpAliasTOs.size() != 0){ - createDeleteIpAliasCommand(router, revokedIpAliasTOs, activeIpAliasTOs, guestNetworkId, cmds); - configDnsMasq(router, _networkDao.findById(guestNetworkId), cmds); - } + Map dhcpCapabilities = _networkSvc.getNetworkOfferingServiceCapabilities(_networkOfferingDao.findById(_networkDao.findById(guestNetworkId).getNetworkOfferingId()), Service.Dhcp); + String supportsMultipleSubnets = dhcpCapabilities.get(Network.Capability.DhcpAccrossMultipleSubnets); + if (supportsMultipleSubnets == null || !Boolean.valueOf(supportsMultipleSubnets)) { + List revokedIpAliasVOs = _nicIpAliasDao.listByNetworkIdAndState(guestNetworkId, NicIpAlias.state.revoked); + s_logger.debug("Found" + revokedIpAliasVOs.size() + "ip Aliases to revoke on the router as a part of dhcp configuration"); + removeRevokedIpAliasFromDb(revokedIpAliasVOs); + List aliasVOs = _nicIpAliasDao.listByNetworkIdAndState(guestNetworkId, NicIpAlias.state.active); + s_logger.debug("Found" + aliasVOs.size() + "ip Aliases to apply on the router as a part of dhcp configuration"); + List activeIpAliasTOs = new ArrayList(); + for (NicIpAliasVO aliasVO : aliasVOs) { + activeIpAliasTOs.add(new IpAliasTO(aliasVO.getIp4Address(), aliasVO.getNetmask(), aliasVO.getAliasCount().toString())); + } + if (activeIpAliasTOs.size() != 0){ + createIpAlias(router, activeIpAliasTOs, guestNetworkId, cmds); + configDnsMasq(router, _networkDao.findById(guestNetworkId), cmds); + } + + } + } + } + + private void removeRevokedIpAliasFromDb(List revokedIpAliasVOs) { + for (NicIpAliasVO ipalias : revokedIpAliasVOs) { + _nicIpAliasDao.expunge(ipalias.getId()); } } @@ -2790,9 +2801,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V router.getState(), DataCenter.class, network.getDataCenterId()); } //check if this is not the primary subnet. - - - //check if the the ip Alias is configured on the virtualrouter. UserVm vm = updatedProfile.getVirtualMachine(); NicVO domr_guest_nic = _nicDao.findByInstanceIdAndIpAddressAndVmtype(router.getId(), _nicDao.getIpAddress(nic.getNetworkId(), router.getId()), VirtualMachine.Type.DomainRouter); //check if the router ip address and the vm ip address belong to same subnet. @@ -2849,8 +2857,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V boolean result = sendCommandsToRouter(router, cmds); if (result == false) { NicIpAliasVO ipAliasVO = _nicIpAliasDao.findByInstanceIdAndNetworkId(network.getId(), router.getId()); + Transaction txn = Transaction.currentTxn(); + txn.start(); _nicIpAliasDao.expunge(ipAliasVO.getId()); _ipAddressDao.unassignIpAddress(routerPublicIP.getId()); + txn.commit(); throw new CloudRuntimeException("failed to configure ip alias on the router as a part of dhcp config"); } } @@ -2891,10 +2902,13 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V configDnsMasq(router, network, cmds); boolean result = sendCommandsToRouter(router, cmds); if (result) { + Transaction txn= Transaction.currentTxn(); + txn.start(); for (NicIpAliasVO revokedAliasVO : revokedIpAliasVOs) { _nicIpAliasDao.expunge(revokedAliasVO.getId()); - return true; } + txn.commit(); + return true; } } return false; @@ -3461,7 +3475,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); List ipAliasVOList = _nicIpAliasDao.listByNetworkIdAndState(network.getId(), NicIpAlias.state.active); - List ipList = new ArrayList(); + List ipList = new ArrayList(); NicVO router_guest_nic = _nicDao.findByNtwkIdAndInstanceId(network.getId(), router.getId()); String cidr = NetUtils.getCidrFromGatewayAndNetmask(router_guest_nic.getGateway(), router_guest_nic.getNetmask()); @@ -3470,22 +3484,25 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V long cidrSize = Long.parseLong(cidrPair[1]); String startIpOfSubnet = NetUtils.getIpRangeStartIpFromCidr(cidrAddress, cidrSize); - ipList.add(new DnsmasqTO(router_guest_nic.getIp4Address(),router_guest_nic.getGateway(),router_guest_nic.getNetmask(), startIpOfSubnet)); + ipList.add(new DhcpTO(router_guest_nic.getIp4Address(),router_guest_nic.getGateway(),router_guest_nic.getNetmask(), startIpOfSubnet)); for (NicIpAliasVO ipAliasVO : ipAliasVOList) { - DnsmasqTO dnsmasqTO = new DnsmasqTO(ipAliasVO.getIp4Address(), ipAliasVO.getGateway(), ipAliasVO.getNetmask(), ipAliasVO.getStartIpOfSubnet()); + DhcpTO DhcpTO = new DhcpTO(ipAliasVO.getIp4Address(), ipAliasVO.getGateway(), ipAliasVO.getNetmask(), ipAliasVO.getStartIpOfSubnet()); if (s_logger.isTraceEnabled()) { - s_logger.trace("configDnsMasq : adding ip {" + dnsmasqTO.getGateway() + ", " + dnsmasqTO.getNetmask() + ", " + dnsmasqTO.getRouterIp() + ", " + dnsmasqTO.getStartIpOfSubnet() + "}"); + s_logger.trace("configDnsMasq : adding ip {" + DhcpTO.getGateway() + ", " + DhcpTO.getNetmask() + ", " + DhcpTO.getRouterIp() + ", " + DhcpTO.getStartIpOfSubnet() + "}"); } - ipList.add(dnsmasqTO); + ipList.add(DhcpTO); ipAliasVO.setVmId(router.getId()); } DataCenterVO dcvo = _dcDao.findById(router.getDataCenterId()); + boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, Provider.VirtualRouter); + String domain_suffix = dcvo.getDetail(ZoneConfig.DnsSearchOrder.getName()); DnsMasqConfigCommand dnsMasqConfigCmd = new DnsMasqConfigCommand(network.getNetworkDomain(),ipList, dcvo.getDns1(), dcvo.getDns2(), dcvo.getInternalDns1(), dcvo.getInternalDns2()); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(network.getId(), router.getId())); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); - + dnsMasqConfigCmd.setDomainSuffix(domain_suffix); + dnsMasqConfigCmd.setIfDnsProvided(dnsProvided); cmds.addCommand("dnsMasqConfig" ,dnsMasqConfigCmd); //To change body of created methods use File | Settings | File Templates. } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 39d08958249..986dd4f1a2f 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -27,6 +27,7 @@ import java.util.TreeSet; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.configuration.ZoneConfig; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -44,7 +45,7 @@ import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetSourceNatCommand; import com.cloud.agent.api.routing.SetStaticRouteCommand; import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; -import com.cloud.agent.api.to.DnsmasqTO; +import com.cloud.agent.api.to.DhcpTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NetworkACLTO; import com.cloud.agent.api.to.NicTO; @@ -885,24 +886,29 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } VpcVO vpc = _vpcDao.findById(router.getVpcId()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); - List ipList = new ArrayList(); + List ipList = new ArrayList(); String cidr = vpc.getCidr(); String[] cidrPair = cidr.split("\\/"); String cidrAddress = cidrPair[0]; long cidrSize = Long.parseLong(cidrPair[1]); String startIpOfSubnet = NetUtils.getIpRangeStartIpFromCidr(cidrAddress, cidrSize); - DnsmasqTO dnsmasqTO = new DnsmasqTO(router.getPrivateIpAddress(), router.getPublicIpAddress(), NetUtils.getCidrNetmask(cidrSize), startIpOfSubnet); - ipList.add(dnsmasqTO); + DhcpTO DhcpTO = new DhcpTO(router.getPrivateIpAddress(), router.getPublicIpAddress(), NetUtils.getCidrNetmask(cidrSize), startIpOfSubnet); + ipList.add(DhcpTO); + NicVO nic = _nicDao.findByIp4AddressAndVmId(_routerDao.findById(router.getId()).getPrivateIpAddress(), router.getId()); + DataCenterVO dcvo = _dcDao.findById(router.getDataCenterId()); + boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(nic.getNetworkId(), Service.Dns, Provider.VirtualRouter); + String domain_suffix = dcvo.getDetail(ZoneConfig.DnsSearchOrder.getName()); DnsMasqConfigCommand dnsMasqConfigCmd = new DnsMasqConfigCommand(vpc.getNetworkDomain(),ipList, dcVo.getDns1(), dcVo.getDns2(), dcVo.getInternalDns1(), dcVo.getInternalDns2()); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getPublicIpAddress()); dnsMasqConfigCmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + dnsMasqConfigCmd.setDomainSuffix(domain_suffix); + dnsMasqConfigCmd.setIfDnsProvided(dnsProvided); cmds.addCommand("dnsMasqConfig" ,dnsMasqConfigCmd); - //To change body of created methods use File | Settings | File Templates. } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index afdc85d8e57..6fb2379dada 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,6 +36,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.dao.VlanDao; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.element.DhcpServiceProvider; +import com.cloud.vm.dao.NicIpAliasDao; +import com.cloud.vm.dao.NicIpAliasVO; import org.apache.log4j.Logger; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -267,6 +274,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac protected ConfigurationServer _configServer; @Inject protected ManagementServer _mgmtServer; + @Inject + protected IPAddressDao _publicIpAddressDao; + @Inject + protected VlanDao _vlanDao; + @Inject + protected NicIpAliasDao _nicIpAliasDao; protected List _planners; public List getPlanners() { @@ -460,6 +473,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Destroying vm " + vm); } + if (vm.getType() == VirtualMachine.Type.User) { + removeDhcpServiceInsubnet(vm); + } + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType()); @@ -517,6 +534,41 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return true; } + @DB + private void removeDhcpServiceInsubnet(VirtualMachine vm) { + //list all the nics which belong to this vm and are the last nics in the subnets. + //we are using the info in these nics to remove the dhcp sercvice for these subnets. + List nicList = listLastNicsInSubnet(vm); + + if(nicList != null && nicList.size() != 0) { + for (NicVO nic : nicList) { + //free the ipalias on the routers corresponding to each of the nics. + Network network = _networkDao.findById(nic.getNetworkId()); + DhcpServiceProvider dhcpServiceProvider = _networkMgr.getDhcpServiceProvider(network); + try { + NicIpAliasVO ipAlias = _nicIpAliasDao.findByGatewayAndNetworkIdAndState(nic.getGateway(), network.getId(), NicIpAlias.state.active); + if (ipAlias != null) { + ipAlias.setState(NicIpAlias.state.revoked); + Transaction txn = Transaction.currentTxn(); + txn.start(); + _nicIpAliasDao.update(ipAlias.getId(),ipAlias); + IPAddressVO aliasIpaddressVo = _publicIpAddressDao.findByIpAndSourceNetworkId(ipAlias.getNetworkId(), ipAlias.getIp4Address()); + _publicIpAddressDao.unassignIpAddress(aliasIpaddressVo.getId()); + txn.commit(); + if (!dhcpServiceProvider.removeDhcpSupportForSubnet(network)) { + s_logger.warn("Failed to remove the ip alias on the router, marking it as removed in db and freed the allocated ip " + ipAlias.getIp4Address()); + } + } + } + catch (ResourceUnavailableException e) { + //failed to remove the dhcpconfig on the router. + s_logger.info ("Unable to delete the ip alias due to unable to contact the virtualrouter."); + } + + } + } + } + @Override public boolean start() { _executor.scheduleAtFixedRate(new CleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS); @@ -1337,6 +1389,28 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return true; } + //list all the nics which belong to this vm and are the last nics in the subnets. + //we are using the info in these nics to remove the dhcp sercvice for these subnets. + private List listLastNicsInSubnet(VirtualMachine vm) { + List nicList = _nicsDao.listByVmId(vm.getId()); + List copyOfnicList = new ArrayList(nicList); + for (NicVO nic : nicList) { + Network network = _networkDao.findById(nic.getNetworkId()); + DhcpServiceProvider dhcpServiceProvider = _networkMgr.getDhcpServiceProvider(network); + Map capabilities = dhcpServiceProvider.getCapabilities().get(Network.Service.Dhcp); + String supportsMultipleSubnets = capabilities.get(Network.Capability.DhcpAccrossMultipleSubnets); + if ((supportsMultipleSubnets != null && Boolean.valueOf(supportsMultipleSubnets) && network.getTrafficType() == Networks.TrafficType.Guest && network.getGuestType() == Network.GuestType.Shared)) { + //including the ip of the vm and the ipAlias + if (_nicsDao.listByNetworkIdTypeAndGatewayAndBroadcastUri(nic.getNetworkId(), VirtualMachine.Type.User, nic.getGateway(), nic.getBroadcastUri()).size() > 1) { + copyOfnicList.remove(nic); + } + } else { + copyOfnicList.remove(nic); + } + } + return copyOfnicList; + } + protected boolean checkVmOnHost(VirtualMachine vm, long hostId) throws AgentUnavailableException, OperationTimedoutException { CheckVirtualMachineAnswer answer = (CheckVirtualMachineAnswer) _agentMgr.send(hostId, new CheckVirtualMachineCommand(vm.getInstanceName())); if (!answer.getResult() || answer.getState() == State.Stopped) { diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 9c7d0926c9e..4577d0ae781 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -907,6 +907,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + @Override public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, Pod pod, Account caller, String requestedIp) diff --git a/server/test/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImplTest.java b/server/test/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImplTest.java index 04a3601d594..071f658f056 100644 --- a/server/test/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImplTest.java +++ b/server/test/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImplTest.java @@ -18,11 +18,21 @@ package com.cloud.network.router; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockingDetails; import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import com.cloud.configuration.ZoneConfig; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.vm.VirtualMachine; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Before; @@ -58,7 +68,10 @@ public class VpcVirtualNetworkApplianceManagerImplTest { @Mock VpcDao _vpcDao; @Mock VirtualRouter router; @Mock NicDao _nicDao; - @Mock DomainRouterDao _routerDao; + @Mock DomainRouterDao _routerDao; + @Mock NetworkModel _networkmodel; + @Mock NicVO nicVO; + @Mock DataCenterVO dcVO; @Before public void setup() { @@ -79,20 +92,28 @@ public class VpcVirtualNetworkApplianceManagerImplTest { VpcVO vpc = new VpcVO(1L,"bla","bla",1L,1L,1L,"10.0.0.0/8","blieb.net"); when( _vpcDao.findById(1L)).thenReturn(vpc); DataCenterVO dcVo = new DataCenterVO(1L,"dc","dc","8.8.8.8",null,null,null,"10.0.0.0/8","bla.net",new Long(1L),NetworkType.Advanced,null,".net"); - when( _dcDao.findById(1L) ).thenReturn(dcVo); + Map map = new HashMap(); + dcVo.setDetails(map); + dcVo.setDetail(ZoneConfig.DnsSearchOrder.getName(), "dummy"); + when(_dcDao.findById(1L)).thenReturn(dcVo); DomainRouterVO routerVo = new DomainRouterVO(1L,1L,1L,"brr",1L,HypervisorType.Any,1L,1L,1L,false,0,false,RedundantState.MASTER,false,false,1L); when( _routerDao.findById(1L)).thenReturn(routerVo); // when( vpcVirtNetAppMgr.getRouterControlIp(1L)).thenReturn("10.0.0.1"); when( router.getInstanceName()).thenReturn("r-vm-1"); when( router.getPublicIpAddress()).thenReturn("11.11.11.11"); - when( _nicDao.listByVmId(1L)).thenReturn(new ArrayList()); + NicVO nicvo = new NicVO("server", 1l, 1l, VirtualMachine.Type.DomainRouter); + nicvo.setNetworkId(1l); + when(_nicDao.findByIp4AddressAndVmId(anyString(), anyLong())).thenReturn(nicvo); NetworkManager netMgr = mock(NetworkManager.class); vpcVirtNetAppMgr._networkMgr = netMgr; - + vpcVirtNetAppMgr._networkModel = _networkmodel; + when(nicVO.getNetworkId()).thenReturn(1l); + when(_networkmodel.isProviderSupportServiceInNetwork(1l, Network.Service.Dhcp, Network.Provider.VirtualRouter)).thenReturn(true); + when(dcVO.getDetail(anyString())).thenReturn(null); Commands cmds = new Commands(OnError.Stop); vpcVirtNetAppMgr.configDnsMasq(router, cmds); - Assert.assertEquals("expected one command",1,cmds.size()); + Assert.assertEquals("expected one command",1, cmds.size()); DnsMasqConfigCommand cmd = cmds.getCommand(DnsMasqConfigCommand.class); } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 523dfb83941..fd61bc65c90 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -1382,6 +1382,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public Map getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + @Override public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, diff --git a/utils/conf/db.properties b/utils/conf/db.properties index e1b5fe9a2c1..903cf7163f6 100644 --- a/utils/conf/db.properties +++ b/utils/conf/db.properties @@ -25,7 +25,7 @@ region.id=1 # CloudStack database settings db.cloud.username=cloud db.cloud.password=cloud -db.root.password= +db.root.password=root db.cloud.host=localhost db.cloud.port=3306 db.cloud.name=cloud diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 68f49655991..05b485b9c39 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -797,13 +797,20 @@ public class NetUtils { return new Pair(tokens[0], Integer.parseInt(tokens[1])); } - public static int isNetowrkASubsetOrSupersetOfNetworkB (String cidrA, String cidrB) { + public static enum supersetOrSubset { + isSuperset, + isSubset, + neitherSubetNorSuperset, + sameSubnet, + errorInCidrFormat + } + public static supersetOrSubset isNetowrkASubsetOrSupersetOfNetworkB (String cidrA, String cidrB) { Long[] cidrALong = cidrToLong(cidrA); Long[] cidrBLong = cidrToLong(cidrB); long shift =0; if (cidrALong == null || cidrBLong == null) { //implies error in the cidr format - return -1; + return supersetOrSubset.errorInCidrFormat; } if (cidrALong[1] >= cidrBLong[1]) { shift = 32 - cidrBLong[1]; @@ -815,17 +822,17 @@ public class NetUtils { if (result == 0) { if (cidrALong[1] < cidrBLong[1]) { //this implies cidrA is super set of cidrB - return 1; + return supersetOrSubset.isSuperset; } else if (cidrALong[1] == cidrBLong[1]) { //this implies both the cidrs are equal - return 3; + return supersetOrSubset.sameSubnet; } // implies cidrA is subset of cidrB - return 2; + return supersetOrSubset.isSubset; } //this implies no overlap. - return 0; + return supersetOrSubset.neitherSubetNorSuperset; } public static boolean isNetworkAWithinNetworkB(String cidrA, String cidrB) {