From ca13586331d215b0be269fea010536106d7fa67c Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Mon, 3 Jun 2013 16:00:15 +0530 Subject: [PATCH] Cloudstack-2511 Multiple_Ip_Ranges: Adding guest ip range in subset/superset to existing CIDR is allowed Cloudstack-2651 [Shared n/w]Add IP range should ask for gateway and netmask Signed-off-by: Abhinandan Prateek --- .../ConfigurationManagerImpl.java | 119 ++++++++++++------ .../configuration/ValidateIpRangeTest.java | 11 +- utils/src/com/cloud/utils/net/NetUtils.java | 31 +++++ 3 files changed, 116 insertions(+), 45 deletions(-) diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 59e70cfcc5a..111586d7733 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -39,6 +39,7 @@ import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; +import com.cloud.utils.Pair; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.api.ApiConstants.LDAPParams; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; @@ -2473,7 +2474,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - boolean sameSubnet=false; + Pair> sameSubnet= null; // Can add vlan range only to the network which allows it if (!network.getSpecifyIpRanges()) { throw new InvalidParameterValueException("Network " + network + " doesn't support adding ip ranges"); @@ -2508,7 +2509,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati sameSubnet=validateIpRange(startIP,endIP,newVlanGateway, newVlanNetmask, vlans, ipv4, ipv6, ip6Gateway, ip6Cidr, startIPv6, endIPv6, network); } - if (zoneId == null || (ipv4 && (newVlanGateway == null || newVlanNetmask == null)) || (ipv6 && (ip6Gateway == null || ip6Cidr == null))) { + if (zoneId == null || (ipv6 && (ip6Gateway == null || ip6Cidr == null))) { throw new InvalidParameterValueException("Gateway, netmask and zoneId have to be passed in for virtual and direct untagged networks"); } @@ -2527,54 +2528,80 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } Transaction txn = Transaction.currentTxn(); txn.start(); - + if (sameSubnet.first() == false) { + s_logger.info("adding a new subnet to the network "+network.getId()); + } + else { + // 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. + newVlanGateway = sameSubnet.second().first(); + newVlanNetmask = sameSubnet.second().second(); + } Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); //create an entry in the nic_secondary table. This will be the new gateway that will be configured on the corresponding routervm. - if (sameSubnet == false) { - s_logger.info("adding a new subnet to the network "+network.getId()); - } + txn.commit(); return vlan; } - public boolean validateIpRange(String startIP, String endIP, String newVlanGateway, String newVlanNetmask, List vlans, boolean ipv4, boolean ipv6, String ip6Gateway, String ip6Cidr, String startIPv6, String endIPv6, Network network) { - String vlanGateway; - String vlanNetmask; + public int checkIfSubsetOrSuperset(String newVlanGateway, String newVlanNetmask, VlanVO vlan, String startIP, String endIP) { + if (newVlanGateway == null && newVlanNetmask==null) { + newVlanGateway = vlan.getVlanGateway(); + newVlanNetmask = vlan.getVlanNetmask(); + //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 0; + } + else if (newVlanGateway == null || newVlanGateway ==null){ + throw new InvalidParameterValueException("either both netmask and gateway should be passed or both should me omited."); + } + else { + if (!NetUtils.sameSubnet(startIP, newVlanGateway, newVlanNetmask)) { + throw new InvalidParameterValueException("The start ip and gateway do not belong to the same subnet"); + } + if (!NetUtils.sameSubnet(endIP, newVlanGateway, newVlanNetmask)) { + throw new InvalidParameterValueException("The end ip and gateway do not belong to the same subnet"); + } + } + String cidrnew = NetUtils.getCidrFromGatewayAndNetmask(newVlanGateway, newVlanNetmask); + String existing_cidr = NetUtils.getCidrFromGatewayAndNetmask(vlan.getVlanGateway(), vlan.getVlanNetmask()); + + return (NetUtils.isNetowrkASubsetOrSupersetOfNetworkB(cidrnew, existing_cidr)); + } + + public Pair> validateIpRange(String startIP, String endIP, String newVlanGateway, String newVlanNetmask, List vlans, boolean ipv4, boolean ipv6, String ip6Gateway, String ip6Cidr, String startIPv6, String endIPv6, Network network) { + String vlanGateway=null; + String vlanNetmask=null; boolean sameSubnet = false; if ( vlans != null && vlans.size() > 0 ) { - for (VlanVO vlan : vlans) { if (ipv4) { vlanGateway = vlan.getVlanGateway(); vlanNetmask = vlan.getVlanNetmask(); - // Check if ip addresses are in network range - if (!NetUtils.sameSubnet(startIP, vlanGateway, vlanNetmask)) { - if (!NetUtils.sameSubnet(endIP, vlanGateway, vlanNetmask)) { - // check if the the new subnet is not a superset of the existing subnets. - if (NetUtils.isNetworkAWithinNetworkB(NetUtils.getCidrFromGatewayAndNetmask(vlanGateway,vlanNetmask), NetUtils.ipAndNetMaskToCidr(startIP, newVlanNetmask))){ - throw new InvalidParameterValueException ("The new subnet is a superset of the existing subnet"); - } - // check if the new subnet is not a subset of the existing subnet. - if (NetUtils.isNetworkAWithinNetworkB(NetUtils.ipAndNetMaskToCidr(startIP, newVlanNetmask), NetUtils.getCidrFromGatewayAndNetmask(vlanGateway,vlanNetmask))){ - throw new InvalidParameterValueException("The new subnet is a subset of the existing subnet"); - } - } - } else if (NetUtils.sameSubnet(endIP, vlanGateway, vlanNetmask)){ - // trying to add to the same subnet. - sameSubnet = true; - if (newVlanGateway == null) { - newVlanGateway = vlanGateway; - } - if (!newVlanGateway.equals(vlanGateway)){ - throw new InvalidParameterValueException("The gateway of the ip range is not same as the gateway of the subnet."); - } - break; + //check if subset or super set or neither. + int val = checkIfSubsetOrSuperset(newVlanGateway, newVlanNetmask, vlan, startIP, endIP); + if (val == 1) { + // 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 { - throw new InvalidParameterValueException("Start ip and End ip is not in vlan range!"); + else if (val == 0) { + //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) { + //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) { + sameSubnet =true; } } if (ipv6) { @@ -2589,13 +2616,25 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati _networkModel.checkIp6Parameters(startIPv6, endIPv6, ip6Gateway, ip6Cidr); } } - if (sameSubnet == false) { - if (newVlanGateway ==null) { - throw new MissingParameterValueException("The gateway for the new subnet is not specified."); - } - } } - return sameSubnet; + if (newVlanGateway==null && newVlanNetmask ==null && sameSubnet == false) { + throw new InvalidParameterValueException("The ip range dose not belong to any of the existing subnets, Provide the netmask and gateway if you want to add new subnet"); + } + Pair vlanDetails=null; + + if (sameSubnet){ + vlanDetails = new Pair(vlanGateway, vlanNetmask); + } + else { + vlanDetails = new Pair(newVlanGateway, newVlanNetmask); + } + //check if the gatewayip is the part of the ip range being added. + if (NetUtils.ipRangesOverlap(startIP, endIP, vlanDetails.first(), vlanDetails.first())) { + throw new InvalidParameterValueException("The gateway ip should not be the part of the ip range being added."); + } + + Pair> result = new Pair>(sameSubnet, vlanDetails); + return result; } @Override diff --git a/server/test/com/cloud/configuration/ValidateIpRangeTest.java b/server/test/com/cloud/configuration/ValidateIpRangeTest.java index 768166719f2..a083cc643ad 100644 --- a/server/test/com/cloud/configuration/ValidateIpRangeTest.java +++ b/server/test/com/cloud/configuration/ValidateIpRangeTest.java @@ -19,6 +19,7 @@ package com.cloud.configuration; import com.cloud.dc.VlanVO; import com.cloud.network.Network; import com.cloud.network.NetworkModel; +import com.cloud.utils.Pair; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -49,20 +50,20 @@ public class ValidateIpRangeTest { @Test public void SameSubnetTest() { - boolean sameSubnet=configurationMgr.validateIpRange("10.147.33.104", "10.147.33.105", "10.147.33.1", "255.255.255.128", vlanVOList, true, false, null, null, null, null,network); - Assert.assertTrue(sameSubnet); + Pair> sameSubnet=configurationMgr.validateIpRange("10.147.33.104", "10.147.33.105", "10.147.33.1", "255.255.255.128", vlanVOList, true, false, null, null, null, null,network); + Assert.assertTrue(sameSubnet.first()); } @Test public void NewSubnetTest() { - boolean sameSubnet= configurationMgr.validateIpRange("10.147.33.140", "10.147.33.145", "10.147.33.129", "255.255.255.191", vlanVOList, true, false, null, null, null, null,network); - Assert.assertTrue(!sameSubnet); + Pair> sameSubnet= configurationMgr.validateIpRange("10.147.33.140", "10.147.33.145", "10.147.33.129", "255.255.255.191", vlanVOList, true, false, null, null, null, null,network); + Assert.assertTrue(!sameSubnet.first()); } @Test public void SuperSetTest() { try { - configurationMgr.validateIpRange("10.147.33.140", "10.147.33.143", "10.147.33.140", "255.255.255.191", vlanVOList, true, false, null, null, null, null,network); + configurationMgr.validateIpRange("10.147.33.10", "10.147.33.20", "10.147.33.21", "255.255.255.127", vlanVOList, true, false, null, null, null, null,network); } catch (Exception e) { junit.framework.Assert.assertTrue(e.getMessage().contains("superset")); } diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 12ac3e6eb08..ec0ff05fce8 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -795,6 +795,37 @@ public class NetUtils { return new Pair(tokens[0], Integer.parseInt(tokens[1])); } + public static int 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; + } + if (cidrALong[1] >= cidrBLong[1]) { + shift = 32 - cidrBLong[1]; + } + else { + shift = 32 - cidrALong[1]; + } + long result = (cidrALong[0] >> shift) - (cidrBLong[0] >> shift); + if (result == 0) { + if (cidrALong[1] < cidrBLong[1]) { + //this implies cidrA is super set of cidrB + return 1; + } + else if (cidrALong[1] == cidrBLong[1]) { + //this implies both the cidrs are equal + return 3; + } + // implies cidrA is subset of cidrB + return 2; + } + //this implies no overlap. + return 0; + } + public static boolean isNetworkAWithinNetworkB(String cidrA, String cidrB) { Long[] cidrALong = cidrToLong(cidrA); Long[] cidrBLong = cidrToLong(cidrB);