diff options
Diffstat (limited to 'framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java')
-rw-r--r-- | framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java new file mode 100644 index 00000000..63f69d40 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java @@ -0,0 +1,328 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.impl; + +import com.google.common.collect.ImmutableSet; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onlab.util.KryoNamespace; +import org.onosproject.dhcp.DhcpStore; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.HostId; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.DistributedSet; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Manages the pool of available IP Addresses in the network and + * Remembers the mapping between MAC ID and IP Addresses assigned. + */ + +@Component(immediate = true) +@Service +public class DistributedDhcpStore implements DhcpStore { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + private ConsistentMap<HostId, IpAssignment> allocationMap; + + private DistributedSet<Ip4Address> freeIPPool; + + private static Ip4Address startIPRange; + + private static Ip4Address endIPRange; + + // Hardcoded values are default values. + + private static int timeoutForPendingAssignments = 60; + + @Activate + protected void activate() { + allocationMap = storageService.<HostId, IpAssignment>consistentMapBuilder() + .withName("onos-dhcp-assignedIP") + .withSerializer(Serializer.using( + new KryoNamespace.Builder() + .register(KryoNamespaces.API) + .register(IpAssignment.class, + IpAssignment.AssignmentStatus.class, + Date.class, + long.class, + Ip4Address.class) + .build())) + .build(); + + freeIPPool = storageService.<Ip4Address>setBuilder() + .withName("onos-dhcp-freeIP") + .withSerializer(Serializer.using(KryoNamespaces.API)) + .build(); + + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + log.info("Stopped"); + } + + @Override + public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { + + IpAssignment assignmentInfo; + if (allocationMap.containsKey(hostId)) { + assignmentInfo = allocationMap.get(hostId).value(); + IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); + Ip4Address ipAddr = assignmentInfo.ipAddress(); + + if (status == IpAssignment.AssignmentStatus.Option_Assigned || + status == IpAssignment.AssignmentStatus.Option_Requested) { + // Client has a currently Active Binding. + if (ipWithinRange(ipAddr)) { + return ipAddr; + } + + } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { + // Client has a Released or Expired Binding. + if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return ipAddr; + } + } + } + } else if (requestedIP.toInt() != 0) { + // Client has requested an IP. + if (freeIPPool.contains(requestedIP)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(requestedIP) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + if (freeIPPool.remove(requestedIP)) { + allocationMap.put(hostId, assignmentInfo); + return requestedIP; + } + } + } + + // Allocate a new IP from the server's pool of available IP. + Ip4Address nextIPAddr = fetchNextIP(); + if (nextIPAddr != null) { + assignmentInfo = IpAssignment.builder() + .ipAddress(nextIPAddr) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + + allocationMap.put(hostId, assignmentInfo); + } + return nextIPAddr; + + } + + @Override + public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) { + + IpAssignment assignmentInfo; + if (allocationMap.containsKey(hostId)) { + assignmentInfo = allocationMap.get(hostId).value(); + IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); + + if (Objects.equals(assignmentInfo.ipAddress(), ipAddr) && ipWithinRange(ipAddr)) { + + if (status == IpAssignment.AssignmentStatus.Option_Assigned || + status == IpAssignment.AssignmentStatus.Option_Requested) { + // Client has a currently active binding with the server. + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + allocationMap.put(hostId, assignmentInfo); + return true; + } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { + // Client has an expired binding with the server. + if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return true; + } + } + } + } + } else if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return true; + } + } + return false; + } + + @Override + public Ip4Address releaseIP(HostId hostId) { + if (allocationMap.containsKey(hostId)) { + IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value()) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired) + .build(); + Ip4Address freeIP = newAssignment.ipAddress(); + allocationMap.put(hostId, newAssignment); + if (ipWithinRange(freeIP)) { + freeIPPool.add(freeIP); + } + return freeIP; + } + return null; + } + + @Override + public void setDefaultTimeoutForPurge(int timeInSeconds) { + timeoutForPendingAssignments = timeInSeconds; + } + + @Override + public Map<HostId, IpAssignment> listAssignedMapping() { + + Map<HostId, IpAssignment> validMapping = new HashMap<>(); + IpAssignment assignment; + for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) { + assignment = entry.getValue().value(); + if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned) { + validMapping.put(entry.getKey(), assignment); + } + } + return validMapping; + } + + @Override + public Map<HostId, IpAssignment> listAllMapping() { + Map<HostId, IpAssignment> validMapping = new HashMap<>(); + for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) { + validMapping.put(entry.getKey(), entry.getValue().value()); + } + return validMapping; + } + + @Override + public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) { + HostId host = HostId.hostId(macID); + return assignIP(host, ipAddr, -1); + } + + @Override + public boolean removeStaticIP(MacAddress macID) { + HostId host = HostId.hostId(macID); + if (allocationMap.containsKey(host)) { + IpAssignment assignment = allocationMap.get(host).value(); + Ip4Address freeIP = assignment.ipAddress(); + if (assignment.leasePeriod() < 0) { + allocationMap.remove(host); + if (ipWithinRange(freeIP)) { + freeIPPool.add(freeIP); + } + return true; + } + } + return false; + } + + @Override + public Iterable<Ip4Address> getAvailableIPs() { + return ImmutableSet.copyOf(freeIPPool); + } + + @Override + public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { + // Clear all entries from previous range. + allocationMap.clear(); + freeIPPool.clear(); + startIPRange = startIP; + endIPRange = endIP; + + int lastIP = endIP.toInt(); + Ip4Address nextIP; + for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) { + nextIP = Ip4Address.valueOf(loopCounter); + freeIPPool.add(nextIP); + } + } + + /** + * Fetches the next available IP from the free pool pf IPs. + * + * @return the next available IP address + */ + private Ip4Address fetchNextIP() { + for (Ip4Address freeIP : freeIPPool) { + if (freeIPPool.remove(freeIP)) { + return freeIP; + } + } + return null; + } + + /** + * Returns true if the given ip is within the range of available IPs. + * + * @param ip given ip address + * @return true if within range, false otherwise + */ + private boolean ipWithinRange(Ip4Address ip) { + if ((ip.toInt() >= startIPRange.toInt()) && (ip.toInt() <= endIPRange.toInt())) { + return true; + } + return false; + } +} |