This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 86827f871d2 Update CIDR/Gateway of the Shared Networks from Guest IP
ranges (#11249)
86827f871d2 is described below
commit 86827f871d24def41c5c8cf6d8b7bad910979a55
Author: Suresh Kumar Anaparti <[email protected]>
AuthorDate: Tue Jul 29 14:00:14 2025 +0530
Update CIDR/Gateway of the Shared Networks from Guest IP ranges (#11249)
---
.../resources/META-INF/db/schema-42010to42100.sql | 5 ++
.../cloud/network/element/BigSwitchBcfElement.java | 54 ++++++++---------
.../main/java/com/cloud/api/ApiResponseHelper.java | 17 +++---
.../configuration/ConfigurationManagerImpl.java | 68 ++++++++++++++++++++++
.../src/main/java/com/cloud/utils/StringUtils.java | 52 +++++++++++++++++
5 files changed, 161 insertions(+), 35 deletions(-)
diff --git
a/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql
b/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql
index 103b9363d6c..4c7fe74cbcd 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql
@@ -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';
diff --git
a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java
b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java
index adb957c3b5e..db0efd71b1d 100644
---
a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java
+++
b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java
@@ -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,
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index a4dafd60562..0293e0d08fb 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -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]);
diff --git
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index a60b84bf2b6..03b97af4e10 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -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) {
diff --git a/utils/src/main/java/com/cloud/utils/StringUtils.java
b/utils/src/main/java/com/cloud/utils/StringUtils.java
index 3e4e970af2e..94295e3bb2e 100644
--- a/utils/src/main/java/com/cloud/utils/StringUtils.java
+++ b/utils/src/main/java/com/cloud/utils/StringUtils.java
@@ -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;
+ }
}