blob: 1ad4bc5d2be0da81d8c951fee8447aefa032e0bd [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
67 // TODO Make the hardcoded values configurable.
68
69 private static final int INITIAL_DELAY = 2;
70
samanwita palf66ed8a2015-07-21 15:45:33 -070071 private static int timeoutForPendingAssignments = 60;
samanwita pal18696f62015-07-17 13:15:43 -070072
samanwita palf66ed8a2015-07-21 15:45:33 -070073 private static final Ip4Address START_IP = Ip4Address.valueOf("10.1.0.140");
samanwita pal18696f62015-07-17 13:15:43 -070074
samanwita palf66ed8a2015-07-21 15:45:33 -070075 private static final Ip4Address END_IP = Ip4Address.valueOf("10.1.0.160");
samanwita pal18696f62015-07-17 13:15:43 -070076
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 populateIPPoolfromRange(START_IP, END_IP);
98 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), INITIAL_DELAY, TimeUnit.MINUTES);
99
100 log.info("Started");
101 }
102
103 @Deactivate
104 protected void deactivate() {
105 timeout.cancel();
106 log.info("Stopped");
107 }
108
109 @Override
110 public Ip4Address suggestIP(MacAddress macID) {
111
112 IPAssignment assignmentInfo;
113 if (allocationMap.containsKey(macID)) {
114 assignmentInfo = allocationMap.get(macID).value();
samanwita palf66ed8a2015-07-21 15:45:33 -0700115 return assignmentInfo.ipAddress();
samanwita pal18696f62015-07-17 13:15:43 -0700116 } else {
117 Ip4Address nextIPAddr = fetchNextIP();
118
samanwita palf66ed8a2015-07-21 15:45:33 -0700119
120 assignmentInfo = IPAssignment.builder()
121 .ipAddress(nextIPAddr)
122 .timestamp(new Date())
123 .leasePeriod(timeoutForPendingAssignments)
124 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
125 .build();
samanwita pal18696f62015-07-17 13:15:43 -0700126
127 allocationMap.put(macID, assignmentInfo);
128 return nextIPAddr;
129 }
130 }
131
132 @Override
samanwita palf66ed8a2015-07-21 15:45:33 -0700133 public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
samanwita pal18696f62015-07-17 13:15:43 -0700134
135 IPAssignment assignmentInfo;
136 if (allocationMap.containsKey(macID)) {
137 assignmentInfo = allocationMap.get(macID).value();
samanwita palf66ed8a2015-07-21 15:45:33 -0700138 if (assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) {
139
140 assignmentInfo = IPAssignment.builder()
141 .ipAddress(ipAddr)
142 .timestamp(new Date())
143 .leasePeriod(leaseTime)
144 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
145 .build();
samanwita pal18696f62015-07-17 13:15:43 -0700146 allocationMap.put(macID, assignmentInfo);
147 return true;
148 }
149 } else if (freeIPPool.contains(ipAddr)) {
samanwita palf66ed8a2015-07-21 15:45:33 -0700150 assignmentInfo = IPAssignment.builder()
151 .ipAddress(ipAddr)
152 .timestamp(new Date())
153 .leasePeriod(leaseTime)
154 .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
155 .build();
samanwita pal18696f62015-07-17 13:15:43 -0700156 if (freeIPPool.remove(ipAddr)) {
157 allocationMap.put(macID, assignmentInfo);
158 return true;
159 }
160 }
161 return false;
162 }
163
164 @Override
165 public void releaseIP(MacAddress macID) {
166 if (allocationMap.containsKey(macID)) {
samanwita palf66ed8a2015-07-21 15:45:33 -0700167 Ip4Address freeIP = allocationMap.get(macID).value().ipAddress();
samanwita pal18696f62015-07-17 13:15:43 -0700168 allocationMap.remove(macID);
169 freeIPPool.add(freeIP);
170 }
171 }
172
173 @Override
samanwita palf66ed8a2015-07-21 15:45:33 -0700174 public void setDefaultTimeoutForPurge(int timeInSeconds) {
samanwita pal18696f62015-07-17 13:15:43 -0700175 timeoutForPendingAssignments = timeInSeconds;
176 }
177
samanwita palf66ed8a2015-07-21 15:45:33 -0700178 @Override
179 public Map<MacAddress, Ip4Address> listMapping() {
180
181 Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
182 for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
183 IPAssignment assignment = entry.getValue().value();
184 if (assignment.assignmentStatus() == IPAssignment.AssignmentStatus.Option_Assigned) {
185 allMapping.put(entry.getKey(), assignment.ipAddress());
186 }
187 }
188
189 return allMapping;
190 }
191
192 @Override
193 public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
194 return assignIP(macID, ipAddr, -1);
195 }
196
197 @Override
198 public boolean removeStaticIP(MacAddress macID) {
199 if (allocationMap.containsKey(macID)) {
200 IPAssignment assignment = allocationMap.get(macID).value();
201 Ip4Address freeIP = assignment.ipAddress();
202 if (assignment.leasePeriod() < 0) {
203 allocationMap.remove(macID);
204 freeIPPool.add(freeIP);
205 return true;
206 }
207 }
208 return false;
209 }
210
211 @Override
212 public Iterable<Ip4Address> getAvailableIPs() {
213 return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
214 }
215
samanwita pal18696f62015-07-17 13:15:43 -0700216 /**
217 * Appends all the IPs in a given range to the free pool of IPs.
218 *
219 * @param startIP Start IP for the range
220 * @param endIP End IP for the range
221 */
222 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
223 int lastIP = endIP.toInt();
224 Ip4Address nextIP;
225 for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
226 nextIP = Ip4Address.valueOf(loopCounter);
227 freeIPPool.add(nextIP);
228 }
229 }
230
231 /**
232 * Fetches the next available IP from the free pool pf IPs.
233 *
234 * @return the next available IP address
235 */
236 private Ip4Address fetchNextIP() {
237 for (Ip4Address freeIP : freeIPPool) {
238 if (freeIPPool.remove(freeIP)) {
239 return freeIP;
240 }
241 }
242 return null;
243 }
244
245 /**
246 * Purges the IP allocation map to remove expired entries and returns the freed IPs to the free pool.
247 */
248 private class PurgeListTask implements TimerTask {
249
250 @Override
251 public void run(Timeout to) {
252 IPAssignment ipAssignment;
253 Date dateNow = new Date();
254 for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
255 ipAssignment = entry.getValue().value();
samanwita palf66ed8a2015-07-21 15:45:33 -0700256 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
257 if ((ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
258 Ip4Address freeIP = ipAssignment.ipAddress();
samanwita pal18696f62015-07-17 13:15:43 -0700259 allocationMap.remove(entry.getKey());
260 freeIPPool.add(freeIP);
261 }
262 }
263 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), INITIAL_DELAY, TimeUnit.MINUTES);
264 }
265
266 }
267
268}