Repository navigation
network: custom DHCP range for isolated networks (API and UI) #14217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1834,10 +1834,23 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac | |
| } | ||
| } | ||
|
|
||
| // For an isolated network a start/end IP defines a custom DHCP range within the CIDR that guest IPs are | ||
| // allocated from; without it the whole CIDR is used, which is the default. Validate it up front so a bad | ||
| // range is rejected before the network is persisted, rather than throwing after commit and leaving an | ||
| // orphaned network. | ||
| boolean hasIsolatedDhcpRange = ntwkOff.getGuestType() == GuestType.Isolated && StringUtils.isNotBlank(startIP); | ||
| if (hasIsolatedDhcpRange) { | ||
| validateIsolatedNetworkDhcpRange(startIP, endIP, cidr, gateway); | ||
| } | ||
|
|
||
| Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zone.getId(), | ||
| domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan, | ||
| externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize, keepMacAddressOnPublicNic); | ||
|
|
||
| if (hasIsolatedDhcpRange) { | ||
| storeIsolatedNetworkDhcpRange(network.getId(), startIP, endIP); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the range is bad this throws after the network is already saved, so does the user end up with a leftover network? could we check the range before creating it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 1bade4b. The range is now validated before commitNetwork via validateIsolatedNetworkDhcpRange, so a range outside the CIDR (or reversed, or over the gateway) is rejected up front and nothing is persisted, no orphaned network. Added a unit test for the validator.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that covers it, the range is checked now before the network is saved |
||
| } | ||
|
|
||
| // retrieve, acquire and associate the correct IP addresses | ||
| checkAndSetRouterSourceNatIp(owner, cmd, network); | ||
|
|
||
|
|
@@ -1872,6 +1885,32 @@ private boolean isNonVpcNetworkSupportingDynamicRouting(NetworkOffering networkO | |
| return !networkOffering.isForVpc() && NetworkOffering.RoutingMode.Dynamic == networkOffering.getRoutingMode(); | ||
| } | ||
|
|
||
| protected void validateIsolatedNetworkDhcpRange(String startIP, String endIP, String cidr, String gateway) { | ||
| if (endIP == null) { | ||
| endIP = startIP; | ||
| } | ||
| if (!NetUtils.isIpWithInCidrRange(startIP, cidr) || !NetUtils.isIpWithInCidrRange(endIP, cidr)) { | ||
| throw new InvalidParameterValueException(String.format("The DHCP range %s-%s is not within the network CIDR %s", startIP, endIP, cidr)); | ||
| } | ||
| if (NetUtils.ip2Long(startIP) > NetUtils.ip2Long(endIP)) { | ||
| throw new InvalidParameterValueException(String.format("The DHCP start IP %s is greater than the end IP %s", startIP, endIP)); | ||
| } | ||
| if (gateway != null && NetUtils.ip2Long(gateway) >= NetUtils.ip2Long(startIP) && NetUtils.ip2Long(gateway) <= NetUtils.ip2Long(endIP)) { | ||
| throw new InvalidParameterValueException(String.format("The DHCP range %s-%s must not include the gateway %s", startIP, endIP, gateway)); | ||
| } | ||
| } | ||
|
|
||
| protected void storeIsolatedNetworkDhcpRange(long networkId, String startIP, String endIP) { | ||
| NetworkVO network = _networksDao.findById(networkId); | ||
| if (endIP == null) { | ||
| endIP = startIP; | ||
| } | ||
| validateIsolatedNetworkDhcpRange(startIP, endIP, network.getCidr(), network.getGateway()); | ||
| network.setDhcpStartIp(startIP); | ||
| network.setDhcpEndIp(endIP); | ||
| _networksDao.update(networkId, network); | ||
| } | ||
|
|
||
| private void validateNetworkCreationSupported(long zoneId, String zoneName, GuestType guestType) { | ||
| NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); | ||
| if (Objects.nonNull(nsxProviderVO) && GuestType.L2.equals(guestType)) { | ||
|
|
@@ -3409,6 +3448,17 @@ public Network updateGuestNetwork(final UpdateNetworkCmd cmd) { | |
| } | ||
| } | ||
|
|
||
| // A custom DHCP range must stay within the reserved Guest VM CIDR; reject a reservation that would | ||
| // leave the stored range partly or wholly outside it, otherwise guest IP allocation could be starved. | ||
| if (StringUtils.isNoneBlank(network.getDhcpStartIp(), network.getDhcpEndIp())) { | ||
| long dhcpStart = NetUtils.ip2Long(network.getDhcpStartIp()); | ||
| long dhcpEnd = NetUtils.ip2Long(network.getDhcpEndIp()); | ||
| if (dhcpStart < startIp || dhcpEnd > endIp) { | ||
| throw new InvalidParameterValueException(String.format("The network has a custom DHCP range %s-%s that falls outside the requested Guest VM CIDR %s. Remove or adjust the DHCP range before applying the reservation.", | ||
| network.getDhcpStartIp(), network.getDhcpEndIp(), guestVmCidr)); | ||
| } | ||
| } | ||
|
|
||
| // In some scenarios even though guesVmCidr and network CIDR do not appear similar but | ||
| // the IP ranges exactly matches, in these special cases make sure no Reservation gets applied | ||
| if (network.getNetworkCidr() == null) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if the network is later shrunk with the guest vm cidr option? the saved range could end up partly outside the new cidr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1bade4b. The updateNetwork guestVmCidr path now rejects a reservation that would leave the stored DHCP range outside the new Guest VM CIDR, with a message to remove or adjust the range first, so the saved range can no longer end up partly outside the CIDR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that covers it, shrinking the network is now refused when the saved range wont fit