blob: d072b58082feab378b96fccdd6949f34059dfffd [file] [log] [blame]
samanwita pal18696f62015-07-17 13:15:43 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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 */
samanwita palf66ed8a2015-07-21 15:45:33 -070016package org.onosproject.dhcpserver.impl;
samanwita pal18696f62015-07-17 13:15:43 -070017
samanwita palf66ed8a2015-07-21 15:45:33 -070018import com.google.common.collect.ImmutableSet;
samanwita pal18696f62015-07-17 13:15:43 -070019import 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;
25import org.jboss.netty.util.Timeout;
26import org.jboss.netty.util.TimerTask;
27import org.onlab.packet.Ip4Address;
28import org.onlab.packet.MacAddress;
29import org.onlab.util.KryoNamespace;
30import org.onlab.util.Timer;
samanwita palf66ed8a2015-07-21 15:45:33 -070031import org.onosproject.dhcpserver.DHCPStore;
32import org.onosproject.dhcpserver.IPAssignment;
samanwita pal18696f62015-07-17 13:15:43 -070033import org.onosproject.store.serializers.KryoNamespaces;
34import org.onosproject.store.service.ConsistentMap;
35import org.onosproject.store.service.DistributedSet;
36import org.onosproject.store.service.Serializer;
37import org.onosproject.store.service.StorageService;
38import org.onosproject.store.service.Versioned;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.util.Date;
samanwita palf66ed8a2015-07-21 15:45:33 -070043import java.util.HashMap;
samanwita pal18696f62015-07-17 13:15:43 -070044import java.util.Map;
45import java.util.concurrent.TimeUnit;
46
47/**
48 * Manages the pool of available IP Addresses in the network and
49 * Remembers the mapping between MAC ID and IP Addresses assigned.
50 */
51
52@Component(immediate = true)
53@Service
54public class DistributedDHCPStore implements DHCPStore {
55
56 private final Logger log = LoggerFactory.getLogger(getClass());
57
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected StorageService storageService;
60
61 private ConsistentMap<MacAddress, IPAssignment> allocationMap;
62
63 private DistributedSet<Ip4Address> freeIPPool;
64
65 private Timeout timeout;
66
samanwita pal775f6192015-07-28 10:10:13 -070067 private static Ip4Address startIPRange;
samanwita pal18696f62015-07-17 13:15:43 -070068
samanwita pal775f6192015-07-28 10:10:13 -070069 private static Ip4Address endIPRange;
70
71 // Hardcoded values are default values.
72
73 private static int timerDelay = 2;
samanwita pal18696f62015-07-17 13:15:43 -070074
samanwita palf66ed8a2015-07-21 15:45:33 -070075 private static int timeoutForPendingAssignments = 60;
samanwita pal18696f62015-07-17 13:15:43 -070076
samanwita pal18696f62015-07-17 13:15:43 -070077 @Activate
78 protected void activate() {
79 allocationMap = storageService.<MacAddress, IPAssignment>consistentMapBuilder()
80 .withName("onos-dhcp-assignedIP")
81 .withSerializer(Serializer.using(
82 new KryoNamespace.Builder()
83 .register(KryoNamespaces.API)
84 .register(IPAssignment.class,
85 IPAssignment.AssignmentStatus.class,
86 Date.class,
87 long.class,
88 Ip4Address.class)
89 .build()))
90 .build();
91
92 freeIPPool = storageService.<Ip4Address>setBuilder()
93 .withName("onos-dhcp-freeIP")
94 .withSerializer(Serializer.using(KryoNamespaces.API))
95 .build();
96
samanwita pal775f6192015-07-28 10:10:13 -070097 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
samanwita pal18696f62015-07-17 13:15:43 -070098
99 log.info("Started");
100 }
101
102 @Deactivate
103 protected void deactivate() {
104 timeout.cancel();
105 log.info("Stopped");
106 }
107
108 @Override
samanwita palf09c09e2015-07-22 16:06:42 -0700109 public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
samanwita pal18696f62015-07-17 13:15:43 -0700110
111 IPAssignment assignmentInfo;
112 if (allocationMap.containsKey(macID)) {
113 assignmentInfo = allocationMap.get(macID).value();
samanwita palf09c09e2015-07-22 16:06:42 -0700114 IPAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
115 Ip4Address ipAddr = assignmentInfo.ipAddress();
116
117 if (status == IPAssignment.AssignmentStatus.Option_Assigned ||
118 status == IPAssignment.AssignmentStatus.Option_Requested) {
119 // Client has a currently Active Binding.
samanwita pal775f6192015-07-28 10:10:13 -0700120 if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
121 return ipAddr;
122 }
samanwita palf09c09e2015-07-22 16:06:42 -0700123
124 } else if (status == IPAssignment.AssignmentStatus.Option_Expired) {
125 // Client has a Released or Expired Binding.
126 if (freeIPPool.contains(ipAddr)) {
127 assignmentInfo = IPAssignment.builder()
128 .ipAddress(ipAddr)
129 .timestamp(new Date())
130 .leasePeriod(timeoutForPendingAssignments)
131 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
132 .build();
133 if (freeIPPool.remove(ipAddr)) {
134 allocationMap.put(macID, assignmentInfo);
135 return ipAddr;
136 }
137 }
138 }
samanwita palf66ed8a2015-07-21 15:45:33 -0700139 return assignmentInfo.ipAddress();
samanwita pal18696f62015-07-17 13:15:43 -0700140
samanwita palf09c09e2015-07-22 16:06:42 -0700141 } else if (requestedIP.toInt() != 0) {
142 // Client has requested an IP.
143 if (freeIPPool.contains(requestedIP)) {
144 assignmentInfo = IPAssignment.builder()
145 .ipAddress(requestedIP)
146 .timestamp(new Date())
147 .leasePeriod(timeoutForPendingAssignments)
148 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
149 .build();
150 if (freeIPPool.remove(requestedIP)) {
151 allocationMap.put(macID, assignmentInfo);
152 return requestedIP;
153 }
154 }
samanwita pal18696f62015-07-17 13:15:43 -0700155 }
samanwita palf09c09e2015-07-22 16:06:42 -0700156
157 // Allocate a new IP from the server's pool of available IP.
158 Ip4Address nextIPAddr = fetchNextIP();
159 assignmentInfo = IPAssignment.builder()
160 .ipAddress(nextIPAddr)
161 .timestamp(new Date())
162 .leasePeriod(timeoutForPendingAssignments)
163 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
164 .build();
165
166 allocationMap.put(macID, assignmentInfo);
167 return nextIPAddr;
168
samanwita pal18696f62015-07-17 13:15:43 -0700169 }
170
171 @Override
samanwita palf66ed8a2015-07-21 15:45:33 -0700172 public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
samanwita pal18696f62015-07-17 13:15:43 -0700173
174 IPAssignment assignmentInfo;
175 if (allocationMap.containsKey(macID)) {
176 assignmentInfo = allocationMap.get(macID).value();
samanwita pal775f6192015-07-28 10:10:13 -0700177 if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
178 (ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
samanwita palf66ed8a2015-07-21 15:45:33 -0700179
180 assignmentInfo = IPAssignment.builder()
samanwita pal775f6192015-07-28 10:10:13 -0700181 .ipAddress(ipAddr)
182 .timestamp(new Date())
183 .leasePeriod(leaseTime)
184 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
185 .build();
samanwita pal18696f62015-07-17 13:15:43 -0700186 allocationMap.put(macID, assignmentInfo);
187 return true;
188 }
189 } else if (freeIPPool.contains(ipAddr)) {
samanwita palf66ed8a2015-07-21 15:45:33 -0700190 assignmentInfo = IPAssignment.builder()
191 .ipAddress(ipAddr)
192 .timestamp(new Date())
193 .leasePeriod(leaseTime)
194 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
195 .build();
samanwita pal18696f62015-07-17 13:15:43 -0700196 if (freeIPPool.remove(ipAddr)) {
197 allocationMap.put(macID, assignmentInfo);
198 return true;
199 }
200 }
201 return false;
202 }
203
204 @Override
205 public void releaseIP(MacAddress macID) {
206 if (allocationMap.containsKey(macID)) {
samanwita palf09c09e2015-07-22 16:06:42 -0700207 IPAssignment newAssignment = IPAssignment.builder(allocationMap.get(macID).value())
208 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
209 .build();
210 Ip4Address freeIP = newAssignment.ipAddress();
211 allocationMap.put(macID, newAssignment);
samanwita pal18696f62015-07-17 13:15:43 -0700212 freeIPPool.add(freeIP);
213 }
214 }
215
216 @Override
samanwita palf66ed8a2015-07-21 15:45:33 -0700217 public void setDefaultTimeoutForPurge(int timeInSeconds) {
samanwita pal18696f62015-07-17 13:15:43 -0700218 timeoutForPendingAssignments = timeInSeconds;
219 }
220
samanwita palf66ed8a2015-07-21 15:45:33 -0700221 @Override
samanwita pal775f6192015-07-28 10:10:13 -0700222 public void setTimerDelay(int timeInSeconds) {
223 timerDelay = timeInSeconds;
224 }
225
226 @Override
samanwita palf66ed8a2015-07-21 15:45:33 -0700227 public Map<MacAddress, Ip4Address> listMapping() {
228
229 Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
230 for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
231 IPAssignment assignment = entry.getValue().value();
232 if (assignment.assignmentStatus() == IPAssignment.AssignmentStatus.Option_Assigned) {
233 allMapping.put(entry.getKey(), assignment.ipAddress());
234 }
235 }
236
237 return allMapping;
238 }
239
240 @Override
241 public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
242 return assignIP(macID, ipAddr, -1);
243 }
244
245 @Override
246 public boolean removeStaticIP(MacAddress macID) {
247 if (allocationMap.containsKey(macID)) {
248 IPAssignment assignment = allocationMap.get(macID).value();
249 Ip4Address freeIP = assignment.ipAddress();
250 if (assignment.leasePeriod() < 0) {
251 allocationMap.remove(macID);
252 freeIPPool.add(freeIP);
253 return true;
254 }
255 }
256 return false;
257 }
258
259 @Override
260 public Iterable<Ip4Address> getAvailableIPs() {
261 return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
262 }
263
samanwita pal775f6192015-07-28 10:10:13 -0700264 @Override
samanwita pal18696f62015-07-17 13:15:43 -0700265 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
samanwita pal775f6192015-07-28 10:10:13 -0700266 // Clear all entries from previous range.
267 startIPRange = startIP;
268 endIPRange = endIP;
269 freeIPPool.clear();
270
samanwita pal18696f62015-07-17 13:15:43 -0700271 int lastIP = endIP.toInt();
272 Ip4Address nextIP;
273 for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
274 nextIP = Ip4Address.valueOf(loopCounter);
275 freeIPPool.add(nextIP);
276 }
277 }
278
279 /**
280 * Fetches the next available IP from the free pool pf IPs.
281 *
282 * @return the next available IP address
283 */
284 private Ip4Address fetchNextIP() {
285 for (Ip4Address freeIP : freeIPPool) {
286 if (freeIPPool.remove(freeIP)) {
287 return freeIP;
288 }
289 }
290 return null;
291 }
292
293 /**
294 * Purges the IP allocation map to remove expired entries and returns the freed IPs to the free pool.
295 */
296 private class PurgeListTask implements TimerTask {
297
298 @Override
299 public void run(Timeout to) {
samanwita palf09c09e2015-07-22 16:06:42 -0700300 IPAssignment ipAssignment, newAssignment;
samanwita pal18696f62015-07-17 13:15:43 -0700301 Date dateNow = new Date();
302 for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
303 ipAssignment = entry.getValue().value();
samanwita palf66ed8a2015-07-21 15:45:33 -0700304 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
samanwita palf09c09e2015-07-22 16:06:42 -0700305 if ((ipAssignment.assignmentStatus() != IPAssignment.AssignmentStatus.Option_Expired) &&
306 (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
samanwita palf66ed8a2015-07-21 15:45:33 -0700307 Ip4Address freeIP = ipAssignment.ipAddress();
samanwita palf09c09e2015-07-22 16:06:42 -0700308
309 newAssignment = IPAssignment.builder(ipAssignment)
samanwita pal775f6192015-07-28 10:10:13 -0700310 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
311 .build();
samanwita palf09c09e2015-07-22 16:06:42 -0700312 allocationMap.put(entry.getKey(), newAssignment);
samanwita pal775f6192015-07-28 10:10:13 -0700313
314 if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
315 freeIPPool.add(freeIP);
316 }
samanwita pal18696f62015-07-17 13:15:43 -0700317 }
318 }
samanwita pal775f6192015-07-28 10:10:13 -0700319 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
samanwita pal18696f62015-07-17 13:15:43 -0700320 }
321
322 }
323
324}