blob: 96013b6b73772fa60f2266ac37fccb5c6b87cf9f [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;
41import java.util.HashMap;
42import java.util.Map;
samanwita palf28207b2015-09-04 10:41:56 -070043
44/**
45 * Manages the pool of available IP Addresses in the network and
46 * Remembers the mapping between MAC ID and IP Addresses assigned.
47 */
48
49@Component(immediate = true)
50@Service
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070051public class DistributedDhcpStore implements DhcpStore {
samanwita palf28207b2015-09-04 10:41:56 -070052
53 private final Logger log = LoggerFactory.getLogger(getClass());
54
55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected StorageService storageService;
57
samanwita pal2a313402015-09-14 16:03:22 -070058 private ConsistentMap<HostId, IpAssignment> allocationMap;
samanwita palf28207b2015-09-04 10:41:56 -070059
60 private DistributedSet<Ip4Address> freeIPPool;
61
samanwita palf28207b2015-09-04 10:41:56 -070062 private static Ip4Address startIPRange;
63
64 private static Ip4Address endIPRange;
65
66 // Hardcoded values are default values.
67
samanwita palf28207b2015-09-04 10:41:56 -070068 private static int timeoutForPendingAssignments = 60;
69
70 @Activate
71 protected void activate() {
samanwita pal2a313402015-09-14 16:03:22 -070072 allocationMap = storageService.<HostId, IpAssignment>consistentMapBuilder()
samanwita palf28207b2015-09-04 10:41:56 -070073 .withName("onos-dhcp-assignedIP")
74 .withSerializer(Serializer.using(
75 new KryoNamespace.Builder()
76 .register(KryoNamespaces.API)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070077 .register(IpAssignment.class,
78 IpAssignment.AssignmentStatus.class,
samanwita palf28207b2015-09-04 10:41:56 -070079 Date.class,
80 long.class,
81 Ip4Address.class)
82 .build()))
83 .build();
84
85 freeIPPool = storageService.<Ip4Address>setBuilder()
86 .withName("onos-dhcp-freeIP")
87 .withSerializer(Serializer.using(KryoNamespaces.API))
88 .build();
89
samanwita palf28207b2015-09-04 10:41:56 -070090 log.info("Started");
91 }
92
93 @Deactivate
94 protected void deactivate() {
samanwita palf28207b2015-09-04 10:41:56 -070095 log.info("Stopped");
96 }
97
98 @Override
samanwita pal2a313402015-09-14 16:03:22 -070099 public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) {
samanwita palf28207b2015-09-04 10:41:56 -0700100
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700101 IpAssignment assignmentInfo;
samanwita pal2a313402015-09-14 16:03:22 -0700102 if (allocationMap.containsKey(hostId)) {
103 assignmentInfo = allocationMap.get(hostId).value();
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700104 IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
samanwita palf28207b2015-09-04 10:41:56 -0700105 Ip4Address ipAddr = assignmentInfo.ipAddress();
106
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700107 if (status == IpAssignment.AssignmentStatus.Option_Assigned ||
108 status == IpAssignment.AssignmentStatus.Option_Requested) {
samanwita palf28207b2015-09-04 10:41:56 -0700109 // Client has a currently Active Binding.
110 if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
111 return ipAddr;
112 }
113
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700114 } else if (status == IpAssignment.AssignmentStatus.Option_Expired) {
samanwita palf28207b2015-09-04 10:41:56 -0700115 // Client has a Released or Expired Binding.
116 if (freeIPPool.contains(ipAddr)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700117 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700118 .ipAddress(ipAddr)
119 .timestamp(new Date())
120 .leasePeriod(timeoutForPendingAssignments)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700121 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
samanwita palf28207b2015-09-04 10:41:56 -0700122 .build();
123 if (freeIPPool.remove(ipAddr)) {
samanwita pal2a313402015-09-14 16:03:22 -0700124 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700125 return ipAddr;
126 }
127 }
128 }
129 return assignmentInfo.ipAddress();
130
131 } else if (requestedIP.toInt() != 0) {
132 // Client has requested an IP.
133 if (freeIPPool.contains(requestedIP)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700134 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700135 .ipAddress(requestedIP)
136 .timestamp(new Date())
137 .leasePeriod(timeoutForPendingAssignments)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700138 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
samanwita palf28207b2015-09-04 10:41:56 -0700139 .build();
140 if (freeIPPool.remove(requestedIP)) {
samanwita pal2a313402015-09-14 16:03:22 -0700141 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700142 return requestedIP;
143 }
144 }
145 }
146
147 // Allocate a new IP from the server's pool of available IP.
148 Ip4Address nextIPAddr = fetchNextIP();
samanwita pal2a313402015-09-14 16:03:22 -0700149 if (nextIPAddr != null) {
150 assignmentInfo = IpAssignment.builder()
151 .ipAddress(nextIPAddr)
152 .timestamp(new Date())
153 .leasePeriod(timeoutForPendingAssignments)
154 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested)
155 .build();
samanwita palf28207b2015-09-04 10:41:56 -0700156
samanwita pal2a313402015-09-14 16:03:22 -0700157 allocationMap.put(hostId, assignmentInfo);
158 }
samanwita palf28207b2015-09-04 10:41:56 -0700159 return nextIPAddr;
160
161 }
162
163 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700164 public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) {
samanwita palf28207b2015-09-04 10:41:56 -0700165
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700166 IpAssignment assignmentInfo;
samanwita pal2a313402015-09-14 16:03:22 -0700167 if (allocationMap.containsKey(hostId)) {
168 assignmentInfo = allocationMap.get(hostId).value();
samanwita palf28207b2015-09-04 10:41:56 -0700169 if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
Thomas Vachuska00090442015-09-11 18:08:04 -0700170 (ipAddr.toInt() >= startIPRange.toInt()) && (ipAddr.toInt() <= endIPRange.toInt())) {
samanwita palf28207b2015-09-04 10:41:56 -0700171
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700172 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700173 .ipAddress(ipAddr)
174 .timestamp(new Date())
175 .leasePeriod(leaseTime)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700176 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
samanwita palf28207b2015-09-04 10:41:56 -0700177 .build();
samanwita pal2a313402015-09-14 16:03:22 -0700178 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700179 return true;
180 }
181 } else if (freeIPPool.contains(ipAddr)) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700182 assignmentInfo = IpAssignment.builder()
samanwita palf28207b2015-09-04 10:41:56 -0700183 .ipAddress(ipAddr)
184 .timestamp(new Date())
185 .leasePeriod(leaseTime)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700186 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
samanwita palf28207b2015-09-04 10:41:56 -0700187 .build();
188 if (freeIPPool.remove(ipAddr)) {
samanwita pal2a313402015-09-14 16:03:22 -0700189 allocationMap.put(hostId, assignmentInfo);
samanwita palf28207b2015-09-04 10:41:56 -0700190 return true;
191 }
192 }
193 return false;
194 }
195
196 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700197 public void releaseIP(HostId hostId) {
198 if (allocationMap.containsKey(hostId)) {
199 IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value())
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700200 .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired)
samanwita palf28207b2015-09-04 10:41:56 -0700201 .build();
202 Ip4Address freeIP = newAssignment.ipAddress();
samanwita pal2a313402015-09-14 16:03:22 -0700203 allocationMap.put(hostId, newAssignment);
204 if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
205 freeIPPool.add(freeIP);
206 }
samanwita palf28207b2015-09-04 10:41:56 -0700207 }
208 }
209
210 @Override
211 public void setDefaultTimeoutForPurge(int timeInSeconds) {
212 timeoutForPendingAssignments = timeInSeconds;
213 }
214
215 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700216 public Map<HostId, IpAssignment> listMapping() {
samanwita palf28207b2015-09-04 10:41:56 -0700217
samanwita pal2a313402015-09-14 16:03:22 -0700218 Map<HostId, IpAssignment> allMapping = new HashMap<>();
219 for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700220 IpAssignment assignment = entry.getValue().value();
221 if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned) {
Thomas Vachuska54dc3522015-09-09 00:11:45 -0700222 allMapping.put(entry.getKey(), assignment);
samanwita palf28207b2015-09-04 10:41:56 -0700223 }
224 }
samanwita palf28207b2015-09-04 10:41:56 -0700225 return allMapping;
Thomas Vachuska54dc3522015-09-09 00:11:45 -0700226
samanwita palf28207b2015-09-04 10:41:56 -0700227 }
228
229 @Override
230 public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
samanwita pal2a313402015-09-14 16:03:22 -0700231 HostId host = HostId.hostId(macID);
232 return assignIP(host, ipAddr, -1);
samanwita palf28207b2015-09-04 10:41:56 -0700233 }
234
235 @Override
236 public boolean removeStaticIP(MacAddress macID) {
samanwita pal2a313402015-09-14 16:03:22 -0700237 HostId host = HostId.hostId(macID);
238 if (allocationMap.containsKey(host)) {
239 IpAssignment assignment = allocationMap.get(host).value();
samanwita palf28207b2015-09-04 10:41:56 -0700240 Ip4Address freeIP = assignment.ipAddress();
241 if (assignment.leasePeriod() < 0) {
samanwita pal2a313402015-09-14 16:03:22 -0700242 allocationMap.remove(host);
243 if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
244 freeIPPool.add(freeIP);
245 }
samanwita palf28207b2015-09-04 10:41:56 -0700246 return true;
247 }
248 }
249 return false;
250 }
251
252 @Override
253 public Iterable<Ip4Address> getAvailableIPs() {
Sho SHIMIZUfd0933b2015-09-11 15:17:48 -0700254 return ImmutableSet.copyOf(freeIPPool);
samanwita palf28207b2015-09-04 10:41:56 -0700255 }
256
257 @Override
258 public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
259 // Clear all entries from previous range.
260 startIPRange = startIP;
261 endIPRange = endIP;
262 freeIPPool.clear();
263
264 int lastIP = endIP.toInt();
265 Ip4Address nextIP;
266 for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
267 nextIP = Ip4Address.valueOf(loopCounter);
268 freeIPPool.add(nextIP);
269 }
270 }
271
272 /**
273 * Fetches the next available IP from the free pool pf IPs.
274 *
275 * @return the next available IP address
276 */
277 private Ip4Address fetchNextIP() {
278 for (Ip4Address freeIP : freeIPPool) {
279 if (freeIPPool.remove(freeIP)) {
280 return freeIP;
281 }
282 }
283 return null;
284 }
samanwita palf28207b2015-09-04 10:41:56 -0700285}