diff --git a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java index d4c5bf61487..e9f4d9c193e 100644 --- a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java @@ -48,6 +48,13 @@ public interface IpAddressManager { ConfigKey RulesContinueOnError = new ConfigKey("Advanced", Boolean.class, "network.rule.delete.ignoreerror", "true", "When true, ip address delete (ipassoc) failures are ignored", true); + ConfigKey VrouterRedundantTiersPlacement = new ConfigKey( + "Advanced", String.class, + "vrouter.redundant.tiers.placement", + "random", + "Set placement of vrouter ips in redundant mode in vpc tiers, this can be 3 value: `first` to use first ips in tiers, `last` to use last ips in tiers and `random` to take random ips in tiers.", + true, ConfigKey.Scope.Account); + /** * Assigns a new public ip address. * @@ -103,6 +110,12 @@ public interface IpAddressManager { String acquireGuestIpAddress(Network network, String requestedIp); + String acquireFirstGuestIpAddress(Network network); + + String acquireLastGuestIpAddress(Network network); + + String acquireGuestIpAddressByPlacement(Network network, String requestedIp); + boolean applyStaticNats(List staticNats, boolean continueOnError, boolean forRevoke) throws ResourceUnavailableException; IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException; diff --git a/engine/components-api/src/main/java/com/cloud/network/IpPlacement.java b/engine/components-api/src/main/java/com/cloud/network/IpPlacement.java new file mode 100644 index 00000000000..f5a80c9ab37 --- /dev/null +++ b/engine/components-api/src/main/java/com/cloud/network/IpPlacement.java @@ -0,0 +1,34 @@ +package com.cloud.network; + +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +public enum IpPlacement { + Random, + First, + Last; + + + public static IpPlacement fromString(String param) { + switch (param.trim().toLowerCase()) { + case "first": + return First; + case "last": + return Last; + } + return Random; + } +} diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index ddb596a840b..9ad56fc6456 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; +import java.util.Collections; import javax.inject.Inject; @@ -1884,6 +1885,52 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage return NetUtils.long2Ip(array[rand.nextInt(array.length)]); } + @Override + public String acquireFirstGuestIpAddress(Network network) { + if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) { + return null; + } + Set availableIps = _networkModel.getAvailableIps(network, null); + if (availableIps == null || availableIps.isEmpty()) { + s_logger.debug("There are no free ips in the network " + network); + return null; + } + return NetUtils.long2Ip(availableIps.iterator().next()); + } + + @Override + public String acquireLastGuestIpAddress(Network network) { + if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) { + return null; + } + Set availableIps = _networkModel.getAvailableIps(network, null); + if (availableIps == null || availableIps.isEmpty()) { + s_logger.debug("There are no free ips in the network " + network); + return null; + } + + List availableIpsReverse = new ArrayList(availableIps); + Collections.sort(availableIpsReverse, Collections.reverseOrder()); + + return NetUtils.long2Ip(availableIpsReverse.iterator().next()); + } + + @Override + public String acquireGuestIpAddressByPlacement(Network network, String requestedIp) { + if (requestedIp != null) { + return this.acquireGuestIpAddress(network, requestedIp); + } + String placementConfig = VrouterRedundantTiersPlacement.valueIn(network.getAccountId()); + IpPlacement ipPlacement = IpPlacement.fromString(placementConfig); + switch (ipPlacement) { + case Last: + return this.acquireLastGuestIpAddress(network); + case First: + return this.acquireFirstGuestIpAddress(network); + } + return this.acquireGuestIpAddress(network, null); + } + /** * Get the list of public IPs that need to be applied for a static NAT enable/disable operation. * Manipulating only these ips prevents concurrency issues when disabling static nat at the same time. @@ -2175,7 +2222,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness}; + return new ConfigKey[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness, VrouterRedundantTiersPlacement}; } /** diff --git a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java index 19927752ee0..7fb482f74d8 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -372,12 +372,15 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur if (isGateway) { guestIp = network.getGateway(); + } else if (vm.getVirtualMachine().getType() == VirtualMachine.Type.DomainRouter) { + guestIp = _ipAddrMgr.acquireGuestIpAddressByPlacement(network, nic.getRequestedIPv4()); } else { guestIp = _ipAddrMgr.acquireGuestIpAddress(network, nic.getRequestedIPv4()); - if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) { - throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class, - dc.getId()); - } + } + + if (!isGateway && guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) { + throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class, + dc.getId()); } nic.setIPv4Address(guestIp); @@ -464,6 +467,6 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {UseSystemGuestVlans}; + return new ConfigKey[]{UseSystemGuestVlans}; } } diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index a549adbc6b3..39d902ffdf4 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -749,7 +749,7 @@ public class NetworkHelperImpl implements NetworkHelper { final NicProfile gatewayNic = new NicProfile(defaultNetworkStartIp, defaultNetworkStartIpv6); if (routerDeploymentDefinition.isPublicNetwork()) { if (routerDeploymentDefinition.isRedundant()) { - gatewayNic.setIPv4Address(_ipAddrMgr.acquireGuestIpAddress(guestNetwork, null)); + gatewayNic.setIPv4Address(this.acquireGuestIpAddressForVrouterRedundant(guestNetwork)); } else { gatewayNic.setIPv4Address(guestNetwork.getGateway()); } @@ -885,4 +885,8 @@ public class NetworkHelperImpl implements NetworkHelper { } return true; } + + public String acquireGuestIpAddressForVrouterRedundant(Network network) { + return _ipAddrMgr.acquireGuestIpAddressByPlacement(network, null); + } } diff --git a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java index 18ab4a93297..588e83271e9 100644 --- a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java @@ -118,7 +118,7 @@ public class NicProfileHelperImpl implements NicProfileHelper { final NicProfile guestNic = new NicProfile(); if (vpcRouterDeploymentDefinition.isRedundant()) { - guestNic.setIPv4Address(_ipAddrMgr.acquireGuestIpAddress(guestNetwork, null)); + guestNic.setIPv4Address(this.acquireGuestIpAddressForVrouterRedundant(guestNetwork)); } else { guestNic.setIPv4Address(guestNetwork.getGateway()); } @@ -133,4 +133,8 @@ public class NicProfileHelperImpl implements NicProfileHelper { return guestNic; } + public String acquireGuestIpAddressForVrouterRedundant(Network network) { + return _ipAddrMgr.acquireGuestIpAddressByPlacement(network, null); + } + } \ No newline at end of file