blob: a582892b1b5cdaac311bfd486c5a82e25f47d634 [file] [log] [blame]
samanwita palf28207b2015-09-04 10:41:56 -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 */
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;
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;
31import org.onosproject.dhcp.DHCPStore;
32import org.onosproject.dhcp.IPAssignment;
33import 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;
43import java.util.HashMap;
44import 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
67 private static Ip4Address startIPRange;
68
69 private static Ip4Address endIPRange;
70
71 // Hardcoded values are default values.
72
73 private static int timerDelay = 2;
74
75 private static int timeoutForPendingAssignments = 60;
76
77 @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
97 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
98
99 log.info("Started");
100 }
101
102 @Deactivate
103 protected void deactivate() {
104 timeout.cancel();
105 log.info("Stopped");
106 }
107
108 @Override
109 public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
110
111 IPAssignment assignmentInfo;
112 if (allocationMap.containsKey(macID)) {
113 assignmentInfo = allocationMap.get(macID).value();
114 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.
120 if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
121 return ipAddr;
122 }
123
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 }
139 return assignmentInfo.ipAddress();
140
141 } 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 }
155 }
156
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
169 }
170
171 @Override
172 public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
173
174 IPAssignment assignmentInfo;
175 if (allocationMap.containsKey(macID)) {
176 assignmentInfo = allocationMap.get(macID).value();
177 if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
178 (ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
179
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(macID, assignmentInfo);
187 return true;
188 }
189 } else if (freeIPPool.contains(ipAddr)) {
190 assignmentInfo = IPAssignment.builder()
191 .ipAddress(ipAddr)
192 .timestamp(new Date())
193 .leasePeriod(leaseTime)
194 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
195 .build();
196 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)) {
207 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);
212 freeIPPool.add(freeIP);
213 }
214 }
215
216 @Override
217 public void setDefaultTimeoutForPurge(int timeInSeconds) {
218 timeoutForPendingAssignments = timeInSeconds;
219 }
220
221 @Override
222 public void setTimerDelay(int timeInSeconds) {
223 timerDelay = timeInSeconds;
224 }
225
226 @Override
227 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
264 @Override
265 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
266 // Clear all entries from previous range.
267 startIPRange = startIP;
268 endIPRange = endIP;
269 freeIPPool.clear();
270
271 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) {
300 IPAssignment ipAssignment, newAssignment;
301 Date dateNow = new Date();
302 for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
303 ipAssignment = entry.getValue().value();
304 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
305 if ((ipAssignment.assignmentStatus() != IPAssignment.AssignmentStatus.Option_Expired) &&
306 (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
307 Ip4Address freeIP = ipAssignment.ipAddress();
308
309 newAssignment = IPAssignment.builder(ipAssignment)
310 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
311 .build();
312 allocationMap.put(entry.getKey(), newAssignment);
313
314 if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
315 freeIPPool.add(freeIP);
316 }
317 }
318 }
319 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
320 }
321
322 }
323
324}