prashanthr2 opened a new issue, #14419:
URL: https://github.com/apache/cloudstack/issues/14419
### problem
For routed networks and routed VPCs, CloudStack treats a guest CIDR as
unique across the entire installation rather than per zone. Creating a routed
VPC with CIDR 10.0.0.0/8 in zone A and then the same CIDR in zone B fails with
The subnet is in use, even though the two zones are independent L3 domains with
separate fabrics.
Routed networks are inherently zone-scoped , they are tied to that zone’s
routing fabric, and the parent table dc_ip4_guest_subnets is explicitly
per-zone via data_center_id. The uniqueness check therefore looks over-strict
rather than intentional, and it blocks a common active/passive DR pattern where
the standby zone deliberately uses the same addressing as the primary.
### versions
4.22.1
### The steps to reproduce the bug
1. Enable routed networks/VPCs. Do not configure any zone IPv4 guest subnets.
2. As root admin, create a routed VPC in zone A with cidr=10.0.0.0/8 ->
succeeds
3. As root admin, create a routed VPC in zone B with cidr=10.0.0.0/8 ->
fails (Request failed (431): The subnet is in use)
### What to do about it?
RoutedIpv4ManagerImpl.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(String
networkCidr, ...) (line 652 in 4.22.1.0) performs an exact-match lookup with no
zone qualifier:
```
Ipv4GuestSubnetNetworkMapVO subnetMap =
ipv4GuestSubnetNetworkMapDao.findBySubnet(networkCidr);
if (subnetMap != null) {
// check if the subnet is in use
if (subnetMap.getNetworkId() != null || subnetMap.getVpcId() != null) {
throw new InvalidParameterValueException("The subnet is in use");
}
```
Ipv4GuestSubnetNetworkMapDaoImpl.findBySubnet() (line 145) uses a search
builder with only a subnet predicate (line 71):
```
SubnetSearch = createSearchBuilder();
SubnetSearch.and("subnet", SubnetSearch.entity().getSubnet(),
SearchCriteria.Op.EQ);
SubnetSearch.done();
```
The underlying table has no zone column at all — Ipv4GuestSubnetNetworkMapVO
(@Table(name = "ip4_guest_subnet_network_map")) exposes only id, uuid,
parent_id, subnet, vpc_id, network_id, state, allocated, created, removed. Zone
is reachable only indirectly through parent_id →
dc_ip4_guest_subnets.data_center_id.
This makes the registry internally inconsistent: rows with a parent are
implicitly zone-scoped, while parentless rows carry no zone information
whatsoever and therefore block their CIDR installation-wide. Parentless rows
are the normal case when no zone subnets are configured —
getParentOfNetworkCidr() returns null and the row is created with parentId =
null.
Both entry points funnel into the same method, so routed VPCs and plain
routed isolated networks are equally affected:
* getOrCreateIpv4SubnetForVpc(Vpc, String)
* getOrCreateIpv4SubnetForGuestNetwork(Network, String)
Evidence from a reproduction — one parentless row blocking the CIDR globally:
```
mysql> SELECT m.id, m.subnet, m.state, m.parent_id, m.network_id, m.vpc_id,
v.name AS vpc_name, v.zone_id AS vpc_zone
FROM cloud.ip4_guest_subnet_network_map m
LEFT JOIN cloud.vpc v ON v.id = m.vpc_id
WHERE m.subnet = '10.0.0.0/8';
+----+------------+-----------+-----------+------------+--------+-----------+----------+
| id | subnet | state | parent_id | network_id | vpc_id | vpc_name
| vpc_zone |
+----+------------+-----------+-----------+------------+--------+-----------+----------+
| 3 | 10.0.0.0/8 | Allocated | NULL | NULL | 5 | RouteVPC2
| 2 |
+----+------------+-----------+-----------+------------+--------+-----------+----------+
```
For contrast, non-routed VPCs have no CIDR uniqueness check at all —
VpcManagerImpl.createVpc() validates only that the CIDR is a valid IPv4 CIDR
and RFC1918-compliant — so the same CIDR in two zones works there. The
restriction is specific to the routed path.
**SUGGESTED FIX**
Scope the lookup to the zone:
1. Add a data_center_id column to ip4_guest_subnet_network_map, populated on
creation. This is required because parentless rows have no other path to a zone.
2. Add a zone predicate to SubnetSearch / findBySubnet() and pass zoneId
from the callers (already available in
getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal).
3. Apply the same scoping to the overlap check in getParentOfNetworkCidr(),
which uses listAllNoParent() and is likewise installation-wide.
4. Upgrade: backfill data_center_id from vpc.zone_id /
networks.data_center_id for allocated rows, and from
dc_ip4_guest_subnets.data_center_id where a parent exists.
**WORKAROUNDS**
1. Use a non-routed (NAT) VPC offering in the second zone — identical CIDRs
work today.
2. Use different CIDRs per zone.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]