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