Moving DHCP to onos branch. REST API included, GUI to be added later.

Change-Id: Id52781ba93d48ad1d56097a9ceff7613a190c48e
diff --git a/apps/onos-app-dhcp/pom.xml b/apps/onos-app-dhcp/pom.xml
new file mode 100644
index 0000000..1329816
--- /dev/null
+++ b/apps/onos-app-dhcp/pom.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  --><project xmlns="http://maven.apache.org/POM/4.0.0"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-apps</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.3.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-dhcp</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>DHCP Server application</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.dhcp</onos.app.name>
+        <web.context>/onos/dhcp</web.context>
+        <api.version>1.0.0</api.version>
+        <api.title>DHCP Server REST API</api.title>
+        <api.description>
+            APIs for interacting with the DHCP Server application.
+        </api.description>
+        <api.package>org.onosproject.dhcp.rest</api.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <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>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Include-Resource>
+                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+                            {maven-resources}
+                        </Include-Resource>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.node,
+                            com.fasterxml.jackson.core,
+                            org.apache.karaf.shell.commands,
+                            org.apache.karaf.shell.console,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onlab.rest.*,
+                            org.onosproject.*,
+                            org.onlab.util.*,
+                            org.jboss.netty.util.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPService.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPService.java
new file mode 100644
index 0000000..238da01
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPService.java
@@ -0,0 +1,80 @@
+/*
+ * 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.dhcp;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+
+import java.util.Map;
+
+/**
+ * DHCP Service Interface.
+ */
+public interface DHCPService {
+
+    /**
+     * Returns a collection of all the MacAddress to IPAddress mapping.
+     *
+     * @return collection of mappings.
+     */
+    Map<MacAddress, Ip4Address> listMapping();
+
+    /**
+     * Returns the default lease time granted by the DHCP Server.
+     *
+     * @return lease time
+     */
+    int getLeaseTime();
+
+    /**
+     * Returns the default renewal time granted by the DHCP Server.
+     *
+     * @return renewal time
+     */
+    int getRenewalTime();
+
+    /**
+     * Returns the default rebinding time granted by the DHCP Server.
+     *
+     * @return rebinding time
+     */
+    int getRebindingTime();
+
+    /**
+     * Registers a static IP mapping with the DHCP Server.
+     *
+     * @param macID     macID of the client
+     * @param ipAddress IP Address requested for the client
+     * @return true if the mapping was successfully registered, false otherwise
+     */
+    boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress);
+
+    /**
+     * Removes a static IP mapping with the DHCP Server.
+     *
+     * @param macID macID of the client
+     * @return true if the mapping was successfully removed, false otherwise
+     */
+    boolean removeStaticMapping(MacAddress macID);
+
+    /**
+     * Returns the list of all the available IPs with the server.
+     *
+     * @return list of available IPs
+     */
+    Iterable<Ip4Address> getAvailableIPs();
+
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPStore.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPStore.java
new file mode 100644
index 0000000..de864db
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/DHCPStore.java
@@ -0,0 +1,106 @@
+/*
+ * 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.dhcp;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+
+import java.util.Map;
+
+/**
+ * DHCPStore Interface.
+ */
+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
+     * @return IP address assigned to the Mac ID
+     */
+    Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP);
+
+    /**
+     * Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message.
+     *
+     * @param macID Mac Id of the client requesting an IP
+     * @param ipAddr IP Address being requested
+     * @param leaseTime Lease time offered by the server for this mapping
+     * @return returns true if the assignment was successful, false otherwise
+     */
+    boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime);
+
+    /**
+     * Sets the default time for which suggested IP mappings are valid.
+     *
+     * @param timeInSeconds default time for IP mappings to be valid
+     */
+    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
+     */
+    void releaseIP(MacAddress macID);
+
+    /**
+     * Returns a collection of all the MacAddress to IPAddress mapping.
+     *
+     * @return the collection of the mappings
+     */
+    Map<MacAddress, Ip4Address> listMapping();
+
+    /**
+     * Assigns the requested IP to the MAC ID (if available) for an indefinite period of time.
+     *
+     * @param macID macID of the client
+     * @param ipAddr IP Address requested for the client
+     * @return true if the mapping was successfully registered, false otherwise
+     */
+    boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr);
+
+    /**
+     * Removes a static IP mapping associated with the given MAC ID from the DHCP Server.
+     *
+     * @param macID macID of the client
+     * @return true if the mapping was successfully registered, false otherwise
+     */
+    boolean removeStaticIP(MacAddress macID);
+
+    /**
+     * Returns the list of all the available IPs with the server.
+     *
+     * @return list of available IPs
+     */
+    Iterable<Ip4Address> getAvailableIPs();
+
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/IPAssignment.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/IPAssignment.java
new file mode 100644
index 0000000..48a3e52
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/IPAssignment.java
@@ -0,0 +1,205 @@
+/*
+ * 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.dhcp;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Date;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Stores the MAC ID to IP Address mapping details.
+ */
+public final class IPAssignment {
+
+    private final Ip4Address ipAddress;
+
+    private final Date timestamp;
+
+    private final long leasePeriod;
+
+    private final AssignmentStatus assignmentStatus;
+
+    public enum AssignmentStatus {
+        /**
+         * IP has been requested by a host, but not assigned to it yet.
+         */
+        Option_Requested,
+
+        /**
+         * IP has been assigned to a host.
+         */
+        Option_Assigned,
+
+        /**
+         * IP mapping is no longer active.
+         */
+        Option_Expired;
+    }
+
+    /**
+     * Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp
+     * and assignment status is supplied.
+     *
+     * @param ipAddress
+     * @param leasePeriod
+     * @param assignmentStatus
+     */
+    private IPAssignment(Ip4Address ipAddress,
+                         long leasePeriod,
+                         Date timestamp,
+                         AssignmentStatus assignmentStatus) {
+        this.ipAddress = ipAddress;
+        this.leasePeriod = leasePeriod;
+        this.timestamp = timestamp;
+        this.assignmentStatus = assignmentStatus;
+    }
+
+    /**
+     * Returns the IP Address of the IP assignment.
+     *
+     * @return the IP address
+     */
+    public Ip4Address ipAddress() {
+        return this.ipAddress;
+    }
+
+    /**
+     * Returns the timestamp of the IP assignment.
+     *
+     * @return the timestamp
+     */
+    public Date timestamp() {
+        return this.timestamp;
+    }
+
+    /**
+     * Returns the assignment status of the IP assignment.
+     *
+     * @return the assignment status
+     */
+    public AssignmentStatus assignmentStatus() {
+        return this.assignmentStatus;
+    }
+
+    /**
+     * Returns the lease period of the IP assignment.
+     *
+     * @return the lease period
+     */
+    public int leasePeriod() {
+        return (int) this.leasePeriod / 1000;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("ip", ipAddress)
+                .add("timestamp", timestamp)
+                .add("lease", leasePeriod)
+                .add("assignmentStatus", assignmentStatus)
+                .toString();
+    }
+
+    /**
+     * Creates and returns a new builder instance.
+     *
+     * @return new builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Creates and returns a new builder instance that clones an existing IPAssignment.
+     *
+     * @return new builder
+     */
+    public static Builder builder(IPAssignment assignment) {
+        return new Builder(assignment);
+    }
+
+    /**
+     * IPAssignment Builder.
+     */
+    public static final class Builder {
+
+        private Ip4Address ipAddress;
+
+        private Date timeStamp;
+
+        private long leasePeriod;
+
+        private AssignmentStatus assignmentStatus;
+
+        private Builder() {
+
+        }
+
+        private Builder(IPAssignment ipAssignment) {
+            ipAddress = ipAssignment.ipAddress();
+            timeStamp = ipAssignment.timestamp();
+            leasePeriod = ipAssignment.leasePeriod() * 1000;
+            assignmentStatus = ipAssignment.assignmentStatus();
+        }
+
+        public IPAssignment build() {
+            validateInputs();
+            return new IPAssignment(ipAddress,
+                                    leasePeriod,
+                                    timeStamp,
+                                    assignmentStatus);
+        }
+
+        public Builder ipAddress(Ip4Address addr) {
+            ipAddress = addr;
+            return this;
+        }
+
+        public Builder timestamp(Date timestamp) {
+            timeStamp = timestamp;
+            return this;
+        }
+
+        public Builder leasePeriod(int leasePeriodinSeconds) {
+            leasePeriod = leasePeriodinSeconds * 1000;
+            return this;
+        }
+
+        public Builder assignmentStatus(AssignmentStatus status) {
+            assignmentStatus = status;
+            return this;
+        }
+
+        private void validateInputs() {
+            checkNotNull(ipAddress, "IP Address must be specified");
+            checkNotNull(assignmentStatus, "Assignment Status must be specified");
+            checkNotNull(leasePeriod, "Lease Period must be specified");
+            checkNotNull(timeStamp, "Timestamp must be specified");
+
+            switch (assignmentStatus) {
+                case Option_Requested:
+                case Option_Assigned:
+                case Option_Expired:
+                    break;
+                default:
+                    throw new IllegalStateException("Unknown assignment status");
+            }
+        }
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPLeaseDetails.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPLeaseDetails.java
new file mode 100644
index 0000000..ca70418
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPLeaseDetails.java
@@ -0,0 +1,41 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DHCPService;
+
+/**
+ * Lists all the default lease parameters offered by the DHCP Server.
+ */
+@Command(scope = "onos", name = "dhcp-lease",
+        description = "Lists all the default lease parameters offered by the DHCP Server")
+public class DHCPLeaseDetails extends AbstractShellCommand {
+
+    private static final String DHCP_LEASE_FORMAT = "Lease Time: %ds\nRenewal Time: %ds\nRebinding Time: %ds";
+
+    @Override
+    protected void execute() {
+
+        DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
+        int leaseTime = dhcpService.getLeaseTime();
+        int renewTime = dhcpService.getRenewalTime();
+        int rebindTime = dhcpService.getRebindingTime();
+
+        print(DHCP_LEASE_FORMAT, leaseTime, renewTime, rebindTime);
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPListAllMappings.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPListAllMappings.java
new file mode 100644
index 0000000..38efa96
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPListAllMappings.java
@@ -0,0 +1,44 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DHCPService;
+
+import java.util.Map;
+
+/**
+ * Lists all the MacAddress to IP Address mappings held by the DHCP Server.
+ */
+@Command(scope = "onos", name = "dhcp-list",
+        description = "Lists all the MAC to IP mappings held by the DHCP Server")
+public class DHCPListAllMappings extends AbstractShellCommand {
+
+    private static final String DHCP_MAPPING_FORMAT = "MAC ID: %s -> IP ASSIGNED %s";
+    @Override
+    protected void execute() {
+
+        DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
+        Map<MacAddress, Ip4Address> allocationMap = dhcpService.listMapping();
+
+        for (Map.Entry<MacAddress, Ip4Address> entry : allocationMap.entrySet()) {
+            print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().toString());
+        }
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPRemoveStaticMapping.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPRemoveStaticMapping.java
new file mode 100644
index 0000000..f558905
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPRemoveStaticMapping.java
@@ -0,0 +1,56 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DHCPService;
+
+/**
+ * Removes a static MAC Address to IP Mapping from the DHCP Server.
+ */
+@Command(scope = "onos", name = "dhcp-remove-static-mapping",
+        description = "Removes a static MAC Address to IP Mapping from the DHCP Server")
+public class DHCPRemoveStaticMapping extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "macAddr",
+            description = "MAC Address of the client",
+            required = true, multiValued = false)
+    String macAddr = null;
+
+    private static final String DHCP_SUCCESS = "Static Mapping Successfully Removed.";
+    private static final String DHCP_FAILURE = "Static Mapping Removal Failed. " +
+                                                "Either the mapping does not exist or it is not static.";
+
+    @Override
+    protected void execute() {
+        DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
+
+        try {
+            MacAddress macID = MacAddress.valueOf(macAddr);
+            if (dhcpService.removeStaticMapping(macID)) {
+                print(DHCP_SUCCESS);
+            } else {
+                print(DHCP_FAILURE);
+            }
+
+        } catch (IllegalArgumentException e) {
+            print(e.getMessage());
+        }
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPSetStaticMapping.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPSetStaticMapping.java
new file mode 100644
index 0000000..3f2ad29
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/DHCPSetStaticMapping.java
@@ -0,0 +1,61 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DHCPService;
+
+/**
+ * Registers a static MAC Address to IP Mapping with the DHCP Server.
+ */
+@Command(scope = "onos", name = "dhcp-set-static-mapping",
+        description = "Registers a static MAC Address to IP Mapping with the DHCP Server")
+public class DHCPSetStaticMapping extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "macAddr",
+            description = "MAC Address of the client",
+            required = true, multiValued = false)
+    String macAddr = null;
+
+    @Argument(index = 1, name = "ipAddr",
+            description = "IP Address requested for static mapping",
+            required = true, multiValued = false)
+    String ipAddr = null;
+
+    private static final String DHCP_SUCCESS = "Static Mapping Successfully Added.";
+    private static final String DHCP_FAILURE = "Static Mapping Failed. The IP maybe unavailable.";
+    @Override
+    protected void execute() {
+        DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
+
+        try {
+            MacAddress macID = MacAddress.valueOf(macAddr);
+            Ip4Address ipAddress = Ip4Address.valueOf(ipAddr);
+            if (dhcpService.setStaticMapping(macID, ipAddress)) {
+                print(DHCP_SUCCESS);
+            } else {
+                print(DHCP_FAILURE);
+            }
+
+        } catch (IllegalArgumentException e) {
+            print(e.getMessage());
+        }
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIPCompleter.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIPCompleter.java
new file mode 100644
index 0000000..a21b985
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIPCompleter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DHCPService;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * Free IP Completer.
+ */
+public class FreeIPCompleter implements Completer {
+
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        // Delegate string completer
+        StringsCompleter delegate = new StringsCompleter();
+        DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
+        Iterator<Ip4Address> it = dhcpService.getAvailableIPs().iterator();
+        SortedSet<String> strings = delegate.getStrings();
+
+        while (it.hasNext()) {
+            strings.add(it.next().toString());
+        }
+
+        // Now let the completer do the work for figuring out what to offer.
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java
new file mode 100644
index 0000000..d6cd73a
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.dhcp.cli;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostService;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * MAC ID Completer.
+ */
+public class MacIdCompleter implements Completer {
+
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        // Delegate string completer
+        StringsCompleter delegate = new StringsCompleter();
+        HostService service = AbstractShellCommand.get(HostService.class);
+        Iterator<Host> it = service.getHosts().iterator();
+        SortedSet<String> strings = delegate.getStrings();
+
+        while (it.hasNext()) {
+            strings.add(it.next().mac().toString());
+        }
+
+        // Now let the completer do the work for figuring out what to offer.
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPConfig.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPConfig.java
new file mode 100644
index 0000000..cedae89
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPConfig.java
@@ -0,0 +1,227 @@
+/*
+ * 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.dhcp.impl;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.onosproject.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 ROUTER_ADDRESS = "router";
+    public static final String DOMAIN_SERVER = "domain";
+    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);
+    }
+
+    /**
+     * Returns the Router Address.
+     *
+     * @return router address or null if not set
+     */
+    public String routerAddress() {
+        return get(ROUTER_ADDRESS, null);
+    }
+
+    /**
+     * Sets the Router Address.
+     *
+     * @param router new router address; null to clear
+     * @return self
+     */
+    public BasicElementConfig routerAddress(String router) {
+        return (BasicElementConfig) setOrClear(ROUTER_ADDRESS, router);
+    }
+
+    /**
+     * Returns the Domain Server Address.
+     *
+     * @return domain server address or null if not set
+     */
+    public String domainServer() {
+        return get(DOMAIN_SERVER, null);
+    }
+
+    /**
+     * Sets the Domain Server Address.
+     *
+     * @param domain new domain server address; null to clear
+     * @return self
+     */
+    public BasicElementConfig domainServer(String domain) {
+        return (BasicElementConfig) setOrClear(DOMAIN_SERVER, domain);
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPManager.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPManager.java
new file mode 100644
index 0000000..04bba9c
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPManager.java
@@ -0,0 +1,668 @@
+/*
+ * 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.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.ARP;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.DHCPOption;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.UDP;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.dhcp.DHCPService;
+import org.onosproject.dhcp.DHCPStore;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.onlab.packet.MacAddress.valueOf;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+
+/**
+ * Skeletal ONOS DHCP Server application.
+ */
+@Component(immediate = true)
+@Service
+public class DHCPManager implements DHCPService {
+
+    private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true);
+    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;
+
+    private DHCPPacketProcessor processor = new DHCPPacketProcessor();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DHCPStore dhcpStore;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostProviderRegistry hostProviderRegistry;
+
+    protected HostProviderService hostProviderService;
+
+    private ApplicationId appId;
+
+    // Hardcoded values are default values.
+
+    private static String myIP = "10.0.0.2";
+
+    private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
+
+    /**
+     * leaseTime - 10 mins or 600s.
+     * renewalTime - 5 mins or 300s.
+     * rebindingTime - 6 mins or 360s.
+     */
+
+    private static int leaseTime = 600;
+
+    private static int renewalTime = 300;
+
+    private static int rebindingTime = 360;
+
+    private static byte packetTTL = (byte) 127;
+
+    private static String subnetMask = "255.0.0.0";
+
+    private static String broadcastAddress = "10.255.255.255";
+
+    private static String routerAddress = "10.0.0.2";
+
+    private static String domainServer = "10.0.0.2";
+    private final HostProvider hostProvider = new InternalHostProvider();
+
+    @Activate
+    protected void activate() {
+        // start the dhcp server
+        appId = coreService.registerApplication("org.onosproject.dhcp");
+
+        cfgService.addListener(cfgListener);
+        factories.forEach(cfgService::registerConfigFactory);
+        hostProviderService = hostProviderRegistry.register(hostProvider);
+        packetService.addProcessor(processor, PacketProcessor.observer(1));
+        requestPackets();
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        cfgService.removeListener(cfgListener);
+        factories.forEach(cfgService::unregisterConfigFactory);
+        packetService.removeProcessor(processor);
+        hostProviderRegistry.unregister(hostProvider);
+        hostProviderService = null;
+        cancelPackets();
+        log.info("Stopped");
+    }
+
+    /**
+     * Request packet in via PacketService.
+     */
+    private void requestPackets() {
+
+        TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_UDP)
+                .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+                .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
+        packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+
+        selectorServer = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_ARP);
+        packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+    }
+
+    /**
+     * Cancel requested packets in via packet service.
+     */
+    private void cancelPackets() {
+        TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_UDP)
+                .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+                .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
+        packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+
+        selectorServer = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_ARP);
+        packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+    }
+
+    @Override
+    public Map<MacAddress, Ip4Address> listMapping() {
+
+        return dhcpStore.listMapping();
+    }
+
+    @Override
+    public int getLeaseTime() {
+        return leaseTime;
+    }
+
+    @Override
+    public int getRenewalTime() {
+        return renewalTime;
+    }
+
+    @Override
+    public int getRebindingTime() {
+        return rebindingTime;
+    }
+
+    @Override
+    public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
+        return dhcpStore.assignStaticIP(macID, ipAddress);
+    }
+
+    @Override
+    public boolean removeStaticMapping(MacAddress macID) {
+        return dhcpStore.removeStaticIP(macID);
+    }
+
+    @Override
+    public Iterable<Ip4Address> getAvailableIPs() {
+        return dhcpStore.getAvailableIPs();
+    }
+
+    private class DHCPPacketProcessor implements PacketProcessor {
+
+        /**
+         * Builds the DHCP Reply packet.
+         *
+         * @param packet the incoming Ethernet frame
+         * @param ipOffered the IP offered by the DHCP Server
+         * @param outgoingMessageType the message type of the outgoing packet
+         * @return the Ethernet reply frame
+         */
+        private Ethernet buildReply(Ethernet packet, String ipOffered, byte outgoingMessageType) {
+            Ip4Address myIPAddress = Ip4Address.valueOf(myIP);
+            Ip4Address ipAddress;
+
+            // Ethernet Frame.
+            Ethernet ethReply = new Ethernet();
+            ethReply.setSourceMACAddress(myMAC);
+            ethReply.setDestinationMACAddress(packet.getSourceMAC());
+            ethReply.setEtherType(Ethernet.TYPE_IPV4);
+            ethReply.setVlanID(packet.getVlanID());
+
+            // IP Packet
+            IPv4 ipv4Packet = (IPv4) packet.getPayload();
+            IPv4 ipv4Reply = new IPv4();
+            ipv4Reply.setSourceAddress(myIPAddress.toInt());
+            ipAddress = Ip4Address.valueOf(ipOffered);
+            ipv4Reply.setDestinationAddress(ipAddress.toInt());
+            ipv4Reply.setTtl(packetTTL);
+
+            // UDP Datagram.
+            UDP udpPacket = (UDP) ipv4Packet.getPayload();
+            UDP udpReply = new UDP();
+            udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
+            udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
+
+            // DHCP Payload.
+            DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
+            DHCP dhcpReply = new DHCP();
+            dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
+
+            ipAddress = Ip4Address.valueOf(ipOffered);
+            dhcpReply.setYourIPAddress(ipAddress.toInt());
+            dhcpReply.setServerIPAddress(myIPAddress.toInt());
+
+            dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
+            dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
+            dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
+            dhcpReply.setHardwareAddressLength((byte) 6);
+
+            // DHCP Options.
+            DHCPOption option = new DHCPOption();
+            List<DHCPOption> optionList = new ArrayList<>();
+
+            // DHCP Message Type.
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
+            option.setLength((byte) 1);
+            byte[] optionData = {outgoingMessageType};
+            option.setData(optionData);
+            optionList.add(option);
+
+            // DHCP Server Identifier.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
+            option.setLength((byte) 4);
+            option.setData(myIPAddress.toOctets());
+            optionList.add(option);
+
+            // IP Address Lease Time.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
+            option.setLength((byte) 4);
+            option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
+            optionList.add(option);
+
+            // IP Address Renewal Time.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
+            option.setLength((byte) 4);
+            option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
+            optionList.add(option);
+
+            // IP Address Rebinding Time.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
+            option.setLength((byte) 4);
+            option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
+            optionList.add(option);
+
+            // Subnet Mask.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
+            option.setLength((byte) 4);
+            ipAddress = Ip4Address.valueOf(subnetMask);
+            option.setData(ipAddress.toOctets());
+            optionList.add(option);
+
+            // Broadcast Address.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
+            option.setLength((byte) 4);
+            ipAddress = Ip4Address.valueOf(broadcastAddress);
+            option.setData(ipAddress.toOctets());
+            optionList.add(option);
+
+            // Router Address.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
+            option.setLength((byte) 4);
+            ipAddress = Ip4Address.valueOf(routerAddress);
+            option.setData(ipAddress.toOctets());
+            optionList.add(option);
+
+            // DNS Server Address.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
+            option.setLength((byte) 4);
+            ipAddress = Ip4Address.valueOf(domainServer);
+            option.setData(ipAddress.toOctets());
+            optionList.add(option);
+
+            // End Option.
+            option = new DHCPOption();
+            option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
+            option.setLength((byte) 1);
+            optionList.add(option);
+
+            dhcpReply.setOptions(optionList);
+
+            udpReply.setPayload(dhcpReply);
+            ipv4Reply.setPayload(udpReply);
+            ethReply.setPayload(ipv4Reply);
+
+            return ethReply;
+        }
+
+        /**
+         * Sends the Ethernet reply frame via the Packet Service.
+         *
+         * @param context the context of the incoming frame
+         * @param reply the Ethernet reply frame
+         */
+        private void sendReply(PacketContext context, Ethernet reply) {
+            if (reply != null) {
+                TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+                ConnectPoint sourcePoint = context.inPacket().receivedFrom();
+                builder.setOutput(sourcePoint.port());
+
+                packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
+                                    builder.build(), ByteBuffer.wrap(reply.serialize())));
+            }
+        }
+
+        /**
+         * Processes the DHCP Payload and initiates a reply to the client.
+         *
+         * @param context context of the incoming message
+         * @param dhcpPayload the extracted DHCP payload
+         */
+        private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
+
+            Ethernet packet = context.inPacket().parsed();
+            boolean flagIfRequestedIP = false;
+            boolean flagIfServerIP = false;
+            Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
+            Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
+
+            if (dhcpPayload != null) {
+
+                // TODO Convert this to enum value.
+                byte incomingPacketType = 0;
+                for (DHCPOption option : dhcpPayload.getOptions()) {
+                    if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
+                        byte[] data = option.getData();
+                        incomingPacketType = data[0];
+                    }
+                    if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
+                        byte[] data = option.getData();
+                        requestedIP = Ip4Address.valueOf(data);
+                        flagIfRequestedIP = true;
+                    }
+                    if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
+                        byte[] data = option.getData();
+                        serverIP = Ip4Address.valueOf(data);
+                        flagIfServerIP = true;
+                    }
+                }
+
+                String ipOffered = "";
+                DHCP.DHCPMessageType outgoingPacketType;
+                MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
+
+                if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Discover.getValue()) {
+
+                    outgoingPacketType = DHCP.DHCPMessageType.MessageType_Offer;
+                    ipOffered = dhcpStore.suggestIP(clientMAC, requestedIP).toString();
+
+                    Ethernet ethReply = buildReply(packet, ipOffered, outgoingPacketType.getValue());
+                    sendReply(context, ethReply);
+
+                } else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Request.getValue()) {
+
+                    outgoingPacketType = DHCP.DHCPMessageType.MessageType_ACK;
+
+                    if (flagIfServerIP && flagIfRequestedIP) {
+                        // SELECTING state
+                        if (myIP.equals(serverIP.toString()) &&
+                                dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
+
+                            Ethernet ethReply = buildReply(packet, requestedIP.toString(),
+                                    outgoingPacketType.getValue());
+                            sendReply(context, ethReply);
+                            discoverHost(context, requestedIP);
+                        }
+                    } else if (flagIfRequestedIP) {
+                        // INIT-REBOOT state
+                        if (dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
+                            Ethernet ethReply = buildReply(packet, requestedIP.toString(),
+                                    outgoingPacketType.getValue());
+                            sendReply(context, ethReply);
+                            discoverHost(context, requestedIP);
+                        }
+                    } else {
+                        // RENEWING and REBINDING state
+                        int ciaadr = dhcpPayload.getClientIPAddress();
+                        if (ciaadr != 0) {
+                            Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
+                            if (dhcpStore.assignIP(clientMAC, clientIaddr, leaseTime)) {
+                                Ethernet ethReply = buildReply(packet, clientIaddr.toString(),
+                                        outgoingPacketType.getValue());
+                                sendReply(context, ethReply);
+                                discoverHost(context, clientIaddr);
+                            }
+                        }
+                    }
+                } else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Release.getValue()) {
+
+                    dhcpStore.releaseIP(clientMAC);
+                }
+            }
+        }
+
+        /**
+         * Processes the ARP Payload and initiates a reply to the client.
+         *
+         * @param context context of the incoming message
+         * @param packet the ethernet payload
+         */
+        private void processARPPacket(PacketContext context, Ethernet packet) {
+
+            ARP arpPacket = (ARP) packet.getPayload();
+
+            ARP arpReply = (ARP) arpPacket.clone();
+            arpReply.setOpCode(ARP.OP_REPLY);
+
+            arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
+            arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
+            arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
+            arpReply.setSenderHardwareAddress(myMAC.toBytes());
+
+            // Ethernet Frame.
+            Ethernet ethReply = new Ethernet();
+            ethReply.setSourceMACAddress(myMAC);
+            ethReply.setDestinationMACAddress(packet.getSourceMAC());
+            ethReply.setEtherType(Ethernet.TYPE_ARP);
+            ethReply.setVlanID(packet.getVlanID());
+
+            ethReply.setPayload(arpReply);
+            sendReply(context, ethReply);
+        }
+
+        /**
+         * Integrates hosts learned through DHCP into topology.
+         * @param context context of the incoming message
+         * @param ipAssigned IP Address assigned to the host by DHCP Manager
+         */
+        private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
+            Ethernet packet = context.inPacket().parsed();
+            MacAddress mac = packet.getSourceMAC();
+            VlanId vlanId = VlanId.vlanId(packet.getVlanID());
+            HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
+
+            Set<IpAddress> ips = new HashSet<>();
+            ips.add(ipAssigned);
+
+            HostId hostId = HostId.hostId(mac, vlanId);
+            DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
+            hostProviderService.hostDetected(hostId, desc);
+        }
+
+
+        @Override
+        public void process(PacketContext context) {
+
+            Ethernet packet = context.inPacket().parsed();
+            if (packet == null) {
+                return;
+            }
+
+            if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
+                IPv4 ipv4Packet = (IPv4) packet.getPayload();
+
+                if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
+                    UDP udpPacket = (UDP) ipv4Packet.getPayload();
+
+                    if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
+                            udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
+                        // This is meant for the dhcp server so process the packet here.
+
+                        DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
+                        processDHCPPacket(context, dhcpPayload);
+                    }
+                }
+            } else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
+                ARP arpPacket = (ARP) packet.getPayload();
+
+                if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
+                        (Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()).toString().equals(myIP))) {
+
+                    processARPPacket(context, packet);
+
+                }
+            }
+        }
+    }
+
+    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.routerAddress() != null) {
+                routerAddress = cfg.routerAddress();
+            }
+            if (cfg.domainServer() != null) {
+                domainServer = cfg.domainServer();
+            }
+            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)) {
+                dhcpStore.populateIPPoolfromRange(Ip4Address.valueOf(cfg.startIP()),
+                                                    Ip4Address.valueOf(cfg.endIP()));
+            }
+        }
+
+        @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");
+                }
+            }
+        }
+    }
+
+    private class InternalHostProvider extends AbstractProvider implements HostProvider {
+
+        /**
+         * Creates a provider with the supplier identifier.
+         */
+        protected InternalHostProvider() {
+            super(PID);
+        }
+
+        @Override
+        public void triggerProbe(Host host) {
+            // nothing to do
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPStoreConfig.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DHCPStoreConfig.java
new file mode 100644
index 0000000..743450c
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/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.dhcp.impl;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.onosproject.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/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDHCPStore.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDHCPStore.java
new file mode 100644
index 0000000..a582892
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDHCPStore.java
@@ -0,0 +1,324 @@
+/*
+ * 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.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.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.Timer;
+import org.onosproject.dhcp.DHCPStore;
+import org.onosproject.dhcp.IPAssignment;
+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.concurrent.TimeUnit;
+
+/**
+ * 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<MacAddress, IPAssignment> allocationMap;
+
+    private DistributedSet<Ip4Address> freeIPPool;
+
+    private Timeout timeout;
+
+    private static Ip4Address startIPRange;
+
+    private static Ip4Address endIPRange;
+
+    // Hardcoded values are default values.
+
+    private static int timerDelay = 2;
+
+    private static int timeoutForPendingAssignments = 60;
+
+    @Activate
+    protected void activate() {
+        allocationMap = storageService.<MacAddress, 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();
+
+        timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        timeout.cancel();
+        log.info("Stopped");
+    }
+
+    @Override
+    public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
+
+        IPAssignment assignmentInfo;
+        if (allocationMap.containsKey(macID)) {
+            assignmentInfo = allocationMap.get(macID).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 ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
+                    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(macID, assignmentInfo);
+                        return ipAddr;
+                    }
+                }
+            }
+            return assignmentInfo.ipAddress();
+
+        } 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(macID, assignmentInfo);
+                    return requestedIP;
+                }
+            }
+        }
+
+        // Allocate a new IP from the server's pool of available IP.
+        Ip4Address nextIPAddr = fetchNextIP();
+        assignmentInfo = IPAssignment.builder()
+                                    .ipAddress(nextIPAddr)
+                                    .timestamp(new Date())
+                                    .leasePeriod(timeoutForPendingAssignments)
+                                    .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
+                                    .build();
+
+        allocationMap.put(macID, assignmentInfo);
+        return nextIPAddr;
+
+    }
+
+    @Override
+    public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
+
+        IPAssignment assignmentInfo;
+        if (allocationMap.containsKey(macID)) {
+            assignmentInfo = allocationMap.get(macID).value();
+            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();
+                allocationMap.put(macID, 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(macID, assignmentInfo);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void releaseIP(MacAddress macID) {
+        if (allocationMap.containsKey(macID)) {
+            IPAssignment newAssignment = IPAssignment.builder(allocationMap.get(macID).value())
+                                                    .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
+                                                    .build();
+            Ip4Address freeIP = newAssignment.ipAddress();
+            allocationMap.put(macID, newAssignment);
+            freeIPPool.add(freeIP);
+        }
+    }
+
+    @Override
+    public void setDefaultTimeoutForPurge(int timeInSeconds) {
+        timeoutForPendingAssignments = timeInSeconds;
+    }
+
+    @Override
+    public void setTimerDelay(int timeInSeconds) {
+        timerDelay = timeInSeconds;
+    }
+
+    @Override
+    public Map<MacAddress, Ip4Address> listMapping() {
+
+        Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
+        for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
+            IPAssignment assignment = entry.getValue().value();
+            if (assignment.assignmentStatus() == IPAssignment.AssignmentStatus.Option_Assigned) {
+                allMapping.put(entry.getKey(), assignment.ipAddress());
+            }
+        }
+
+        return allMapping;
+    }
+
+    @Override
+    public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
+        return assignIP(macID, ipAddr, -1);
+    }
+
+    @Override
+    public boolean removeStaticIP(MacAddress macID) {
+        if (allocationMap.containsKey(macID)) {
+            IPAssignment assignment = allocationMap.get(macID).value();
+            Ip4Address freeIP = assignment.ipAddress();
+            if (assignment.leasePeriod() < 0) {
+                allocationMap.remove(macID);
+                freeIPPool.add(freeIP);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Iterable<Ip4Address> getAvailableIPs() {
+        return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
+    }
+
+    @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++) {
+            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;
+    }
+
+    /**
+     * Purges the IP allocation map to remove expired entries and returns the freed IPs to the free pool.
+     */
+    private class PurgeListTask implements TimerTask {
+
+        @Override
+        public void run(Timeout to) {
+            IPAssignment ipAssignment, newAssignment;
+            Date dateNow = new Date();
+            for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
+                ipAssignment = entry.getValue().value();
+                long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
+                if ((ipAssignment.assignmentStatus() != IPAssignment.AssignmentStatus.Option_Expired) &&
+                        (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
+                    Ip4Address freeIP = ipAssignment.ipAddress();
+
+                    newAssignment = IPAssignment.builder(ipAssignment)
+                            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
+                            .build();
+                    allocationMap.put(entry.getKey(), newAssignment);
+
+                    if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
+                        freeIPPool.add(freeIP);
+                    }
+                }
+            }
+            timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
+        }
+
+    }
+
+}
diff --git a/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java
new file mode 100644
index 0000000..fad6f9d
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java
@@ -0,0 +1,160 @@
+/*
+ * 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.rest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.dhcp.DHCPService;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Manage DHCP address assignments.
+ */
+@Path("dhcp")
+public class DHCPWebResource extends AbstractWebResource {
+
+    final DHCPService service = get(DHCPService.class);
+
+    /**
+     * Get DHCP server configuration data.
+     * Shows lease, renewal and rebinding times in seconds.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("config")
+    public Response getConfigs() {
+        DHCPService service = get(DHCPService.class);
+        ObjectNode node = mapper().createObjectNode()
+                .put("leaseTime", service.getLeaseTime())
+                .put("renewalTime", service.getRenewalTime())
+                .put("rebindingTime", service.getRebindingTime());
+        return ok(node.toString()).build();
+    }
+
+    /**
+     * Get all MAC/IP mappings.
+     * Shows all MAC/IP mappings held by the DHCP server.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("mappings")
+    public Response listMappings() {
+        ObjectNode root = mapper().createObjectNode();
+
+        final Map<MacAddress, Ip4Address> intents = service.listMapping();
+        ArrayNode arrayNode = root.putArray("mappings");
+        intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
+                .put("mac", i.getKey().toString())
+                .put("ip", i.getValue().toString())));
+
+        return ok(root.toString()).build();
+    }
+
+
+
+    /**
+     * Get all available IPs.
+     * Shows all the IPs in the free pool of the DHCP Server.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("available")
+    public Response listAvailableIPs() {
+        final Iterable<Ip4Address> availableIPList = service.getAvailableIPs();
+
+        final ObjectNode root = mapper().createObjectNode();
+        ArrayNode arrayNode = root.putArray("availableIP");
+        availableIPList.forEach(i -> arrayNode.add(i.toString()));
+        return ok(root.toString()).build();
+    }
+
+    /**
+     * Post a new static MAC/IP binding.
+     * Registers a static binding to the DHCP server, and displays the current set of bindings.
+     *
+     * @return 200 OK
+     */
+    @POST
+    @Path("mappings")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response setMapping(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode macID = jsonTree.get("mac");
+            JsonNode ip = jsonTree.get("ip");
+            if (macID != null && ip != null) {
+
+                if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()),
+                        Ip4Address.valueOf(ip.asText()))) {
+                    throw new IllegalArgumentException("Static Mapping Failed. The IP maybe unavailable.");
+                }
+            }
+
+            final Map<MacAddress, Ip4Address> intents = service.listMapping();
+            ArrayNode arrayNode = root.putArray("mappings");
+            intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
+                    .put("mac", i.getKey().toString())
+                    .put("ip", i.getValue().toString())));
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root.toString()).build();
+    }
+
+    /**
+     * Delete a static MAC/IP binding.
+     * Removes a static binding from the DHCP Server, and displays the current set of bindings.
+     *
+     * @return 200 OK
+     */
+    @DELETE
+    @Path("mappings/{macID}")
+    public Response deleteMapping(@PathParam("macID") String macID) {
+
+        ObjectNode root = mapper().createObjectNode();
+
+        if (!service.removeStaticMapping(MacAddress.valueOf(macID))) {
+            throw new IllegalArgumentException("Static Mapping Removal Failed.");
+        }
+        final Map<MacAddress, Ip4Address> intents = service.listMapping();
+        ArrayNode arrayNode = root.putArray("mappings");
+        intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
+                .put("mac", i.getKey().toString())
+                .put("ip", i.getValue().toString())));
+
+        return ok(root.toString()).build();
+    }
+}
diff --git a/apps/onos-app-dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/onos-app-dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..cd3c501
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ 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.
+  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.dhcp.cli.DHCPListAllMappings"/>
+        </command>
+        <command>
+            <action class="org.onosproject.dhcp.cli.DHCPLeaseDetails"/>
+        </command>
+        <command>
+            <action class="org.onosproject.dhcp.cli.DHCPSetStaticMapping"/>
+            <completers>
+                <ref component-id="macIDCompleter"/>
+                <ref component-id="freeIPCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.dhcp.cli.DHCPRemoveStaticMapping"/>
+            <completers>
+                <ref component-id="macIDCompleter"/>
+            </completers>
+        </command>
+    </command-bundle>
+
+    <bean id="macIDCompleter" class="org.onosproject.dhcp.cli.MacIdCompleter"/>
+    <bean id="freeIPCompleter" class="org.onosproject.dhcp.cli.FreeIPCompleter"/>
+
+</blueprint>
\ No newline at end of file
diff --git a/apps/onos-app-dhcp/src/main/webapp/WEB-INF/web.xml b/apps/onos-app-dhcp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..2750454
--- /dev/null
+++ b/apps/onos-app-dhcp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>DHCP Server REST API v1.0</display-name>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+        </init-param>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.classnames</param-name>
+            <param-value>
+                org.onosproject.dhcp.rest.DHCPWebResource
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java
new file mode 100644
index 0000000..0783ec7
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/IPAssignmentTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.dhcp;
+
+import com.google.common.testing.EqualsTester;
+import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Date;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit Tests for IPAssignment class.
+ */
+public class IPAssignmentTest extends TestCase {
+
+    private final Date dateNow = new Date();
+
+    private final IPAssignment stats1 = IPAssignment.builder()
+            .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+            .leasePeriod(300)
+            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
+            .timestamp(dateNow)
+            .build();
+
+    private final IPAssignment stats2 = IPAssignment.builder()
+            .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+            .leasePeriod(300)
+            .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
+            .timestamp(dateNow)
+            .build();
+
+    private final IPAssignment stats3 = IPAssignment.builder(stats1)
+            .build();
+
+    /**
+     *  Tests the constructor for the class.
+     */
+    @Test
+    public void testConstruction() {
+        assertThat(stats3.ipAddress(), is(Ip4Address.valueOf("10.10.10.10")));
+        assertThat(stats3.timestamp(), is(dateNow));
+        assertThat(stats3.leasePeriod(), is(300));
+        assertThat(stats3.assignmentStatus(), is(IPAssignment.AssignmentStatus.Option_Expired));
+    }
+
+    /**
+     * Tests the equality and inequality of objects using Guava EqualsTester.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(stats1, stats1)
+                .addEqualityGroup(stats2)
+                .testEquals();
+    }
+
+    /**
+     * Tests if the toString method returns a consistent value for hashing.
+     */
+    @Test
+    public void testToString() {
+        assertThat(stats1.toString(), is(stats1.toString()));
+    }
+
+    /**
+     * Tests if the validateInputs method returns an exception for malformed object.
+     */
+    @Test
+    public void testValidateInputs() {
+        try {
+            IPAssignment stats4 = IPAssignment.builder()
+                    .ipAddress(Ip4Address.valueOf("10.10.10.10"))
+                    .leasePeriod(300)
+                    .build();
+
+            fail("Construction of a malformed IPAssignment did not throw an exception");
+        } catch (NullPointerException e) {
+            Assert.assertThat(e.getMessage(), containsString("must be specified"));
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java
new file mode 100644
index 0000000..3eda1bc
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/java/org/onosproject/dhcp/impl/DHCPManagerTest.java
@@ -0,0 +1,374 @@
+/*
+ * 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.dhcp.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.DHCPOption;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.UDP;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.dhcp.DHCPStore;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.packet.DefaultInboundPacket;
+import org.onosproject.net.packet.DefaultPacketContext;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+/**
+ * Set of tests of the ONOS application component.
+ */
+
+public class DHCPManagerTest {
+
+    private DHCPManager dhcpManager;
+
+    protected PacketProcessor packetProcessor;
+
+    protected HostProviderService hostProviderService;
+
+    private static final MacAddress CLIENT1_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
+
+    private static final String EXPECTED_IP = "10.2.0.2";
+
+    private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255");
+
+    private static final int TRANSACTION_ID = 1000;
+
+    private static final ProviderId PID = new ProviderId("of", "foo");
+
+    @Before
+    public void setUp() {
+        dhcpManager = new DHCPManager();
+        dhcpManager.cfgService = new TestNetworkConfigRegistry();
+        dhcpManager.packetService = new TestPacketService();
+        dhcpManager.coreService = new TestCoreService();
+        dhcpManager.dhcpStore = new TestDHCPStore();
+        hostProviderService = new TestHostProviderService(new TestHostProvider());
+        dhcpManager.hostProviderService = hostProviderService;
+        dhcpManager.hostProviderRegistry = new TestHostRegistry();
+        dhcpManager.activate();
+    }
+
+    @After
+    public void tearDown() {
+        dhcpManager.deactivate();
+    }
+
+    /**
+     * Tests the response to a DHCP Discover Packet.
+     */
+    @Test
+    public void testDiscover() {
+        Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Discover);
+        sendPacket(reply);
+    }
+
+    /**
+     * Tests the response to a DHCP Request Packet.
+     */
+    @Test
+    public void testRequest() {
+        Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Request);
+        sendPacket(reply);
+    }
+
+    /**
+     * Sends an Ethernet packet to the process method of the Packet Processor.
+     * @param reply Ethernet packet
+     */
+    private void sendPacket(Ethernet reply) {
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize());
+        InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
+                reply,
+                byteBuffer);
+
+        PacketContext context = new TestPacketContext(127L, inPacket, null, false);
+        packetProcessor.process(context);
+    }
+
+    /**
+     * Constructs an Ethernet packet containing a DHCP Payload.
+     * @param messageType DHCP Message Type
+     * @return Ethernet packet
+     */
+    private Ethernet constructDHCPPacket(DHCP.DHCPMessageType messageType) {
+
+        // Ethernet Frame.
+        Ethernet ethReply = new Ethernet();
+        ethReply.setSourceMACAddress(CLIENT1_MAC);
+        ethReply.setDestinationMACAddress(MacAddress.BROADCAST);
+        ethReply.setEtherType(Ethernet.TYPE_IPV4);
+        ethReply.setVlanID((short) 2);
+
+        // IP Packet
+        IPv4 ipv4Reply = new IPv4();
+        ipv4Reply.setSourceAddress(0);
+        ipv4Reply.setDestinationAddress(BROADCAST.toInt());
+        ipv4Reply.setTtl((byte) 127);
+
+        // UDP Datagram.
+        UDP udpReply = new UDP();
+        udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
+        udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
+
+        // DHCP Payload.
+        DHCP dhcpReply = new DHCP();
+        dhcpReply.setOpCode(DHCP.OPCODE_REQUEST);
+
+        dhcpReply.setYourIPAddress(0);
+        dhcpReply.setServerIPAddress(0);
+
+        dhcpReply.setTransactionId(TRANSACTION_ID);
+        dhcpReply.setClientHardwareAddress(CLIENT1_MAC.toBytes());
+        dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
+        dhcpReply.setHardwareAddressLength((byte) 6);
+
+        // DHCP Options.
+        DHCPOption option = new DHCPOption();
+        List<DHCPOption> optionList = new ArrayList<>();
+
+        // DHCP Message Type.
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
+        option.setLength((byte) 1);
+        byte[] optionData = {messageType.getValue()};
+        option.setData(optionData);
+        optionList.add(option);
+
+        // DHCP Requested IP.
+        option = new DHCPOption();
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
+        option.setLength((byte) 4);
+        optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
+        option.setData(optionData);
+        optionList.add(option);
+
+        // End Option.
+        option = new DHCPOption();
+        option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
+        option.setLength((byte) 1);
+        optionList.add(option);
+
+        dhcpReply.setOptions(optionList);
+
+        udpReply.setPayload(dhcpReply);
+        ipv4Reply.setPayload(udpReply);
+        ethReply.setPayload(ipv4Reply);
+
+        return ethReply;
+    }
+
+    /**
+     * Validates the contents of the packet sent by the DHCP Manager.
+     * @param packet Ethernet packet received
+     */
+    private void validatePacket(Ethernet packet) {
+        DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload();
+        assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_MAC);
+        assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP));
+        assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID);
+    }
+
+    /**
+     * Mocks the DHCPStore.
+     */
+    private final class TestDHCPStore implements DHCPStore {
+
+
+        public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
+        }
+
+        public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
+            return Ip4Address.valueOf(EXPECTED_IP);
+        }
+
+        public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
+            return true;
+        }
+
+        public void setDefaultTimeoutForPurge(int timeInSeconds) {
+        }
+
+        public void setTimerDelay(int timeInSeconds) {
+        }
+
+        public void releaseIP(MacAddress macID) {
+        }
+
+        public Map<MacAddress, Ip4Address> listMapping() {
+            Map<MacAddress, Ip4Address> map = new HashMap<>();
+            map.put(CLIENT1_MAC, Ip4Address.valueOf(EXPECTED_IP));
+            return map;
+        }
+
+        public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
+            return true;
+        }
+
+        public boolean removeStaticIP(MacAddress macID) {
+            return true;
+        }
+
+        public Iterable<Ip4Address> getAvailableIPs() {
+            List<Ip4Address> ipList = new ArrayList<>();
+            ipList.add(Ip4Address.valueOf(EXPECTED_IP));
+            return ImmutableSet.copyOf(ipList);
+        }
+    }
+
+    /**
+     * Mocks the DefaultPacket context.
+     */
+    private final class TestPacketContext extends DefaultPacketContext {
+        private TestPacketContext(long time, InboundPacket inPkt,
+                                    OutboundPacket outPkt, boolean block) {
+            super(time, inPkt, outPkt, block);
+        }
+
+        @Override
+        public void send() {
+            // We don't send anything out.
+        }
+    }
+
+    /**
+     * Keeps a reference to the PacketProcessor and verifies the OutboundPackets.
+     */
+    private class TestPacketService extends PacketServiceAdapter {
+
+        @Override
+        public void addProcessor(PacketProcessor processor, int priority) {
+            packetProcessor = processor;
+        }
+
+        @Override
+        public void emit(OutboundPacket packet) {
+            try {
+                Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
+                        0, packet.data().array().length);
+                validatePacket(eth);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Mocks the CoreService.
+     */
+    private class TestCoreService extends CoreServiceAdapter {
+
+    }
+
+    /**
+     * Mocks the NetworkConfigRegistry.
+     */
+    private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
+
+    }
+
+    /**
+     * Mocks the HostProviderService.
+     */
+    private class TestHostProviderService extends AbstractProviderService<HostProvider>
+            implements HostProviderService {
+
+        protected TestHostProviderService(HostProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void hostDetected(HostId hostId, HostDescription hostDescription) {
+        }
+
+        @Override
+        public void hostVanished(HostId hostId) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProvider.
+     */
+    private static class TestHostProvider extends AbstractProvider
+            implements HostProvider {
+
+        protected TestHostProvider() {
+            super(PID);
+        }
+
+        @Override
+        public ProviderId id() {
+            return PID;
+        }
+
+        @Override
+        public void triggerProbe(Host host) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProviderRegistry.
+     */
+    private class TestHostRegistry implements HostProviderRegistry {
+
+        @Override
+        public HostProviderService register(HostProvider provider) {
+            return hostProviderService;
+        }
+
+        @Override
+        public void unregister(HostProvider provider) {
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+
+    }
+
+}
diff --git a/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json b/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json
new file mode 100644
index 0000000..8ce5486
--- /dev/null
+++ b/apps/onos-app-dhcp/src/test/resources/dhcp-cfg.json
@@ -0,0 +1,24 @@
+{
+  "apps": {
+    "org.onosproject.dhcp" : {
+      "dhcp" : {
+        "ip": "10.0.0.1",
+        "mac": "1a:2b:3c:4e:5e:6f",
+        "subnet": "255.0.0.0",
+        "broadcast": "10.255.255.255",
+        "router": "10.0.0.1",
+        "domain": "10.0.0.1",
+        "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
diff --git a/apps/pom.xml b/apps/pom.xml
index 3e34a42..3cbc905 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -57,6 +57,7 @@
         <module>vtnrsc</module>
         <module>vtn</module>
         <module>vtnweb</module>
+        <module>onos-app-dhcp</module>
     </modules>
 
     <properties>