aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/dhcp
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/dhcp')
-rw-r--r--framework/src/onos/apps/dhcp/pom.xml161
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java80
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java107
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java206
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java41
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java44
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java56
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java61
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java48
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java48
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java227
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java669
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpStoreConfig.java107
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java74
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java96
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java324
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java163
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml43
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css27
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html47
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js51
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/gui/css.html1
-rw-r--r--framework/src/onos/apps/dhcp/src/main/resources/gui/js.html1
-rw-r--r--framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml43
-rw-r--r--framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java101
-rw-r--r--framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java383
-rw-r--r--framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json24
27 files changed, 3233 insertions, 0 deletions
diff --git a/framework/src/onos/apps/dhcp/pom.xml b/framework/src/onos/apps/dhcp/pom.xml
new file mode 100644
index 00000000..13298163
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java
new file mode 100644
index 00000000..20e1c614
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+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, IpAssignment> 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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java
new file mode 100644
index 00000000..4e2d67d6
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+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
+ * @param requestedIP requested IP address
+ * @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, IpAssignment> 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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java
new file mode 100644
index 00000000..c8bd1906
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ *
+ * @param assignment ip address assignment
+ * @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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java
new file mode 100644
index 00000000..95f49e69
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java
new file mode 100644
index 00000000..fc470ce3
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java
@@ -0,0 +1,44 @@
+/*
+ * 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.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DhcpService;
+import org.onosproject.dhcp.IpAssignment;
+
+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, IpAssignment> allocationMap = dhcpService.listMapping();
+
+ for (Map.Entry<MacAddress, IpAssignment> entry : allocationMap.entrySet()) {
+ print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().ipAddress().toString());
+ }
+ }
+}
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java
new file mode 100644
index 00000000..a92cd250
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java
new file mode 100644
index 00000000..9f4f6580
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java
new file mode 100644
index 00000000..228d70fd
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java
new file mode 100644
index 00000000..d6cd73a7
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java
new file mode 100644
index 00000000..f8d5e63b
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
new file mode 100644
index 00000000..24cb0878
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
@@ -0,0 +1,669 @@
+/*
+ * 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.DHCPPacketType;
+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.dhcp.IpAssignment;
+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, IpAssignment> 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 = "";
+ DHCPPacketType outgoingPacketType;
+ MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
+
+ if (incomingPacketType == DHCPPacketType.DHCPDISCOVER.getValue()) {
+
+ outgoingPacketType = DHCPPacketType.DHCPOFFER;
+ ipOffered = dhcpStore.suggestIP(clientMAC, requestedIP).toString();
+
+ Ethernet ethReply = buildReply(packet, ipOffered, (byte) outgoingPacketType.getValue());
+ sendReply(context, ethReply);
+
+ } else if (incomingPacketType == DHCPPacketType.DHCPREQUEST.getValue()) {
+
+ outgoingPacketType = DHCPPacketType.DHCPACK;
+
+ if (flagIfServerIP && flagIfRequestedIP) {
+ // SELECTING state
+ if (myIP.equals(serverIP.toString()) &&
+ dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
+
+ Ethernet ethReply = buildReply(packet, requestedIP.toString(),
+ (byte) 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(),
+ (byte) 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(),
+ (byte) outgoingPacketType.getValue());
+ sendReply(context, ethReply);
+ discoverHost(context, clientIaddr);
+ }
+ }
+ }
+ } else if (incomingPacketType == DHCPPacketType.DHCPRELEASE.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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpStoreConfig.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpStoreConfig.java
new file mode 100644
index 00000000..0059e7e5
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java
new file mode 100644
index 00000000..bb2bd2c2
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.dhcp.impl;
+
+import com.google.common.collect.ImmutableList;
+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.onosproject.ui.UiExtension;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiView;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import static org.onosproject.ui.UiView.Category.NETWORK;
+
+/**
+ * Mechanism to stream data to the GUI.
+ */
+@Component(immediate = true, enabled = true)
+@Service(value = DhcpUi.class)
+public class DhcpUi {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final ClassLoader CL = DhcpUi.class.getClassLoader();
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected UiExtensionService uiExtensionService;
+
+ private final UiMessageHandlerFactory messageHandlerFactory =
+ () -> ImmutableList.of(new DhcpViewMessageHandler());
+
+ private final List<UiView> views = ImmutableList.of(
+ new UiView(NETWORK, "dhcp", "DHCP Server")
+ );
+
+ private final UiExtension uiExtension =
+ new UiExtension.Builder(CL, views)
+ .messageHandlerFactory(messageHandlerFactory)
+ .resourcePath("gui")
+ .build();
+
+ @Activate
+ protected void activate() {
+ uiExtensionService.register(uiExtension);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ uiExtensionService.unregister(uiExtension);
+ log.info("Stopped");
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java
new file mode 100644
index 00000000..89ed5720
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.dhcp.impl;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.dhcp.DhcpService;
+import org.onosproject.dhcp.IpAssignment;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.table.TableModel;
+import org.onosproject.ui.table.TableRequestHandler;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * DHCPViewMessageHandler class implementation.
+ */
+public class DhcpViewMessageHandler extends UiMessageHandler {
+
+ private static final String DHCP_DATA_REQ = "dhcpDataRequest";
+ private static final String DHCP_DATA_RESP = "dhcpDataResponse";
+ private static final String DHCP = "dhcps";
+
+ private static final String MAC = "mac";
+ private static final String IP = "ip";
+ private static final String LEASE = "lease";
+
+ private static final String[] COL_IDS = {
+ MAC, IP, LEASE
+ };
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new DataRequestHandler()
+ );
+ }
+
+ private final class DataRequestHandler extends TableRequestHandler {
+
+ private DataRequestHandler() {
+ super(DHCP_DATA_REQ, DHCP_DATA_RESP, DHCP);
+ }
+
+ @Override
+ protected String defaultColumnId() {
+ return MAC;
+ }
+
+ @Override
+ protected String[] getColumnIds() {
+ return COL_IDS;
+ }
+
+ @Override
+ protected void populateTable(TableModel tm, ObjectNode payload) {
+ DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class);
+ Map<MacAddress, IpAssignment> allocationMap = dhcpService.listMapping();
+
+ for (Map.Entry<MacAddress, IpAssignment> entry : allocationMap.entrySet()) {
+ populateRow(tm.addRow(), entry);
+ }
+ }
+
+ private void populateRow(TableModel.Row row, Map.Entry<MacAddress, IpAssignment> entry) {
+ if (entry.getValue().leasePeriod() > 0) {
+ Date now = new Date(entry.getValue().timestamp().getTime() + entry.getValue().leasePeriod());
+ row.cell(MAC, entry.getKey())
+ .cell(IP, entry.getValue().ipAddress())
+ .cell(LEASE, now.toString());
+ } else {
+ row.cell(MAC, entry.getKey())
+ .cell(IP, entry.getValue().ipAddress())
+ .cell(LEASE, "Infinite Static Lease");
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java
new file mode 100644
index 00000000..6e29216a
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.dhcp.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.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, IpAssignment> listMapping() {
+
+ Map<MacAddress, IpAssignment> 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);
+ }
+ }
+ 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/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java
new file mode 100644
index 00000000..bfa2767d
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java
@@ -0,0 +1,163 @@
+/*
+ * 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.dhcp.IpAssignment;
+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, IpAssignment> 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().ipAddress().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.
+ *
+ * @param stream JSON stream
+ * @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, IpAssignment> 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().ipAddress().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.
+ *
+ * @param macID mac address identifier
+ * @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, IpAssignment> 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().ipAddress().toString())));
+
+ return ok(root.toString()).build();
+ }
+}
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..ce716315
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css
new file mode 100644
index 00000000..e0a29314
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- DHCP Server -- CSS file
+ */
+
+#ov-dhcp h2 {
+ display: inline-block;
+}
+
+#ov-dhcp div.ctrl-btns {
+ width: 45px;
+}
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html
new file mode 100644
index 00000000..3e14570a
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html
@@ -0,0 +1,47 @@
+<!-- DHCP Server partial HTML -->
+<div id="ov-dhcp">
+ <div class="tabular-header">
+ <h2>DHCP Mappings ({{tableData.length}} total)</h2>
+ <div class="ctrl-btns">
+ <div class="refresh" ng-class="{active: autoRefresh}"
+ icon icon-size="36" icon-id="refresh"
+ tooltip tt-msg="autoRefreshTip"
+ ng-click="toggleRefresh()"></div>
+ </div>
+ </div>
+
+ <div class="summary-list" onos-table-resize>
+ <div ng-show="loading" class="loading-wheel"
+ icon icon-id="loading" icon-size="75"></div>
+
+ <div class="table-header" onos-sortable-header>
+ <table>
+ <tr>
+ <td colId="mac" sortable>MAC Address</td>
+ <td colId="ip" sortable>IP Address</td>
+ <td colId="lease" sortable>Lease Expiry</td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="table-body">
+ <table onos-flash-changes id-prop="mac">
+ <tr ng-if="!tableData.length" class="no-data">
+ <td colspan="2">
+ No mappings found
+ </td>
+ </tr>
+
+ <tr ng-repeat="dhcp in tableData track by $index"
+ ng-click="selectCallback($event, dhcp)"
+ ng-repeat-complete row-id="{{dhcp.mac}}">
+ <td>{{dhcp.mac}}</td>
+ <td>{{dhcp.ip}}</td>
+ <td>{{dhcp.lease}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
+</div>
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js
new file mode 100644
index 00000000..061d0de6
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- DHCP Server View Module
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $scope;
+
+ angular.module('ovDhcp', [])
+ .controller('OvDhcpCtrl',
+ ['$log', '$scope', 'TableBuilderService',
+
+ function (_$log_, _$scope_, tbs) {
+ $log = _$log_;
+ $scope = _$scope_;
+
+ function selCb($event, row) {
+ $log.debug('Got a click on:', row);
+ }
+
+ tbs.buildTable({
+ scope: $scope,
+ tag: 'dhcp',
+ selCb: selCb
+ });
+
+ $scope.$on('$destroy', function () {
+ $log.debug('OvDhcpCtrl has been destroyed');
+ });
+
+ $log.log('OvDhcpCtrl has been created');
+ }]);
+}()); \ No newline at end of file
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html b/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html
new file mode 100644
index 00000000..d02ad44a
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/dhcp/dhcp.css"> \ No newline at end of file
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html b/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html
new file mode 100644
index 00000000..d37b5768
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html
@@ -0,0 +1 @@
+<script src="app/view/dhcp/dhcp.js"></script> \ No newline at end of file
diff --git a/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..27504548
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java
new file mode 100644
index 00000000..dad5ef55
--- /dev/null
+++ b/framework/src/onos/apps/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/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
new file mode 100644
index 00000000..42ac73d3
--- /dev/null
+++ b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.dhcp.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.DHCPOption;
+import org.onlab.packet.DHCPPacketType;
+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.dhcp.IpAssignment;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+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.Date;
+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 dhcpXManager;
+
+ 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() {
+ dhcpXManager = new DhcpManager();
+ dhcpXManager.cfgService = new TestNetworkConfigRegistry();
+ dhcpXManager.packetService = new TestPacketService();
+ dhcpXManager.coreService = new TestCoreService();
+ dhcpXManager.dhcpStore = new TestDhcpStore();
+ hostProviderService = new TestHostProviderService(new TestHostProvider());
+ dhcpXManager.hostProviderService = hostProviderService;
+ dhcpXManager.hostProviderRegistry = new TestHostRegistry();
+ dhcpXManager.activate();
+ }
+
+ @After
+ public void tearDown() {
+ dhcpXManager.deactivate();
+ }
+
+ /**
+ * Tests the response to a DHCP Discover Packet.
+ */
+ @Test
+ public void testDiscover() {
+ Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPDISCOVER);
+ sendPacket(reply);
+ }
+
+ /**
+ * Tests the response to a DHCP Request Packet.
+ */
+ @Test
+ public void testRequest() {
+ Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPREQUEST);
+ 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 packetType DHCP Message Type
+ * @return Ethernet packet
+ */
+ private Ethernet constructDHCPPacket(DHCPPacketType packetType) {
+
+ // 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 = {(byte) packetType.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, IpAssignment> listMapping() {
+ Map<MacAddress, IpAssignment> map = new HashMap<>();
+ IpAssignment assignment = IpAssignment.builder()
+ .ipAddress(Ip4Address.valueOf(EXPECTED_IP))
+ .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
+ .leasePeriod(300)
+ .timestamp(new Date())
+ .build();
+ map.put(CLIENT1_MAC, assignment);
+ 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/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json b/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json
new file mode 100644
index 00000000..8ce5486f
--- /dev/null
+++ b/framework/src/onos/apps/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