blob: ad4522cb7aa38c9f988cdda66f4688789b898129 [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
daniel877bb2f2015-11-12 21:33:05 +0900109 if (assignmentInfo.rangeNotEnforced()) {
danielcd9deed2015-10-30 17:16:16 +0900110 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
daniel877bb2f2015-11-12 21:33:05 +0900166 public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime, boolean rangeNotEnforced,
danielcd9deed2015-10-30 17:16:16 +0900167 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
daniel877bb2f2015-11-12 21:33:05 +0900171 log.debug("Assign IP Called w/ Ip4Address: {}, HostId: {}", ipAddr.toString(), hostId.mac().toString());
172
samanwita pal2a313402015-09-14 16:03:22 -0700173 if (allocationMap.containsKey(hostId)) {
daniel877bb2f2015-11-12 21:33:05 +0900174
samanwita pal2a313402015-09-14 16:03:22 -0700175 assignmentInfo = allocationMap.get(hostId).value();
samanwita pal0bff4302015-09-15 13:37:00 -0700176 IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
samanwita palf28207b2015-09-04 10:41:56 -0700177
samanwita pal0bff4302015-09-15 13:37:00 -0700178 if (Objects.equals(assignmentInfo.ipAddress(), ipAddr) && ipWithinRange(ipAddr)) {
179
180 if (status == IpAssignment.AssignmentStatus.Option_Assigned ||
181 status == IpAssignment.AssignmentStatus.Option_Requested) {
182 // Client has a currently active binding with the server.
183 assignmentInfo = IpAssignment.builder()
184 .ipAddress(ipAddr)
185 .timestamp(new Date())
186 .leasePeriod(leaseTime)
187 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
188 .build();
189 allocationMap.put(hostId, assignmentInfo);
190 return true;
191 } else if (status == IpAssignment.AssignmentStatus.Option_Expired) {
192 // Client has an expired binding with the server.
193 if (freeIPPool.contains(ipAddr)) {
194 assignmentInfo = IpAssignment.builder()
195 .ipAddress(ipAddr)
196 .timestamp(new Date())
197 .leasePeriod(leaseTime)
198 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
199 .build();
200 if (freeIPPool.remove(ipAddr)) {
201 allocationMap.put(hostId, assignmentInfo);
202 return true;
203 }
204 }
205 }
samanwita palf28207b2015-09-04 10:41:56 -0700206 }
207 } else if (freeIPPool.contains(ipAddr)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700208 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700209 .ipAddress(ipAddr)
210 .timestamp(new Date())
211 .leasePeriod(leaseTime)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700212 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
samanwita palf28207b2015-09-04 10:41:56 -0700213 .build();
214 if (freeIPPool.remove(ipAddr)) {
samanwita pal2a313402015-09-14 16:03:22 -0700215 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700216 return true;
217 }
daniel877bb2f2015-11-12 21:33:05 +0900218 } else if (rangeNotEnforced) {
danielcd9deed2015-10-30 17:16:16 +0900219 assignmentInfo = IpAssignment.builder()
220 .ipAddress(ipAddr)
221 .timestamp(new Date())
222 .leasePeriod(leaseTime)
daniel877bb2f2015-11-12 21:33:05 +0900223 .rangeNotEnforced(true)
224 .assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced)
danielcd9deed2015-10-30 17:16:16 +0900225 .subnetMask((Ip4Address) addressList.toArray()[0])
226 .dhcpServer((Ip4Address) addressList.toArray()[1])
daniel877bb2f2015-11-12 21:33:05 +0900227 .routerAddress((Ip4Address) addressList.toArray()[2])
228 .domainServer((Ip4Address) addressList.toArray()[3])
danielcd9deed2015-10-30 17:16:16 +0900229 .build();
230 allocationMap.put(hostId, assignmentInfo);
231 return true;
samanwita palf28207b2015-09-04 10:41:56 -0700232 }
233 return false;
234 }
235
236 @Override
samanwita palc40e5ed2015-09-24 11:01:51 -0700237 public Ip4Address releaseIP(HostId hostId) {
samanwita pal2a313402015-09-14 16:03:22 -0700238 if (allocationMap.containsKey(hostId)) {
239 IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value())
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700240 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired)
samanwita palf28207b2015-09-04 10:41:56 -0700241 .build();
242 Ip4Address freeIP = newAssignment.ipAddress();
samanwita pal2a313402015-09-14 16:03:22 -0700243 allocationMap.put(hostId, newAssignment);
samanwita pal0bff4302015-09-15 13:37:00 -0700244 if (ipWithinRange(freeIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700245 freeIPPool.add(freeIP);
246 }
samanwita palc40e5ed2015-09-24 11:01:51 -0700247 return freeIP;
samanwita palf28207b2015-09-04 10:41:56 -0700248 }
samanwita palc40e5ed2015-09-24 11:01:51 -0700249 return null;
samanwita palf28207b2015-09-04 10:41:56 -0700250 }
251
252 @Override
253 public void setDefaultTimeoutForPurge(int timeInSeconds) {
254 timeoutForPendingAssignments = timeInSeconds;
255 }
256
257 @Override
samanwita pal0bff4302015-09-15 13:37:00 -0700258 public Map<HostId, IpAssignment> listAssignedMapping() {
samanwita palf28207b2015-09-04 10:41:56 -0700259
samanwita pal0bff4302015-09-15 13:37:00 -0700260 Map<HostId, IpAssignment> validMapping = new HashMap<>();
261 IpAssignment assignment;
samanwita pal2a313402015-09-14 16:03:22 -0700262 for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
samanwita pal0bff4302015-09-15 13:37:00 -0700263 assignment = entry.getValue().value();
danielcd9deed2015-10-30 17:16:16 +0900264 if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned
daniel877bb2f2015-11-12 21:33:05 +0900265 || assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_RangeNotEnforced) {
samanwita pal0bff4302015-09-15 13:37:00 -0700266 validMapping.put(entry.getKey(), assignment);
samanwita palf28207b2015-09-04 10:41:56 -0700267 }
268 }
samanwita pal0bff4302015-09-15 13:37:00 -0700269 return validMapping;
270 }
Thomas Vachuska54dc3522015-09-09 00:11:45 -0700271
samanwita pal0bff4302015-09-15 13:37:00 -0700272 @Override
273 public Map<HostId, IpAssignment> listAllMapping() {
274 Map<HostId, IpAssignment> validMapping = new HashMap<>();
275 for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
276 validMapping.put(entry.getKey(), entry.getValue().value());
277 }
278 return validMapping;
samanwita palf28207b2015-09-04 10:41:56 -0700279 }
280
281 @Override
daniel877bb2f2015-11-12 21:33:05 +0900282 public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr, boolean rangeNotEnforced,
danielcd9deed2015-10-30 17:16:16 +0900283 List<Ip4Address> addressList) {
samanwita pal2a313402015-09-14 16:03:22 -0700284 HostId host = HostId.hostId(macID);
daniel877bb2f2015-11-12 21:33:05 +0900285 return assignIP(host, ipAddr, -1, rangeNotEnforced, addressList);
samanwita palf28207b2015-09-04 10:41:56 -0700286 }
287
288 @Override
289 public boolean removeStaticIP(MacAddress macID) {
samanwita pal2a313402015-09-14 16:03:22 -0700290 HostId host = HostId.hostId(macID);
291 if (allocationMap.containsKey(host)) {
292 IpAssignment assignment = allocationMap.get(host).value();
daniel877bb2f2015-11-12 21:33:05 +0900293
294 if (assignment.rangeNotEnforced()) {
295 allocationMap.remove(host);
296 return true;
297 }
298
samanwita palf28207b2015-09-04 10:41:56 -0700299 Ip4Address freeIP = assignment.ipAddress();
300 if (assignment.leasePeriod() < 0) {
samanwita pal2a313402015-09-14 16:03:22 -0700301 allocationMap.remove(host);
samanwita pal0bff4302015-09-15 13:37:00 -0700302 if (ipWithinRange(freeIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700303 freeIPPool.add(freeIP);
304 }
samanwita palf28207b2015-09-04 10:41:56 -0700305 return true;
306 }
307 }
308 return false;
309 }
310
311 @Override
312 public Iterable<Ip4Address> getAvailableIPs() {
Sho SHIMIZUfd0933b2015-09-11 15:17:48 -0700313 return ImmutableSet.copyOf(freeIPPool);
samanwita palf28207b2015-09-04 10:41:56 -0700314 }
315
316 @Override
317 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
318 // Clear all entries from previous range.
samanwita pal0bff4302015-09-15 13:37:00 -0700319 allocationMap.clear();
320 freeIPPool.clear();
samanwita palf28207b2015-09-04 10:41:56 -0700321 startIPRange = startIP;
322 endIPRange = endIP;
samanwita palf28207b2015-09-04 10:41:56 -0700323
324 int lastIP = endIP.toInt();
325 Ip4Address nextIP;
326 for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
327 nextIP = Ip4Address.valueOf(loopCounter);
328 freeIPPool.add(nextIP);
329 }
330 }
331
danielcd9deed2015-10-30 17:16:16 +0900332 @Override
333 public IpAssignment getIpAssignmentFromAllocationMap(HostId hostId) {
334 return allocationMap.get(hostId).value();
335 }
336
samanwita palf28207b2015-09-04 10:41:56 -0700337 /**
338 * Fetches the next available IP from the free pool pf IPs.
339 *
340 * @return the next available IP address
341 */
342 private Ip4Address fetchNextIP() {
343 for (Ip4Address freeIP : freeIPPool) {
344 if (freeIPPool.remove(freeIP)) {
345 return freeIP;
346 }
347 }
348 return null;
349 }
samanwita pal0bff4302015-09-15 13:37:00 -0700350
351 /**
352 * Returns true if the given ip is within the range of available IPs.
353 *
354 * @param ip given ip address
355 * @return true if within range, false otherwise
356 */
357 private boolean ipWithinRange(Ip4Address ip) {
358 if ((ip.toInt() >= startIPRange.toInt()) && (ip.toInt() <= endIPRange.toInt())) {
359 return true;
360 }
361 return false;
362 }
samanwita palf28207b2015-09-04 10:41:56 -0700363}
danielcd9deed2015-10-30 17:16:16 +0900364