Committed by
Gerrit Code Review
Fixes deadlock in dhcp ip assignment logic caused by nesting calls to distributed primitives.
Change-Id: I25acd37cbf3800ad260c672c99e9f630435f0f88
Showing
1 changed file
with
72 additions
and
79 deletions
| ... | @@ -25,13 +25,11 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -25,13 +25,11 @@ import org.apache.felix.scr.annotations.Service; |
| 25 | import org.onlab.packet.Ip4Address; | 25 | import org.onlab.packet.Ip4Address; |
| 26 | import org.onlab.packet.MacAddress; | 26 | import org.onlab.packet.MacAddress; |
| 27 | import org.onlab.util.KryoNamespace; | 27 | import org.onlab.util.KryoNamespace; |
| 28 | -import org.onlab.util.Tools; | ||
| 29 | import org.onosproject.dhcp.DhcpStore; | 28 | import org.onosproject.dhcp.DhcpStore; |
| 30 | import org.onosproject.dhcp.IpAssignment; | 29 | import org.onosproject.dhcp.IpAssignment; |
| 31 | import org.onosproject.net.HostId; | 30 | import org.onosproject.net.HostId; |
| 32 | import org.onosproject.store.serializers.KryoNamespaces; | 31 | import org.onosproject.store.serializers.KryoNamespaces; |
| 33 | import org.onosproject.store.service.ConsistentMap; | 32 | import org.onosproject.store.service.ConsistentMap; |
| 34 | -import org.onosproject.store.service.ConsistentMapException; | ||
| 35 | import org.onosproject.store.service.DistributedSet; | 33 | import org.onosproject.store.service.DistributedSet; |
| 36 | import org.onosproject.store.service.Serializer; | 34 | import org.onosproject.store.service.Serializer; |
| 37 | import org.onosproject.store.service.StorageService; | 35 | import org.onosproject.store.service.StorageService; |
| ... | @@ -44,7 +42,6 @@ import java.util.Map; | ... | @@ -44,7 +42,6 @@ import java.util.Map; |
| 44 | import java.util.List; | 42 | import java.util.List; |
| 45 | import java.util.HashMap; | 43 | import java.util.HashMap; |
| 46 | import java.util.Objects; | 44 | import java.util.Objects; |
| 47 | -import java.util.concurrent.atomic.AtomicBoolean; | ||
| 48 | 45 | ||
| 49 | /** | 46 | /** |
| 50 | * Manages the pool of available IP Addresses in the network and | 47 | * Manages the pool of available IP Addresses in the network and |
| ... | @@ -172,83 +169,79 @@ public class DistributedDhcpStore implements DhcpStore { | ... | @@ -172,83 +169,79 @@ public class DistributedDhcpStore implements DhcpStore { |
| 172 | List<Ip4Address> addressList) { | 169 | List<Ip4Address> addressList) { |
| 173 | log.debug("Assign IP Called w/ Ip4Address: {}, HostId: {}", ipAddr.toString(), hostId.mac().toString()); | 170 | log.debug("Assign IP Called w/ Ip4Address: {}, HostId: {}", ipAddr.toString(), hostId.mac().toString()); |
| 174 | 171 | ||
| 175 | - AtomicBoolean assigned = Tools.retryable(() -> { | 172 | + Versioned<IpAssignment> currentAssignment = allocationMap.get(hostId); |
| 176 | - AtomicBoolean result = new AtomicBoolean(false); | 173 | + IpAssignment newAssignment = null; |
| 177 | - allocationMap.compute( | 174 | + if (currentAssignment == null) { |
| 178 | - hostId, | 175 | + if (rangeNotEnforced) { |
| 179 | - (h, existingAssignment) -> { | 176 | + newAssignment = IpAssignment.builder() |
| 180 | - IpAssignment assignment = existingAssignment; | 177 | + .ipAddress(ipAddr) |
| 181 | - if (existingAssignment == null) { | 178 | + .timestamp(new Date()) |
| 182 | - if (rangeNotEnforced) { | 179 | + .leasePeriod(leaseTime) |
| 183 | - assignment = IpAssignment.builder() | 180 | + .rangeNotEnforced(true) |
| 184 | - .ipAddress(ipAddr) | 181 | + .assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced) |
| 185 | - .timestamp(new Date()) | 182 | + .subnetMask((Ip4Address) addressList.toArray()[0]) |
| 186 | - .leasePeriod(leaseTime) | 183 | + .dhcpServer((Ip4Address) addressList.toArray()[1]) |
| 187 | - .rangeNotEnforced(true) | 184 | + .routerAddress((Ip4Address) addressList.toArray()[2]) |
| 188 | - .assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced) | 185 | + .domainServer((Ip4Address) addressList.toArray()[3]) |
| 189 | - .subnetMask((Ip4Address) addressList.toArray()[0]) | 186 | + .build(); |
| 190 | - .dhcpServer((Ip4Address) addressList.toArray()[1]) | ||
| 191 | - .routerAddress((Ip4Address) addressList.toArray()[2]) | ||
| 192 | - .domainServer((Ip4Address) addressList.toArray()[3]) | ||
| 193 | - .build(); | ||
| 194 | - result.set(true); | ||
| 195 | - } else if (freeIPPool.remove(ipAddr)) { | ||
| 196 | - assignment = IpAssignment.builder() | ||
| 197 | - .ipAddress(ipAddr) | ||
| 198 | - .timestamp(new Date()) | ||
| 199 | - .leasePeriod(leaseTime) | ||
| 200 | - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 201 | - .build(); | ||
| 202 | - result.set(true); | ||
| 203 | - } | ||
| 204 | - } else if (Objects.equals(existingAssignment.ipAddress(), ipAddr) && | ||
| 205 | - (existingAssignment.rangeNotEnforced() || ipWithinRange(ipAddr))) { | ||
| 206 | - switch (existingAssignment.assignmentStatus()) { | ||
| 207 | - case Option_RangeNotEnforced: | ||
| 208 | - assignment = IpAssignment.builder() | ||
| 209 | - .ipAddress(ipAddr) | ||
| 210 | - .timestamp(new Date()) | ||
| 211 | - .leasePeriod(existingAssignment.leasePeriod()) | ||
| 212 | - .rangeNotEnforced(true) | ||
| 213 | - .assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced) | ||
| 214 | - .subnetMask(existingAssignment.subnetMask()) | ||
| 215 | - .dhcpServer(existingAssignment.dhcpServer()) | ||
| 216 | - .routerAddress(existingAssignment.routerAddress()) | ||
| 217 | - .domainServer(existingAssignment.domainServer()) | ||
| 218 | - .build(); | ||
| 219 | - result.set(true); | ||
| 220 | - break; | ||
| 221 | - case Option_Assigned: | ||
| 222 | - case Option_Requested: | ||
| 223 | - assignment = IpAssignment.builder() | ||
| 224 | - .ipAddress(ipAddr) | ||
| 225 | - .timestamp(new Date()) | ||
| 226 | - .leasePeriod(leaseTime) | ||
| 227 | - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 228 | - .build(); | ||
| 229 | - result.set(true); | ||
| 230 | - break; | ||
| 231 | - case Option_Expired: | ||
| 232 | - if (freeIPPool.remove(ipAddr)) { | ||
| 233 | - assignment = IpAssignment.builder() | ||
| 234 | - .ipAddress(ipAddr) | ||
| 235 | - .timestamp(new Date()) | ||
| 236 | - .leasePeriod(leaseTime) | ||
| 237 | - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 238 | - .build(); | ||
| 239 | - result.set(true); | ||
| 240 | - } | ||
| 241 | - break; | ||
| 242 | - default: | ||
| 243 | - break; | ||
| 244 | - } | ||
| 245 | - } | ||
| 246 | - return assignment; | ||
| 247 | - }); | ||
| 248 | - return result; | ||
| 249 | - }, ConsistentMapException.class, MAX_RETRIES, MAX_BACKOFF).get(); | ||
| 250 | 187 | ||
| 251 | - return assigned.get(); | 188 | + } else if (freeIPPool.remove(ipAddr)) { |
| 189 | + newAssignment = IpAssignment.builder() | ||
| 190 | + .ipAddress(ipAddr) | ||
| 191 | + .timestamp(new Date()) | ||
| 192 | + .leasePeriod(leaseTime) | ||
| 193 | + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 194 | + .build(); | ||
| 195 | + } else { | ||
| 196 | + return false; | ||
| 197 | + } | ||
| 198 | + return allocationMap.putIfAbsent(hostId, newAssignment) == null; | ||
| 199 | + // TODO: handle the case where map changed. | ||
| 200 | + } else { | ||
| 201 | + IpAssignment existingAssignment = currentAssignment.value(); | ||
| 202 | + if (Objects.equals(existingAssignment.ipAddress(), ipAddr) && | ||
| 203 | + (existingAssignment.rangeNotEnforced() || ipWithinRange(ipAddr))) { | ||
| 204 | + switch (existingAssignment.assignmentStatus()) { | ||
| 205 | + case Option_RangeNotEnforced: | ||
| 206 | + newAssignment = IpAssignment.builder() | ||
| 207 | + .ipAddress(ipAddr) | ||
| 208 | + .timestamp(new Date()) | ||
| 209 | + .leasePeriod(existingAssignment.leasePeriod()) | ||
| 210 | + .rangeNotEnforced(true) | ||
| 211 | + .assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced) | ||
| 212 | + .subnetMask(existingAssignment.subnetMask()) | ||
| 213 | + .dhcpServer(existingAssignment.dhcpServer()) | ||
| 214 | + .routerAddress(existingAssignment.routerAddress()) | ||
| 215 | + .domainServer(existingAssignment.domainServer()) | ||
| 216 | + .build(); | ||
| 217 | + break; | ||
| 218 | + case Option_Assigned: | ||
| 219 | + case Option_Requested: | ||
| 220 | + newAssignment = IpAssignment.builder() | ||
| 221 | + .ipAddress(ipAddr) | ||
| 222 | + .timestamp(new Date()) | ||
| 223 | + .leasePeriod(leaseTime) | ||
| 224 | + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 225 | + .build(); | ||
| 226 | + break; | ||
| 227 | + case Option_Expired: | ||
| 228 | + if (freeIPPool.remove(ipAddr)) { | ||
| 229 | + newAssignment = IpAssignment.builder() | ||
| 230 | + .ipAddress(ipAddr) | ||
| 231 | + .timestamp(new Date()) | ||
| 232 | + .leasePeriod(leaseTime) | ||
| 233 | + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) | ||
| 234 | + .build(); | ||
| 235 | + } | ||
| 236 | + break; | ||
| 237 | + default: | ||
| 238 | + break; | ||
| 239 | + } | ||
| 240 | + return allocationMap.replace(hostId, currentAssignment.version(), newAssignment); | ||
| 241 | + } else { | ||
| 242 | + return false; | ||
| 243 | + } | ||
| 244 | + } | ||
| 252 | } | 245 | } |
| 253 | 246 | ||
| 254 | @Override | 247 | @Override | ... | ... |
-
Please register or login to post a comment