Skip to content

Commit 646c894

Browse files
authored
Fix for race when automatically assigning IP to Vms (#9240)
* Fix for race when automatically assigning IP to Vms * code refactor
1 parent d4446ee commit 646c894

3 files changed

Lines changed: 76 additions & 25 deletions

File tree

api/src/main/java/com/cloud/vm/NicProfile.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class NicProfile implements InternalIdentity, Serializable {
6262
String iPv4Dns1;
6363
String iPv4Dns2;
6464
String requestedIPv4;
65+
boolean ipv4AllocationRaceCheck;
6566

6667
// IPv6
6768
String iPv6Address;
@@ -405,6 +406,13 @@ public void setMtu(Integer mtu) {
405406
this.mtu = mtu;
406407
}
407408

409+
public boolean getIpv4AllocationRaceCheck() {
410+
return this.ipv4AllocationRaceCheck;
411+
}
412+
413+
public void setIpv4AllocationRaceCheck(boolean ipv4AllocationRaceCheck) {
414+
this.ipv4AllocationRaceCheck = ipv4AllocationRaceCheck;
415+
}
408416

409417
//
410418
// OTHER METHODS

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,42 +1020,84 @@ public void saveExtraDhcpOptions(final String networkUuid, final Long nicId, fin
10201020
}
10211021
}
10221022

1023-
@DB
1024-
@Override
1025-
public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
1026-
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException {
1023+
private NicVO persistNicAfterRaceCheck(final NicVO nic, final Long networkId, final NicProfile profile, int deviceId) {
1024+
return Transaction.execute(new TransactionCallback<NicVO>() {
1025+
@Override
1026+
public NicVO doInTransaction(TransactionStatus status) {
1027+
NicVO vo = _nicDao.findByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId);
1028+
if (vo == null) {
1029+
applyProfileToNic(nic, profile, deviceId);
1030+
vo = _nicDao.persist(nic);
1031+
return vo;
1032+
} else {
1033+
return null;
1034+
}
1035+
}
1036+
});
1037+
}
10271038

1039+
private NicVO checkForRaceAndAllocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
1040+
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
10281041
final NetworkVO ntwkVO = _networksDao.findById(network.getId());
10291042
s_logger.debug("Allocating nic for vm " + vm.getVirtualMachine() + " in network " + network + " with requested profile " + requested);
10301043
final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, ntwkVO.getGuruName());
10311044

1032-
if (requested != null && requested.getMode() == null) {
1033-
requested.setMode(network.getMode());
1034-
}
1035-
final NicProfile profile = guru.allocate(network, requested, vm);
1036-
if (profile == null) {
1037-
return null;
1038-
}
1045+
NicVO vo = null;
1046+
boolean retryIpAllocation;
1047+
do {
1048+
retryIpAllocation = false;
1049+
final NicProfile profile = guru.allocate(network, requested, vm);
1050+
if (profile == null) {
1051+
return null;
1052+
}
10391053

1040-
if (isDefaultNic != null) {
1041-
profile.setDefaultNic(isDefaultNic);
1042-
}
1054+
if (isDefaultNic != null) {
1055+
profile.setDefaultNic(isDefaultNic);
1056+
}
10431057

1044-
if (requested != null && requested.getMode() == null) {
1045-
profile.setMode(requested.getMode());
1046-
} else {
1047-
profile.setMode(network.getMode());
1048-
}
1058+
if (requested != null && requested.getMode() == null) {
1059+
profile.setMode(requested.getMode());
1060+
} else {
1061+
profile.setMode(network.getMode());
1062+
}
1063+
1064+
vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType());
1065+
1066+
DataCenterVO dcVo = _dcDao.findById(network.getDataCenterId());
1067+
if (dcVo.getNetworkType() == NetworkType.Basic) {
1068+
configureNicProfileBasedOnRequestedIp(requested, profile, network);
1069+
}
1070+
1071+
if (profile.getIpv4AllocationRaceCheck()) {
1072+
vo = persistNicAfterRaceCheck(vo, network.getId(), profile, deviceId);
1073+
} else {
1074+
applyProfileToNic(vo, profile, deviceId);
1075+
vo = _nicDao.persist(vo);
1076+
}
1077+
1078+
if (vo == null) {
1079+
if (requested.getRequestedIPv4() != null) {
1080+
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire requested Guest IP address " + requested.getRequestedIPv4() + " for network " + network, DataCenter.class, dcVo.getId());
1081+
} else {
1082+
requested.setIPv4Address(null);
1083+
}
1084+
retryIpAllocation = true;
1085+
}
1086+
} while (retryIpAllocation);
10491087

1050-
NicVO vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType());
1088+
return vo;
1089+
}
10511090

1052-
DataCenterVO dcVo = _dcDao.findById(network.getDataCenterId());
1053-
if (dcVo.getNetworkType() == NetworkType.Basic) {
1054-
configureNicProfileBasedOnRequestedIp(requested, profile, network);
1091+
@DB
1092+
@Override
1093+
public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
1094+
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException {
1095+
1096+
if (requested != null && requested.getMode() == null) {
1097+
requested.setMode(network.getMode());
10551098
}
10561099

1057-
deviceId = applyProfileToNic(vo, profile, deviceId);
1058-
vo = _nicDao.persist(vo);
1100+
NicVO vo = checkForRaceAndAllocateNic(requested, network, isDefaultNic, deviceId, vm);
10591101

10601102
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
10611103
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),

server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ public NicProfile allocate(final Network network, NicProfile nic, final VirtualM
441441
} else {
442442
guestIp = _ipAddrMgr.acquireGuestIpAddress(network, nic.getRequestedIPv4());
443443
}
444+
nic.setIpv4AllocationRaceCheck(true);
444445
}
445446
if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
446447
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class,

0 commit comments

Comments
 (0)