ONOS-2197 Enabling configuration using a json file for the DHCP server

Change-Id: I2e2998eec134d8e230a806c898e8f15d5cd1b559
diff --git a/onos-app-dhcpserver/pom.xml b/onos-app-dhcpserver/pom.xml
index 8f9000e..33a1f42 100644
--- a/onos-app-dhcpserver/pom.xml
+++ b/onos-app-dhcpserver/pom.xml
@@ -63,6 +63,12 @@
             <artifactId>onos-core-serializers</artifactId>
             <version>${project.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/DHCPStore.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/DHCPStore.java
index 29cb277..e2cabbd 100644
--- a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/DHCPStore.java
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/DHCPStore.java
@@ -26,6 +26,14 @@
 public interface DHCPStore {
 
     /**
+     * Appends all the IPs in a given range to the free pool of IPs.
+     *
+     * @param startIP Start IP for the range
+     * @param endIP End IP for the range
+     */
+    void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP);
+
+    /**
      * Returns an IP Address for a Mac ID, in response to a DHCP DISCOVER message.
      *
      * @param macID Mac ID of the client requesting an IP
@@ -51,6 +59,13 @@
     void setDefaultTimeoutForPurge(int timeInSeconds);
 
     /**
+     * Sets the delay after which the dhcp server will purge expired entries.
+     *
+     * @param timeInSeconds default time
+     */
+    void setTimerDelay(int timeInSeconds);
+
+    /**
      * Releases the IP assigned to a Mac ID into the free pool.
      *
      * @param macID the macID for which the mapping needs to be changed
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPConfig.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPConfig.java
new file mode 100644
index 0000000..4b678f1
--- /dev/null
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPConfig.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2014 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.dhcpserver.impl;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.config.Config;
+import org.onosproject.incubator.net.config.basics.BasicElementConfig;
+
+/**
+ * DHCP Config class.
+ */
+public class DHCPConfig extends Config<ApplicationId> {
+
+    public static final String MY_IP = "ip";
+    public static final String MY_MAC = "mac";
+    public static final String SUBNET_MASK = "subnet";
+    public static final String BROADCAST_ADDRESS = "broadcast";
+    public static final String TTL = "ttl";
+    public static final String LEASE_TIME = "lease";
+    public static final String RENEW_TIME = "renew";
+    public static final String REBIND_TIME = "rebind";
+
+    /**
+     * Returns the dhcp server ip.
+     *
+     * @return ip address or null if not set
+     */
+    public String ip() {
+        return get(MY_IP, null);
+    }
+
+    /**
+     * Sets the dhcp server ip.
+     *
+     * @param ip new ip address; null to clear
+     * @return self
+     */
+    public BasicElementConfig ip(String ip) {
+        return (BasicElementConfig) setOrClear(MY_IP, ip);
+    }
+
+    /**
+     * Returns the dhcp server mac.
+     *
+     * @return server mac or null if not set
+     */
+    public String mac() {
+        return get(MY_MAC, null);
+    }
+
+    /**
+     * Sets the dhcp server mac.
+     *
+     * @param mac new mac address; null to clear
+     * @return self
+     */
+    public BasicElementConfig mac(String mac) {
+        return (BasicElementConfig) setOrClear(MY_MAC, mac);
+    }
+
+    /**
+     * Returns the subnet mask.
+     *
+     * @return subnet mask or null if not set
+     */
+    public String subnetMask() {
+        return get(SUBNET_MASK, null);
+    }
+
+    /**
+     * Sets the subnet mask.
+     *
+     * @param subnet new subnet mask; null to clear
+     * @return self
+     */
+    public BasicElementConfig subnetMask(String subnet) {
+        return (BasicElementConfig) setOrClear(SUBNET_MASK, subnet);
+    }
+
+    /**
+     * Returns the broadcast address.
+     *
+     * @return broadcast address or null if not set
+     */
+    public String broadcastAddress() {
+        return get(BROADCAST_ADDRESS, null);
+    }
+
+    /**
+     * Sets the broadcast address.
+     *
+     * @param broadcast new broadcast address; null to clear
+     * @return self
+     */
+    public BasicElementConfig broadcastAddress(String broadcast) {
+        return (BasicElementConfig) setOrClear(BROADCAST_ADDRESS, broadcast);
+    }
+
+    /**
+     * Returns the Time To Live for the reply packets.
+     *
+     * @return ttl or null if not set
+     */
+    public String ttl() {
+        return get(TTL, null);
+    }
+
+    /**
+     * Sets the Time To Live for the reply packets.
+     *
+     * @param ttl new ttl; null to clear
+     * @return self
+     */
+    public BasicElementConfig ttl(String ttl) {
+        return (BasicElementConfig) setOrClear(TTL, ttl);
+    }
+
+    /**
+     * Returns the Lease Time offered by the DHCP Server.
+     *
+     * @return lease time or null if not set
+     */
+    public String leaseTime() {
+        return get(LEASE_TIME, null);
+    }
+
+    /**
+     * Sets the Lease Time offered by the DHCP Server.
+     *
+     * @param lease new lease time; null to clear
+     * @return self
+     */
+    public BasicElementConfig leaseTime(String lease) {
+        return (BasicElementConfig) setOrClear(LEASE_TIME, lease);
+    }
+
+    /**
+     * Returns the Renew Time offered by the DHCP Server.
+     *
+     * @return renew time or null if not set
+     */
+    public String renewTime() {
+        return get(RENEW_TIME, null);
+    }
+
+    /**
+     * Sets the Renew Time offered by the DHCP Server.
+     *
+     * @param renew new renew time; null to clear
+     * @return self
+     */
+    public BasicElementConfig renewTime(String renew) {
+        return (BasicElementConfig) setOrClear(RENEW_TIME, renew);
+    }
+
+    /**
+     * Returns the Rebind Time offered by the DHCP Server.
+     *
+     * @return rebind time or null if not set
+     */
+    public String rebindTime() {
+        return get(REBIND_TIME, null);
+    }
+
+    /**
+     * Sets the Rebind Time offered by the DHCP Server.
+     *
+     * @param rebind new rebind time; null to clear
+     * @return self
+     */
+    public BasicElementConfig rebindTime(String rebind) {
+        return (BasicElementConfig) setOrClear(REBIND_TIME, rebind);
+    }
+}
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
index ee995d0..39cf17d 100644
--- a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.dhcpserver.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;
@@ -32,6 +33,10 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.dhcpserver.DHCPService;
 import org.onosproject.dhcpserver.DHCPStore;
+import org.onosproject.incubator.net.config.ConfigFactory;
+import org.onosproject.incubator.net.config.NetworkConfigEvent;
+import org.onosproject.incubator.net.config.NetworkConfigListener;
+import org.onosproject.incubator.net.config.NetworkConfigRegistry;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -49,8 +54,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.onlab.packet.MacAddress.valueOf;
+import static org.onosproject.incubator.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
 
 /**
  * Skeletal ONOS DHCP Server application.
@@ -61,6 +68,29 @@
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
+    private final NetworkConfigListener cfgListener = new InternalConfigListener();
+
+    private final Set<ConfigFactory> factories = ImmutableSet.of(
+            new ConfigFactory<ApplicationId, DHCPConfig>(APP_SUBJECT_FACTORY,
+                    DHCPConfig.class,
+                    "dhcp") {
+                @Override
+                public DHCPConfig createConfig() {
+                    return new DHCPConfig();
+                }
+            },
+            new ConfigFactory<ApplicationId, DHCPStoreConfig>(APP_SUBJECT_FACTORY,
+                    DHCPStoreConfig.class,
+                    "dhcpstore") {
+                @Override
+                public DHCPStoreConfig createConfig() {
+                    return new DHCPStoreConfig();
+                }
+            }
+    );
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
@@ -74,11 +104,11 @@
 
     private ApplicationId appId;
 
-    // TODO Make the hardcoded values configurable.
+    // Hardcoded values are default values.
 
-    private static final String MY_IP = "10.0.0.2";
+    private static String myIP = "10.0.0.2";
 
-    private static final MacAddress MY_MAC = valueOf("4f:4f:4f:4f:4f:4f");
+    private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
 
     /**
      * leaseTime - 10 mins or 600s.
@@ -98,18 +128,27 @@
 
     private static String broadcastAddress = "10.255.255.255";
 
+    private static Ip4Address startIPRange = Ip4Address.valueOf("10.1.0.140");
+
+    private static Ip4Address endIPRange = Ip4Address.valueOf("10.1.0.160");
+
     @Activate
     protected void activate() {
         // start the dhcp server
         appId = coreService.registerApplication("org.onosproject.dhcpserver");
 
+        cfgService.addListener(cfgListener);
+        factories.forEach(cfgService::registerConfigFactory);
         packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 10);
         requestPackets();
+        dhcpStore.populateIPPoolfromRange(startIPRange, endIPRange);
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
+        cfgService.removeListener(cfgListener);
+        factories.forEach(cfgService::unregisterConfigFactory);
         packetService.removeProcessor(processor);
 
         TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
@@ -184,12 +223,12 @@
          * @return the Ethernet reply frame
          */
         private Ethernet buildReply(Ethernet packet, String ipOffered, byte outgoingMessageType) {
-            Ip4Address myIPAddress = Ip4Address.valueOf(MY_IP);
+            Ip4Address myIPAddress = Ip4Address.valueOf(myIP);
             Ip4Address ipAddress;
 
             // Ethernet Frame.
             Ethernet ethReply = new Ethernet();
-            ethReply.setSourceMACAddress(MY_MAC);
+            ethReply.setSourceMACAddress(myMAC);
             ethReply.setDestinationMACAddress(packet.getSourceMAC());
             ethReply.setEtherType(Ethernet.TYPE_IPV4);
             ethReply.setVlanID(packet.getVlanID());
@@ -376,7 +415,7 @@
 
                     if (flagIfServerIP && flagIfRequestedIP) {
                         // SELECTING state
-                        if (MY_IP.equals(serverIP.toString()) &&
+                        if (myIP.equals(serverIP.toString()) &&
                                 dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
 
                             Ethernet ethReply = buildReply(packet, requestedIP.toString(),
@@ -440,4 +479,80 @@
             }
         }
     }
+
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        /**
+         * Reconfigures the DHCP Server according to the configuration parameters passed.
+         *
+         * @param cfg configuration object
+         */
+        private void reconfigureNetwork(DHCPConfig cfg) {
+
+            if (cfg.ip() != null) {
+                myIP = cfg.ip();
+            }
+            if (cfg.mac() != null) {
+                myMAC = MacAddress.valueOf(cfg.mac());
+            }
+            if (cfg.subnetMask() != null) {
+                subnetMask = cfg.subnetMask();
+            }
+            if (cfg.broadcastAddress() != null) {
+                broadcastAddress = cfg.broadcastAddress();
+            }
+            if (cfg.ttl() != null) {
+                packetTTL = Byte.valueOf(cfg.ttl());
+            }
+            if (cfg.leaseTime() != null) {
+                leaseTime = Integer.valueOf(cfg.leaseTime());
+            }
+            if (cfg.renewTime() != null) {
+                renewalTime = Integer.valueOf(cfg.renewTime());
+            }
+            if (cfg.rebindTime() != null) {
+                rebindingTime = Integer.valueOf(cfg.rebindTime());
+            }
+        }
+
+        /**
+         * Reconfigures the DHCP Store according to the configuration parameters passed.
+         *
+         * @param cfg configuration object
+         */
+        private void reconfigureStore(DHCPStoreConfig cfg) {
+
+            if (cfg.defaultTimeout() != null) {
+                dhcpStore.setDefaultTimeoutForPurge(Integer.valueOf(cfg.defaultTimeout()));
+            }
+            if (cfg.timerDelay() != null) {
+                dhcpStore.setTimerDelay(Integer.valueOf(cfg.defaultTimeout()));
+            }
+            if ((cfg.startIP() != null) && (cfg.endIP() != null)) {
+                startIPRange = Ip4Address.valueOf(cfg.startIP());
+                endIPRange = Ip4Address.valueOf(cfg.endIP());
+                dhcpStore.populateIPPoolfromRange(startIPRange, endIPRange);
+            }
+        }
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) {
+                if (event.configClass().equals(DHCPConfig.class)) {
+                    DHCPConfig cfg = cfgService.getConfig(appId, DHCPConfig.class);
+                    reconfigureNetwork(cfg);
+                    log.info("Reconfigured Manager");
+                }
+                if (event.configClass().equals(DHCPStoreConfig.class)) {
+                    DHCPStoreConfig cfg = cfgService.getConfig(appId, DHCPStoreConfig.class);
+                    reconfigureStore(cfg);
+                    log.info("Reconfigured Store");
+                }
+
+            }
+            log.info("Reconfigured");
+        }
+    }
 }
\ No newline at end of file
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPStoreConfig.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPStoreConfig.java
new file mode 100644
index 0000000..edc389c
--- /dev/null
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPStoreConfig.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 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.dhcpserver.impl;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.config.Config;
+import org.onosproject.incubator.net.config.basics.BasicElementConfig;
+
+/**
+ * DHCP Store Config class.
+ */
+public class DHCPStoreConfig extends Config<ApplicationId> {
+
+    public static final String TIMER_DELAY = "delay";
+    public static final String DEFAULT_TIMEOUT = "timeout";
+    public static final String START_IP = "startip";
+    public static final String END_IP = "endip";
+
+    /**
+     * Returns the delay after which the dhcp server will purge expired entries.
+     *
+     * @return time delay or null if not set
+     */
+    public String timerDelay() {
+        return get(TIMER_DELAY, null);
+    }
+
+    /**
+     * Sets the delay after which the dhcp server will purge expired entries.
+     *
+     * @param delay new time delay; null to clear
+     * @return self
+     */
+    public BasicElementConfig timerDelay(String delay) {
+        return (BasicElementConfig) setOrClear(TIMER_DELAY, delay);
+    }
+
+    /**
+     * Returns the default timeout for pending assignments.
+     *
+     * @return default timeout or null if not set
+     */
+    public String defaultTimeout() {
+        return get(DEFAULT_TIMEOUT, null);
+    }
+
+    /**
+     * Sets the default timeout for pending assignments.
+     *
+     * @param defaultTimeout new default timeout; null to clear
+     * @return self
+     */
+    public BasicElementConfig defaultTimeout(String defaultTimeout) {
+        return (BasicElementConfig) setOrClear(DEFAULT_TIMEOUT, defaultTimeout);
+    }
+
+    /**
+     * Returns the start IP for the available IP Range.
+     *
+     * @return start IP or null if not set
+     */
+    public String startIP() {
+        return get(START_IP, null);
+    }
+
+    /**
+     * Sets the start IP for the available IP Range.
+     *
+     * @param startIP new start IP; null to clear
+     * @return self
+     */
+    public BasicElementConfig startIP(String startIP) {
+        return (BasicElementConfig) setOrClear(START_IP, startIP);
+    }
+
+    /**
+     * Returns the end IP for the available IP Range.
+     *
+     * @return end IP or null if not set
+     */
+    public String endIP() {
+        return get(END_IP, null);
+    }
+
+    /**
+     * Sets the end IP for the available IP Range.
+     *
+     * @param endIP new end IP; null to clear
+     * @return self
+     */
+    public BasicElementConfig endIP(String endIP) {
+        return (BasicElementConfig) setOrClear(END_IP, endIP);
+    }
+}
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DistributedDHCPStore.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DistributedDHCPStore.java
index 7344e6c..d072b58 100644
--- a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DistributedDHCPStore.java
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DistributedDHCPStore.java
@@ -64,16 +64,16 @@
 
     private Timeout timeout;
 
-    // TODO Make the hardcoded values configurable.
+    private static Ip4Address startIPRange;
 
-    private static final int INITIAL_DELAY = 2;
+    private static Ip4Address endIPRange;
+
+    // Hardcoded values are default values.
+
+    private static int timerDelay = 2;
 
     private static int timeoutForPendingAssignments = 60;
 
-    private static final Ip4Address START_IP = Ip4Address.valueOf("10.1.0.140");
-
-    private static final Ip4Address END_IP = Ip4Address.valueOf("10.1.0.160");
-
     @Activate
     protected void activate() {
         allocationMap = storageService.<MacAddress, IPAssignment>consistentMapBuilder()
@@ -94,8 +94,7 @@
                 .withSerializer(Serializer.using(KryoNamespaces.API))
                 .build();
 
-        populateIPPoolfromRange(START_IP, END_IP);
-        timeout = Timer.getTimer().newTimeout(new PurgeListTask(), INITIAL_DELAY, TimeUnit.MINUTES);
+        timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
 
         log.info("Started");
     }
@@ -118,7 +117,9 @@
             if (status == IPAssignment.AssignmentStatus.Option_Assigned ||
                     status == IPAssignment.AssignmentStatus.Option_Requested) {
                 // Client has a currently Active Binding.
-                return ipAddr;
+                if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
+                    return ipAddr;
+                }
 
             } else if (status == IPAssignment.AssignmentStatus.Option_Expired) {
                 // Client has a Released or Expired Binding.
@@ -173,14 +174,15 @@
         IPAssignment assignmentInfo;
         if (allocationMap.containsKey(macID)) {
             assignmentInfo = allocationMap.get(macID).value();
-            if (assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) {
+            if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
+                    (ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
 
                 assignmentInfo = IPAssignment.builder()
-                                    .ipAddress(ipAddr)
-                                    .timestamp(new Date())
-                                    .leasePeriod(leaseTime)
-                                    .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
-                                    .build();
+                        .ipAddress(ipAddr)
+                        .timestamp(new Date())
+                        .leasePeriod(leaseTime)
+                        .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
+                        .build();
                 allocationMap.put(macID, assignmentInfo);
                 return true;
             }
@@ -217,6 +219,11 @@
     }
 
     @Override
+    public void setTimerDelay(int timeInSeconds) {
+        timerDelay = timeInSeconds;
+    }
+
+    @Override
     public Map<MacAddress, Ip4Address> listMapping() {
 
         Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
@@ -254,13 +261,13 @@
         return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
     }
 
-    /**
-     * Appends all the IPs in a given range to the free pool of IPs.
-     *
-     * @param startIP Start IP for the range
-     * @param endIP End IP for the range
-     */
+    @Override
     public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
+        // Clear all entries from previous range.
+        startIPRange = startIP;
+        endIPRange = endIP;
+        freeIPPool.clear();
+
         int lastIP = endIP.toInt();
         Ip4Address nextIP;
         for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
@@ -300,13 +307,16 @@
                     Ip4Address freeIP = ipAssignment.ipAddress();
 
                     newAssignment = IPAssignment.builder(ipAssignment)
-                                                .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
-                                                .build();
+                            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
+                            .build();
                     allocationMap.put(entry.getKey(), newAssignment);
-                    freeIPPool.add(freeIP);
+
+                    if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
+                        freeIPPool.add(freeIP);
+                    }
                 }
             }
-            timeout = Timer.getTimer().newTimeout(new PurgeListTask(), INITIAL_DELAY, TimeUnit.MINUTES);
+            timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
         }
 
     }
diff --git a/onos-app-dhcpserver/src/test/resources/dhcp-cfg.json b/onos-app-dhcpserver/src/test/resources/dhcp-cfg.json
new file mode 100644
index 0000000..c4aefff
--- /dev/null
+++ b/onos-app-dhcpserver/src/test/resources/dhcp-cfg.json
@@ -0,0 +1,22 @@
+{
+  "apps": {
+    "org.onosproject.dhcpserver" : {
+      "dhcp" : {
+        "ip": "10.0.0.1",
+        "mac": "1f:2f:3f:4f:5f:6f",
+        "subnet": "255.0.0.0",
+        "broadcast": "10.255.255.255",
+        "ttl": "63",
+        "lease": "300",
+        "renew": "150",
+        "rebind": "200"
+      },
+      "dhcpstore" : {
+        "delay": "3",
+        "timeout": "150",
+        "startip": "10.0.0.110",
+        "endip": "10.0.0.130"
+      }
+    }
+  }
+}
\ No newline at end of file