blob: 0f25495e17c8fc769a9dbcc7ba1621ab2160d43d [file] [log] [blame]
samanwita palf28207b2015-09-04 10:41:56 -07001/*
Thomas Vachuska54dc3522015-09-09 00:11:45 -07002 * Copyright 2015 Open Networking Laboratory
samanwita palf28207b2015-09-04 10:41:56 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.dhcp.impl;
17
18import com.google.common.collect.ImmutableSet;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
samanwita palf28207b2015-09-04 10:41:56 -070025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.MacAddress;
27import org.onlab.util.KryoNamespace;
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070028import org.onosproject.dhcp.DhcpStore;
29import org.onosproject.dhcp.IpAssignment;
samanwita pal2a313402015-09-14 16:03:22 -070030import org.onosproject.net.HostId;
samanwita palf28207b2015-09-04 10:41:56 -070031import org.onosproject.store.serializers.KryoNamespaces;
32import org.onosproject.store.service.ConsistentMap;
33import org.onosproject.store.service.DistributedSet;
34import org.onosproject.store.service.Serializer;
35import org.onosproject.store.service.StorageService;
36import org.onosproject.store.service.Versioned;
37import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40import java.util.Date;
samanwita palf28207b2015-09-04 10:41:56 -070041import java.util.Map;
danielcd9deed2015-10-30 17:16:16 +090042import java.util.List;
43import java.util.HashMap;
samanwita pal0bff4302015-09-15 13:37:00 -070044import java.util.Objects;
samanwita palf28207b2015-09-04 10:41:56 -070045
46/**
47 * Manages the pool of available IP Addresses in the network and
48 * Remembers the mapping between MAC ID and IP Addresses assigned.
49 */
50
51@Component(immediate = true)
52@Service
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070053public class DistributedDhcpStore implements DhcpStore {
samanwita palf28207b2015-09-04 10:41:56 -070054
55 private final Logger log = LoggerFactory.getLogger(getClass());
56
57 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected StorageService storageService;
59
samanwita pal2a313402015-09-14 16:03:22 -070060 private ConsistentMap<HostId, IpAssignment> allocationMap;
samanwita palf28207b2015-09-04 10:41:56 -070061
62 private DistributedSet<Ip4Address> freeIPPool;
63
samanwita palf28207b2015-09-04 10:41:56 -070064 private static Ip4Address startIPRange;
65
66 private static Ip4Address endIPRange;
67
68 // Hardcoded values are default values.
69
samanwita palf28207b2015-09-04 10:41:56 -070070 private static int timeoutForPendingAssignments = 60;
71
72 @Activate
73 protected void activate() {
samanwita pal2a313402015-09-14 16:03:22 -070074 allocationMap = storageService.<HostId, IpAssignment>consistentMapBuilder()
samanwita palf28207b2015-09-04 10:41:56 -070075 .withName("onos-dhcp-assignedIP")
76 .withSerializer(Serializer.using(
77 new KryoNamespace.Builder()
78 .register(KryoNamespaces.API)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070079 .register(IpAssignment.class,
80 IpAssignment.AssignmentStatus.class,
samanwita palf28207b2015-09-04 10:41:56 -070081 Date.class,
82 long.class,
83 Ip4Address.class)
84 .build()))
85 .build();
86
87 freeIPPool = storageService.<Ip4Address>setBuilder()
88 .withName("onos-dhcp-freeIP")
89 .withSerializer(Serializer.using(KryoNamespaces.API))
90 .build();
91
samanwita palf28207b2015-09-04 10:41:56 -070092 log.info("Started");
93 }
94
95 @Deactivate
96 protected void deactivate() {
samanwita palf28207b2015-09-04 10:41:56 -070097 log.info("Stopped");
98 }
99
100 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700101 public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) {
samanwita palf28207b2015-09-04 10:41:56 -0700102
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700103 IpAssignment assignmentInfo;
samanwita pal2a313402015-09-14 16:03:22 -0700104 if (allocationMap.containsKey(hostId)) {
105 assignmentInfo = allocationMap.get(hostId).value();
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700106 IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
samanwita palf28207b2015-09-04 10:41:56 -0700107 Ip4Address ipAddr = assignmentInfo.ipAddress();
108
danielcd9deed2015-10-30 17:16:16 +0900109 if (assignmentInfo.fromOpenStack()) {
110 return assignmentInfo.ipAddress();
111 } else if (status == IpAssignment.AssignmentStatus.Option_Assigned ||
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700112 status == IpAssignment.AssignmentStatus.Option_Requested) {
samanwita palf28207b2015-09-04 10:41:56 -0700113 // Client has a currently Active Binding.
samanwita pal0bff4302015-09-15 13:37:00 -0700114 if (ipWithinRange(ipAddr)) {
samanwita palf28207b2015-09-04 10:41:56 -0700115 return ipAddr;
116 }
117
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700118 } else if (status == IpAssignment.AssignmentStatus.Option_Expired) {
samanwita palf28207b2015-09-04 10:41:56 -0700119 // Client has a Released or Expired Binding.
120 if (freeIPPool.contains(ipAddr)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700121 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700122 .ipAddress(ipAddr)
123 .timestamp(new Date())
124 .leasePeriod(timeoutForPendingAssignments)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700125 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
samanwita palf28207b2015-09-04 10:41:56 -0700126 .build();
127 if (freeIPPool.remove(ipAddr)) {
samanwita pal2a313402015-09-14 16:03:22 -0700128 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700129 return ipAddr;
130 }
131 }
132 }
samanwita palf28207b2015-09-04 10:41:56 -0700133 } else if (requestedIP.toInt() != 0) {
134 // Client has requested an IP.
135 if (freeIPPool.contains(requestedIP)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700136 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700137 .ipAddress(requestedIP)
138 .timestamp(new Date())
139 .leasePeriod(timeoutForPendingAssignments)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700140 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
samanwita palf28207b2015-09-04 10:41:56 -0700141 .build();
142 if (freeIPPool.remove(requestedIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700143 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700144 return requestedIP;
145 }
146 }
147 }
148
149 // Allocate a new IP from the server's pool of available IP.
150 Ip4Address nextIPAddr = fetchNextIP();
samanwita pal2a313402015-09-14 16:03:22 -0700151 if (nextIPAddr != null) {
152 assignmentInfo = IpAssignment.builder()
153 .ipAddress(nextIPAddr)
154 .timestamp(new Date())
155 .leasePeriod(timeoutForPendingAssignments)
156 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
157 .build();
samanwita palf28207b2015-09-04 10:41:56 -0700158
samanwita pal2a313402015-09-14 16:03:22 -0700159 allocationMap.put(hostId, assignmentInfo);
160 }
samanwita palf28207b2015-09-04 10:41:56 -0700161 return nextIPAddr;
162
163 }
164
165 @Override
danielcd9deed2015-10-30 17:16:16 +0900166 public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime, boolean fromOpenStack,
167 List<Ip4Address> addressList) {
samanwita palf28207b2015-09-04 10:41:56 -0700168
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700169 IpAssignment assignmentInfo;
danielcd9deed2015-10-30 17:16:16 +0900170
samanwita pal2a313402015-09-14 16:03:22 -0700171 if (allocationMap.containsKey(hostId)) {
172 assignmentInfo = allocationMap.get(hostId).value();
samanwita pal0bff4302015-09-15 13:37:00 -0700173 IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
samanwita palf28207b2015-09-04 10:41:56 -0700174
samanwita pal0bff4302015-09-15 13:37:00 -0700175 if (Objects.equals(assignmentInfo.ipAddress(), ipAddr) && ipWithinRange(ipAddr)) {
176
177 if (status == IpAssignment.AssignmentStatus.Option_Assigned ||
178 status == IpAssignment.AssignmentStatus.Option_Requested) {
179 // Client has a currently active binding with the server.
180 assignmentInfo = IpAssignment.builder()
181 .ipAddress(ipAddr)
182 .timestamp(new Date())
183 .leasePeriod(leaseTime)
184 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
185 .build();
186 allocationMap.put(hostId, assignmentInfo);
187 return true;
188 } else if (status == IpAssignment.AssignmentStatus.Option_Expired) {
189 // Client has an expired binding with the server.
190 if (freeIPPool.contains(ipAddr)) {
191 assignmentInfo = IpAssignment.builder()
192 .ipAddress(ipAddr)
193 .timestamp(new Date())
194 .leasePeriod(leaseTime)
195 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
196 .build();
197 if (freeIPPool.remove(ipAddr)) {
198 allocationMap.put(hostId, assignmentInfo);
199 return true;
200 }
201 }
202 }
samanwita palf28207b2015-09-04 10:41:56 -0700203 }
204 } else if (freeIPPool.contains(ipAddr)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700205 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700206 .ipAddress(ipAddr)
207 .timestamp(new Date())
208 .leasePeriod(leaseTime)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700209 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
samanwita palf28207b2015-09-04 10:41:56 -0700210 .build();
211 if (freeIPPool.remove(ipAddr)) {
samanwita pal2a313402015-09-14 16:03:22 -0700212 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700213 return true;
214 }
danielcd9deed2015-10-30 17:16:16 +0900215 } else if (fromOpenStack) {
216 assignmentInfo = IpAssignment.builder()
217 .ipAddress(ipAddr)
218 .timestamp(new Date())
219 .leasePeriod(leaseTime)
220 .fromOpenStack(true)
221 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested_From_OpenStack)
222 .subnetMask((Ip4Address) addressList.toArray()[0])
223 .dhcpServer((Ip4Address) addressList.toArray()[1])
224 .domainServer((Ip4Address) addressList.toArray()[2])
225 .routerAddress((Ip4Address) addressList.toArray()[3])
226 .build();
227 allocationMap.put(hostId, assignmentInfo);
228 return true;
samanwita palf28207b2015-09-04 10:41:56 -0700229 }
230 return false;
231 }
232
233 @Override
samanwita palc40e5ed2015-09-24 11:01:51 -0700234 public Ip4Address releaseIP(HostId hostId) {
samanwita pal2a313402015-09-14 16:03:22 -0700235 if (allocationMap.containsKey(hostId)) {
236 IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value())
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700237 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired)
samanwita palf28207b2015-09-04 10:41:56 -0700238 .build();
239 Ip4Address freeIP = newAssignment.ipAddress();
samanwita pal2a313402015-09-14 16:03:22 -0700240 allocationMap.put(hostId, newAssignment);
samanwita pal0bff4302015-09-15 13:37:00 -0700241 if (ipWithinRange(freeIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700242 freeIPPool.add(freeIP);
243 }
samanwita palc40e5ed2015-09-24 11:01:51 -0700244 return freeIP;
samanwita palf28207b2015-09-04 10:41:56 -0700245 }
samanwita palc40e5ed2015-09-24 11:01:51 -0700246 return null;
samanwita palf28207b2015-09-04 10:41:56 -0700247 }
248
249 @Override
250 public void setDefaultTimeoutForPurge(int timeInSeconds) {
251 timeoutForPendingAssignments = timeInSeconds;
252 }
253
254 @Override
samanwita pal0bff4302015-09-15 13:37:00 -0700255 public Map<HostId, IpAssignment> listAssignedMapping() {
samanwita palf28207b2015-09-04 10:41:56 -0700256
samanwita pal0bff4302015-09-15 13:37:00 -0700257 Map<HostId, IpAssignment> validMapping = new HashMap<>();
258 IpAssignment assignment;
samanwita pal2a313402015-09-14 16:03:22 -0700259 for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
samanwita pal0bff4302015-09-15 13:37:00 -0700260 assignment = entry.getValue().value();
danielcd9deed2015-10-30 17:16:16 +0900261 if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned
262 || assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Requested_From_OpenStack) {
samanwita pal0bff4302015-09-15 13:37:00 -0700263 validMapping.put(entry.getKey(), assignment);
samanwita palf28207b2015-09-04 10:41:56 -0700264 }
265 }
samanwita pal0bff4302015-09-15 13:37:00 -0700266 return validMapping;
267 }
Thomas Vachuska54dc3522015-09-09 00:11:45 -0700268
samanwita pal0bff4302015-09-15 13:37:00 -0700269 @Override
270 public Map<HostId, IpAssignment> listAllMapping() {
271 Map<HostId, IpAssignment> validMapping = new HashMap<>();
272 for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
273 validMapping.put(entry.getKey(), entry.getValue().value());
274 }
275 return validMapping;
samanwita palf28207b2015-09-04 10:41:56 -0700276 }
277
278 @Override
danielcd9deed2015-10-30 17:16:16 +0900279 public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr, boolean fromOpenStack,
280 List<Ip4Address> addressList) {
samanwita pal2a313402015-09-14 16:03:22 -0700281 HostId host = HostId.hostId(macID);
danielcd9deed2015-10-30 17:16:16 +0900282 return assignIP(host, ipAddr, -1, fromOpenStack, addressList);
samanwita palf28207b2015-09-04 10:41:56 -0700283 }
284
285 @Override
286 public boolean removeStaticIP(MacAddress macID) {
samanwita pal2a313402015-09-14 16:03:22 -0700287 HostId host = HostId.hostId(macID);
288 if (allocationMap.containsKey(host)) {
289 IpAssignment assignment = allocationMap.get(host).value();
samanwita palf28207b2015-09-04 10:41:56 -0700290 Ip4Address freeIP = assignment.ipAddress();
291 if (assignment.leasePeriod() < 0) {
samanwita pal2a313402015-09-14 16:03:22 -0700292 allocationMap.remove(host);
samanwita pal0bff4302015-09-15 13:37:00 -0700293 if (ipWithinRange(freeIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700294 freeIPPool.add(freeIP);
295 }
samanwita palf28207b2015-09-04 10:41:56 -0700296 return true;
297 }
298 }
299 return false;
300 }
301
302 @Override
303 public Iterable<Ip4Address> getAvailableIPs() {
Sho SHIMIZUfd0933b2015-09-11 15:17:48 -0700304 return ImmutableSet.copyOf(freeIPPool);
samanwita palf28207b2015-09-04 10:41:56 -0700305 }
306
307 @Override
308 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
309 // Clear all entries from previous range.
samanwita pal0bff4302015-09-15 13:37:00 -0700310 allocationMap.clear();
311 freeIPPool.clear();
samanwita palf28207b2015-09-04 10:41:56 -0700312 startIPRange = startIP;
313 endIPRange = endIP;
samanwita palf28207b2015-09-04 10:41:56 -0700314
315 int lastIP = endIP.toInt();
316 Ip4Address nextIP;
317 for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
318 nextIP = Ip4Address.valueOf(loopCounter);
319 freeIPPool.add(nextIP);
320 }
321 }
322
danielcd9deed2015-10-30 17:16:16 +0900323 @Override
324 public IpAssignment getIpAssignmentFromAllocationMap(HostId hostId) {
325 return allocationMap.get(hostId).value();
326 }
327
samanwita palf28207b2015-09-04 10:41:56 -0700328 /**
329 * Fetches the next available IP from the free pool pf IPs.
330 *
331 * @return the next available IP address
332 */
333 private Ip4Address fetchNextIP() {
334 for (Ip4Address freeIP : freeIPPool) {
335 if (freeIPPool.remove(freeIP)) {
336 return freeIP;
337 }
338 }
339 return null;
340 }
samanwita pal0bff4302015-09-15 13:37:00 -0700341
342 /**
343 * Returns true if the given ip is within the range of available IPs.
344 *
345 * @param ip given ip address
346 * @return true if within range, false otherwise
347 */
348 private boolean ipWithinRange(Ip4Address ip) {
349 if ((ip.toInt() >= startIPRange.toInt()) && (ip.toInt() <= endIPRange.toInt())) {
350 return true;
351 }
352 return false;
353 }
samanwita palf28207b2015-09-04 10:41:56 -0700354}
danielcd9deed2015-10-30 17:16:16 +0900355