Update CIDR/Gateway of the Shared Networks from Guest IP ranges (#11249)

This commit is contained in:
Suresh Kumar Anaparti 2025-07-29 14:00:14 +05:30 committed by GitHub
parent f6ad184ea2
commit 86827f871d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 161 additions and 35 deletions

View File

@ -659,3 +659,8 @@ CALL `cloud`.`INSERT_EXTENSION_CUSTOM_ACTION_DETAILS_IF_NOT_EXISTS`(
'Resume',
'[]'
);
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `cidr` varchar(255) DEFAULT NULL COMMENT 'CloudStack managed vms get IP address from cidr.In general this cidr also serves as the network CIDR. But in case IP reservation feature is being used by a Guest network, networkcidr is the Effective network CIDR for that network';
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `gateway` varchar(255) DEFAULT NULL COMMENT 'gateway(s) for this network configuration';
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_cidr` varchar(1024) DEFAULT NULL COMMENT 'IPv6 cidr(s) for this network';
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_gateway` varchar(1024) DEFAULT NULL COMMENT 'IPv6 gateway(s) for this network';

View File

@ -237,7 +237,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
// get arguments for CreateBcfAttachmentCommand
// determine whether this is VPC network or stand-alone network
Vpc vpc = null;
if(network.getVpcId()!=null){
if (network.getVpcId() != null) {
vpc = _vpcDao.acquireInLockTable(network.getVpcId());
}
@ -264,7 +264,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
String vmwareVswitchLabel = _networkModel.getDefaultGuestTrafficLabel(zoneId, HypervisorType.VMware);
String[] labelArray = null;
String vswitchName = null;
if(vmwareVswitchLabel!=null){
if (vmwareVswitchLabel != null) {
labelArray=vmwareVswitchLabel.split(",");
vswitchName = labelArray[0];
}
@ -273,9 +273,9 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
// kvm: ivs port name
// vmware: specific portgroup naming convention
String pgName = "";
if (dest.getHost().getHypervisorType() == HypervisorType.KVM){
if (dest.getHost().getHypervisorType() == HypervisorType.KVM) {
pgName = hostname;
} else if (dest.getHost().getHypervisorType() == HypervisorType.VMware){
} else if (dest.getHost().getHypervisorType() == HypervisorType.VMware) {
pgName = hostname + "-" + vswitchName;
}
@ -306,7 +306,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
String nicId = nic.getUuid();
String tenantId;
if(network.getVpcId()!=null) {
if (network.getVpcId() != null) {
tenantId = network.getNetworkDomain();
} else {
tenantId = networkId;
@ -439,16 +439,16 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
DataCenterVO zone = _zoneDao.findById(physicalNetwork.getDataCenterId());
String zoneName;
if(zone!= null){
if (zone != null) {
zoneName = zone.getName();
} else {
zoneName = String.valueOf(zoneId);
}
Boolean natNow = _bcfUtils.isNatEnabled();
if (!nat && natNow){
if (!nat && natNow) {
throw new CloudRuntimeException("NAT is enabled in existing controller. Enable NAT for new controller or remove existing controller first.");
} else if (nat && !natNow){
} else if (nat && !natNow) {
throw new CloudRuntimeException("NAT is disabled in existing controller. Disable NAT for new controller or remove existing controller first.");
}
@ -582,7 +582,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
BigSwitchBcfResource bcfResource = (BigSwitchBcfResource) resource;
bcfUtilsInit();
if(_bcfUtils.getTopology()!=null){
if (_bcfUtils.getTopology() != null) {
bcfResource.setTopology(_bcfUtils.getTopology());
}
@ -621,7 +621,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
_bcfUtils.listACLbyNetwork(network);
Vpc vpc = null;
if(network.getVpcId()!=null){
if (network.getVpcId() != null) {
vpc = _vpcDao.acquireInLockTable(network.getVpcId());
}
@ -635,11 +635,11 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
tenantId = network.getUuid();
}
for (StaticNat rule: rules){
for (StaticNat rule: rules) {
String srcIp = _ipAddressDao.findById(rule.getSourceIpAddressId()).getAddress().addr();
String dstIp = rule.getDestIpAddress();
String mac = rule.getSourceMacAddress();
if(!rule.isForRevoke()) {
if (!rule.isForRevoke()) {
logger.debug("BCF enables static NAT for public IP: " + srcIp + " private IP " + dstIp
+ " mac " + mac);
CreateBcfStaticNatCommand cmd = new CreateBcfStaticNatCommand(
@ -671,13 +671,13 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
SubnetUtils utils;
String cidr = null;
List<String> cidrList;
for(NetworkACLItem r: rules){
if(r.getState()==NetworkACLItem.State.Revoke){
for (NetworkACLItem r: rules) {
if (r.getState() == NetworkACLItem.State.Revoke) {
continue;
}
cidrList = r.getSourceCidrList();
if(cidrList != null){
if(cidrList.size()>1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())){
if (cidrList != null) {
if (cidrList.size() > 1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())) {
throw new ResourceUnavailableException("One CIDR and one port only please.",
Network.class, network.getId());
} else {
@ -688,7 +688,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
cidr = "";
} else {
utils = new SubnetUtils(cidr);
if(!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())){
if (!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())) {
throw new ResourceUnavailableException("Invalid CIDR in Network ACL rule.",
Network.class, network.getId());
}
@ -710,13 +710,13 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
SubnetUtils utils;
String cidr = null;
List<String> cidrList;
for(FirewallRule r: rules){
if(r.getState()==FirewallRule.State.Revoke){
for (FirewallRule r: rules) {
if (r.getState() == FirewallRule.State.Revoke) {
continue;
}
cidrList = r.getSourceCidrList();
if(cidrList != null){
if(cidrList.size()>1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())){
if (cidrList != null) {
if (cidrList.size()>1 || !r.getSourcePortEnd().equals(r.getSourcePortStart())) {
throw new ResourceUnavailableException("One CIDR and one port only please.",
Network.class, network.getId());
} else {
@ -727,7 +727,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
cidr = "";
} else {
utils = new SubnetUtils(cidr);
if(!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())){
if (!utils.getInfo().getNetworkAddress().equals(utils.getInfo().getAddress())) {
throw new ResourceUnavailableException("Invalid CIDR in Firewall rule.",
Network.class, network.getId());
}
@ -741,7 +741,7 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
bcfUtilsInit();
Vpc vpc = null;
if(network.getVpcId()!=null){
if (network.getVpcId() != null) {
vpc = _vpcDao.acquireInLockTable(network.getVpcId());
}
@ -756,23 +756,23 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
UpdateBcfRouterCommand cmd = new UpdateBcfRouterCommand(tenantId);
List<AclData> aclList = _bcfUtils.listACLbyNetwork(network);
for(AclData acl: aclList){
for (AclData acl: aclList) {
cmd.addAcl(acl);
}
if(vpc != null){
if (vpc != null) {
cmd.setPublicIp(_bcfUtils.getPublicIpByVpc(vpc));
} else {
cmd.setPublicIp(_bcfUtils.getPublicIpByNetwork(network));
}
BcfAnswer answer = _bcfUtils.sendBcfCommandWithNetworkSyncCheck(cmd, network);
if(answer != null && !answer.getResult()){
if (answer != null && !answer.getResult()) {
throw new IllegalArgumentException("Illegal router update arguments");
}
}
private void bcfUtilsInit(){
private void bcfUtilsInit() {
if (_bcfUtils == null) {
_bcfUtils = new BigSwitchBcfUtils(_networkDao, _nicDao,
_vmDao, _hostDao, _vpcDao, _bigswitchBcfDao,

View File

@ -2539,10 +2539,11 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setType(network.getGuestType().toString());
}
response.setGateway(network.getGateway());
response.setGateway(com.cloud.utils.StringUtils.getFirstValueFromCommaSeparatedString(network.getGateway()));
String cidr = com.cloud.utils.StringUtils.getFirstValueFromCommaSeparatedString(network.getCidr());
// FIXME - either set netmask or cidr
response.setCidr(network.getCidr());
response.setCidr(cidr);
if (network.getNetworkCidr() != null) {
response.setNetworkCidr((network.getNetworkCidr()));
}
@ -2553,18 +2554,18 @@ public class ApiResponseHelper implements ResponseGenerator {
if (network.getNetworkCidr() != null) {
response.setNetmask(NetUtils.cidr2Netmask(network.getNetworkCidr()));
}
if (((network.getCidr()) != null) && (network.getNetworkCidr() == null)) {
response.setNetmask(NetUtils.cidr2Netmask(network.getCidr()));
if ((cidr != null) && (network.getNetworkCidr() == null)) {
response.setNetmask(NetUtils.cidr2Netmask(cidr));
}
response.setIp6Gateway(network.getIp6Gateway());
response.setIp6Cidr(network.getIp6Cidr());
response.setIp6Gateway(com.cloud.utils.StringUtils.getFirstValueFromCommaSeparatedString(network.getIp6Gateway()));
response.setIp6Cidr(com.cloud.utils.StringUtils.getFirstValueFromCommaSeparatedString(network.getIp6Cidr()));
// create response for reserved IP ranges that can be used for
// non-cloudstack purposes
String reservation = null;
if ((network.getCidr() != null) && (NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr()))) {
String[] guestVmCidrPair = network.getCidr().split("\\/");
if ((cidr != null) && (NetUtils.isNetworkAWithinNetworkB(cidr, network.getNetworkCidr()))) {
String[] guestVmCidrPair = cidr.split("\\/");
String[] guestCidrPair = network.getNetworkCidr().split("\\/");
Long guestVmCidrSize = Long.valueOf(guestVmCidrPair[1]);

View File

@ -5397,9 +5397,42 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr,
ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms, provider);
if (vlan != null) {
if (ipv4) {
addCidrAndGatewayForIpv4(networkId, vlanGateway, vlanNetmask);
} else if (ipv6) {
addCidrAndGatewayForIpv6(networkId, vlanIp6Gateway, vlanIp6Cidr);
}
}
return vlan;
}
private void addCidrAndGatewayForIpv4(final long networkId, final String vlanGateway, final String vlanNetmask) {
final NetworkVO networkVO = _networkDao.findById(networkId);
String networkCidr = networkVO.getCidr();
String newCidr = NetUtils.getCidrFromGatewayAndNetmask(vlanGateway, vlanNetmask);
String newNetworkCidr = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkCidr, newCidr, true);
networkVO.setCidr(newNetworkCidr);
String networkGateway = networkVO.getGateway();
String newNetworkGateway = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkGateway, vlanGateway, true);
networkVO.setGateway(newNetworkGateway);
_networkDao.update(networkId, networkVO);
}
private void addCidrAndGatewayForIpv6(final long networkId, final String vlanIp6Gateway, final String vlanIp6Cidr) {
final NetworkVO networkVO = _networkDao.findById(networkId);
String networkIp6Cidr = networkVO.getIp6Cidr();
String newNetworkIp6Cidr = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkIp6Cidr, vlanIp6Cidr, true);
networkVO.setIp6Cidr(newNetworkIp6Cidr);
String networkIp6Gateway = networkVO.getIp6Gateway();
String newNetworkIp6Gateway = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkIp6Gateway, vlanIp6Gateway, true);
networkVO.setIp6Gateway(newNetworkIp6Gateway);
_networkDao.update(networkId, networkVO);
}
private boolean isConnectivityWithoutVlan(Network network) {
boolean connectivityWithoutVlan = false;
if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Connectivity)) {
@ -6440,12 +6473,47 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
private boolean deleteAndPublishVlanAndPublicIpRange(final long userId, final long vlanDbId, final Account caller) {
VlanVO deletedVlan = deleteVlanAndPublicIpRange(userId, vlanDbId, caller);
if (deletedVlan != null) {
final boolean ipv4 = deletedVlan.getVlanGateway() != null;
final boolean ipv6 = deletedVlan.getIp6Gateway() != null;
final long networkId = deletedVlan.getNetworkId();
if (ipv4) {
removeCidrAndGatewayForIpv4(networkId, deletedVlan);
} else if (ipv6) {
removeCidrAndGatewayForIpv6(networkId, deletedVlan);
}
messageBus.publish(_name, MESSAGE_DELETE_VLAN_IP_RANGE_EVENT, PublishScope.LOCAL, deletedVlan);
return true;
}
return false;
}
private void removeCidrAndGatewayForIpv4(final long networkId, VlanVO deletedVlan) {
final NetworkVO networkVO = _networkDao.findById(networkId);
String networkCidr = networkVO.getCidr();
String cidrToRemove = NetUtils.getCidrFromGatewayAndNetmask(deletedVlan.getVlanGateway(), deletedVlan.getVlanNetmask());
String newNetworkCidr = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkCidr, cidrToRemove, false);
networkVO.setCidr(newNetworkCidr);
String networkGateway = networkVO.getGateway();
String newNetworkGateway = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkGateway, deletedVlan.getVlanGateway(), false);
networkVO.setGateway(newNetworkGateway);
_networkDao.update(networkId, networkVO);
}
private void removeCidrAndGatewayForIpv6(final long networkId, VlanVO deletedVlan) {
final NetworkVO networkVO = _networkDao.findById(networkId);
String networkIp6Cidr = networkVO.getIp6Cidr();
String newNetworkIp6Cidr = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkIp6Cidr, deletedVlan.getIp6Cidr(), false);
networkVO.setIp6Cidr(newNetworkIp6Cidr);
String networkIp6Gateway = networkVO.getIp6Gateway();
String newNetworkIp6Gateway = com.cloud.utils.StringUtils.updateCommaSeparatedStringWithValue(networkIp6Gateway, deletedVlan.getIp6Gateway(), false);
networkVO.setIp6Gateway(newNetworkIp6Gateway);
_networkDao.update(networkId, networkVO);
}
@Override
public void checkDiskOfferingAccess(final Account caller, final DiskOffering dof, DataCenter zone) {
for (final SecurityChecker checker : _secChecker) {

View File

@ -24,14 +24,17 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class StringUtils extends org.apache.commons.lang3.StringUtils {
private static final char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
@ -409,4 +412,53 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
String[] finalMergedTagsArray = appendedTags.split(",");
return finalMergedTagsArray;
}
/**
* Converts the comma separated numbers and ranges to numbers
* @param originalString the original string (can be null or empty) containing list of comma separated values that has to be updated
* @param value the value to add to, or remove from the original string
* @param add if true, adds the input value; if false, removes it
* @return String containing the modified original string (or null if empty)
*/
public static String updateCommaSeparatedStringWithValue(String originalString, String value, boolean add) {
if (org.apache.commons.lang3.StringUtils.isEmpty(value)) {
return originalString;
}
Set<String> values = new LinkedHashSet<>();
if (org.apache.commons.lang3.StringUtils.isNotEmpty(originalString)) {
values.addAll(Arrays.stream(originalString.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList()));
}
if (add) {
values.add(value);
} else {
values.remove(value);
}
return values.isEmpty() ? null : String.join(",", values);
}
/**
* Returns the first value from a comma-separated string.
* @param inputString the input string (can be null or empty) containing list of comma separated values
* @return the first value, or null if none found
*/
public static String getFirstValueFromCommaSeparatedString(String inputString) {
if (org.apache.commons.lang3.StringUtils.isEmpty(inputString)) {
return inputString;
}
String[] values = inputString.split(",");
if (values.length > 0) {
return values[0].trim();
}
return null;
}
}