samanwita pal
Committed by Gerrit Code Review

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

Change-Id: Id52781ba93d48ad1d56097a9ceff7613a190c48e
Showing 21 changed files with 2922 additions and 0 deletions
<?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>
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import java.util.Map;
/**
* DHCP Service Interface.
*/
public interface DHCPService {
/**
* Returns a collection of all the MacAddress to IPAddress mapping.
*
* @return collection of mappings.
*/
Map<MacAddress, Ip4Address> listMapping();
/**
* Returns the default lease time granted by the DHCP Server.
*
* @return lease time
*/
int getLeaseTime();
/**
* Returns the default renewal time granted by the DHCP Server.
*
* @return renewal time
*/
int getRenewalTime();
/**
* Returns the default rebinding time granted by the DHCP Server.
*
* @return rebinding time
*/
int getRebindingTime();
/**
* Registers a static IP mapping with the DHCP Server.
*
* @param macID macID of the client
* @param ipAddress IP Address requested for the client
* @return true if the mapping was successfully registered, false otherwise
*/
boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress);
/**
* Removes a static IP mapping with the DHCP Server.
*
* @param macID macID of the client
* @return true if the mapping was successfully removed, false otherwise
*/
boolean removeStaticMapping(MacAddress macID);
/**
* Returns the list of all the available IPs with the server.
*
* @return list of available IPs
*/
Iterable<Ip4Address> getAvailableIPs();
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import java.util.Map;
/**
* DHCPStore Interface.
*/
public interface DHCPStore {
/**
* Appends all the IPs in a given range to the free pool of IPs.
*
* @param startIP Start IP for the range
* @param endIP End IP for the range
*/
void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP);
/**
* Returns an IP Address for a Mac ID, in response to a DHCP DISCOVER message.
*
* @param macID Mac ID of the client requesting an IP
* @return IP address assigned to the Mac ID
*/
Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP);
/**
* Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message.
*
* @param macID Mac Id of the client requesting an IP
* @param ipAddr IP Address being requested
* @param leaseTime Lease time offered by the server for this mapping
* @return returns true if the assignment was successful, false otherwise
*/
boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime);
/**
* Sets the default time for which suggested IP mappings are valid.
*
* @param timeInSeconds default time for IP mappings to be valid
*/
void setDefaultTimeoutForPurge(int timeInSeconds);
/**
* Sets the delay after which the dhcp server will purge expired entries.
*
* @param timeInSeconds default time
*/
void setTimerDelay(int timeInSeconds);
/**
* Releases the IP assigned to a Mac ID into the free pool.
*
* @param macID the macID for which the mapping needs to be changed
*/
void releaseIP(MacAddress macID);
/**
* Returns a collection of all the MacAddress to IPAddress mapping.
*
* @return the collection of the mappings
*/
Map<MacAddress, Ip4Address> listMapping();
/**
* Assigns the requested IP to the MAC ID (if available) for an indefinite period of time.
*
* @param macID macID of the client
* @param ipAddr IP Address requested for the client
* @return true if the mapping was successfully registered, false otherwise
*/
boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr);
/**
* Removes a static IP mapping associated with the given MAC ID from the DHCP Server.
*
* @param macID macID of the client
* @return true if the mapping was successfully registered, false otherwise
*/
boolean removeStaticIP(MacAddress macID);
/**
* Returns the list of all the available IPs with the server.
*
* @return list of available IPs
*/
Iterable<Ip4Address> getAvailableIPs();
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp;
import com.google.common.base.MoreObjects;
import org.onlab.packet.Ip4Address;
import java.util.Date;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores the MAC ID to IP Address mapping details.
*/
public final class IPAssignment {
private final Ip4Address ipAddress;
private final Date timestamp;
private final long leasePeriod;
private final AssignmentStatus assignmentStatus;
public enum AssignmentStatus {
/**
* IP has been requested by a host, but not assigned to it yet.
*/
Option_Requested,
/**
* IP has been assigned to a host.
*/
Option_Assigned,
/**
* IP mapping is no longer active.
*/
Option_Expired;
}
/**
* Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp
* and assignment status is supplied.
*
* @param ipAddress
* @param leasePeriod
* @param assignmentStatus
*/
private IPAssignment(Ip4Address ipAddress,
long leasePeriod,
Date timestamp,
AssignmentStatus assignmentStatus) {
this.ipAddress = ipAddress;
this.leasePeriod = leasePeriod;
this.timestamp = timestamp;
this.assignmentStatus = assignmentStatus;
}
/**
* Returns the IP Address of the IP assignment.
*
* @return the IP address
*/
public Ip4Address ipAddress() {
return this.ipAddress;
}
/**
* Returns the timestamp of the IP assignment.
*
* @return the timestamp
*/
public Date timestamp() {
return this.timestamp;
}
/**
* Returns the assignment status of the IP assignment.
*
* @return the assignment status
*/
public AssignmentStatus assignmentStatus() {
return this.assignmentStatus;
}
/**
* Returns the lease period of the IP assignment.
*
* @return the lease period
*/
public int leasePeriod() {
return (int) this.leasePeriod / 1000;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("ip", ipAddress)
.add("timestamp", timestamp)
.add("lease", leasePeriod)
.add("assignmentStatus", assignmentStatus)
.toString();
}
/**
* Creates and returns a new builder instance.
*
* @return new builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Creates and returns a new builder instance that clones an existing IPAssignment.
*
* @return new builder
*/
public static Builder builder(IPAssignment assignment) {
return new Builder(assignment);
}
/**
* IPAssignment Builder.
*/
public static final class Builder {
private Ip4Address ipAddress;
private Date timeStamp;
private long leasePeriod;
private AssignmentStatus assignmentStatus;
private Builder() {
}
private Builder(IPAssignment ipAssignment) {
ipAddress = ipAssignment.ipAddress();
timeStamp = ipAssignment.timestamp();
leasePeriod = ipAssignment.leasePeriod() * 1000;
assignmentStatus = ipAssignment.assignmentStatus();
}
public IPAssignment build() {
validateInputs();
return new IPAssignment(ipAddress,
leasePeriod,
timeStamp,
assignmentStatus);
}
public Builder ipAddress(Ip4Address addr) {
ipAddress = addr;
return this;
}
public Builder timestamp(Date timestamp) {
timeStamp = timestamp;
return this;
}
public Builder leasePeriod(int leasePeriodinSeconds) {
leasePeriod = leasePeriodinSeconds * 1000;
return this;
}
public Builder assignmentStatus(AssignmentStatus status) {
assignmentStatus = status;
return this;
}
private void validateInputs() {
checkNotNull(ipAddress, "IP Address must be specified");
checkNotNull(assignmentStatus, "Assignment Status must be specified");
checkNotNull(leasePeriod, "Lease Period must be specified");
checkNotNull(timeStamp, "Timestamp must be specified");
switch (assignmentStatus) {
case Option_Requested:
case Option_Assigned:
case Option_Expired:
break;
default:
throw new IllegalStateException("Unknown assignment status");
}
}
}
}
/*
* 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);
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp.cli;
import org.apache.karaf.shell.commands.Command;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.dhcp.DHCPService;
import java.util.Map;
/**
* Lists all the MacAddress to IP Address mappings held by the DHCP Server.
*/
@Command(scope = "onos", name = "dhcp-list",
description = "Lists all the MAC to IP mappings held by the DHCP Server")
public class DHCPListAllMappings extends AbstractShellCommand {
private static final String DHCP_MAPPING_FORMAT = "MAC ID: %s -> IP ASSIGNED %s";
@Override
protected void execute() {
DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
Map<MacAddress, Ip4Address> allocationMap = dhcpService.listMapping();
for (Map.Entry<MacAddress, Ip4Address> entry : allocationMap.entrySet()) {
print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().toString());
}
}
}
/*
* 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());
}
}
}
/*
* 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());
}
}
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp.impl;
import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.ARP;
import org.onlab.packet.DHCP;
import org.onlab.packet.DHCPOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DHCPService;
import org.onosproject.dhcp.DHCPStore;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.onlab.packet.MacAddress.valueOf;
import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
/**
* Skeletal ONOS DHCP Server application.
*/
@Component(immediate = true)
@Service
public class DHCPManager implements DHCPService {
private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true);
private final Logger log = LoggerFactory.getLogger(getClass());
private final NetworkConfigListener cfgListener = new InternalConfigListener();
private final Set<ConfigFactory> factories = ImmutableSet.of(
new ConfigFactory<ApplicationId, DHCPConfig>(APP_SUBJECT_FACTORY,
DHCPConfig.class,
"dhcp") {
@Override
public DHCPConfig createConfig() {
return new DHCPConfig();
}
},
new ConfigFactory<ApplicationId, DHCPStoreConfig>(APP_SUBJECT_FACTORY,
DHCPStoreConfig.class,
"dhcpstore") {
@Override
public DHCPStoreConfig createConfig() {
return new DHCPStoreConfig();
}
}
);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
private DHCPPacketProcessor processor = new DHCPPacketProcessor();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DHCPStore dhcpStore;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry hostProviderRegistry;
protected HostProviderService hostProviderService;
private ApplicationId appId;
// Hardcoded values are default values.
private static String myIP = "10.0.0.2";
private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
/**
* leaseTime - 10 mins or 600s.
* renewalTime - 5 mins or 300s.
* rebindingTime - 6 mins or 360s.
*/
private static int leaseTime = 600;
private static int renewalTime = 300;
private static int rebindingTime = 360;
private static byte packetTTL = (byte) 127;
private static String subnetMask = "255.0.0.0";
private static String broadcastAddress = "10.255.255.255";
private static String routerAddress = "10.0.0.2";
private static String domainServer = "10.0.0.2";
private final HostProvider hostProvider = new InternalHostProvider();
@Activate
protected void activate() {
// start the dhcp server
appId = coreService.registerApplication("org.onosproject.dhcp");
cfgService.addListener(cfgListener);
factories.forEach(cfgService::registerConfigFactory);
hostProviderService = hostProviderRegistry.register(hostProvider);
packetService.addProcessor(processor, PacketProcessor.observer(1));
requestPackets();
log.info("Started");
}
@Deactivate
protected void deactivate() {
cfgService.removeListener(cfgListener);
factories.forEach(cfgService::unregisterConfigFactory);
packetService.removeProcessor(processor);
hostProviderRegistry.unregister(hostProvider);
hostProviderService = null;
cancelPackets();
log.info("Stopped");
}
/**
* Request packet in via PacketService.
*/
private void requestPackets() {
TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_UDP)
.matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
selectorServer = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_ARP);
packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
}
/**
* Cancel requested packets in via packet service.
*/
private void cancelPackets() {
TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_UDP)
.matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
.matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
selectorServer = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_ARP);
packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
}
@Override
public Map<MacAddress, Ip4Address> listMapping() {
return dhcpStore.listMapping();
}
@Override
public int getLeaseTime() {
return leaseTime;
}
@Override
public int getRenewalTime() {
return renewalTime;
}
@Override
public int getRebindingTime() {
return rebindingTime;
}
@Override
public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
return dhcpStore.assignStaticIP(macID, ipAddress);
}
@Override
public boolean removeStaticMapping(MacAddress macID) {
return dhcpStore.removeStaticIP(macID);
}
@Override
public Iterable<Ip4Address> getAvailableIPs() {
return dhcpStore.getAvailableIPs();
}
private class DHCPPacketProcessor implements PacketProcessor {
/**
* Builds the DHCP Reply packet.
*
* @param packet the incoming Ethernet frame
* @param ipOffered the IP offered by the DHCP Server
* @param outgoingMessageType the message type of the outgoing packet
* @return the Ethernet reply frame
*/
private Ethernet buildReply(Ethernet packet, String ipOffered, byte outgoingMessageType) {
Ip4Address myIPAddress = Ip4Address.valueOf(myIP);
Ip4Address ipAddress;
// Ethernet Frame.
Ethernet ethReply = new Ethernet();
ethReply.setSourceMACAddress(myMAC);
ethReply.setDestinationMACAddress(packet.getSourceMAC());
ethReply.setEtherType(Ethernet.TYPE_IPV4);
ethReply.setVlanID(packet.getVlanID());
// IP Packet
IPv4 ipv4Packet = (IPv4) packet.getPayload();
IPv4 ipv4Reply = new IPv4();
ipv4Reply.setSourceAddress(myIPAddress.toInt());
ipAddress = Ip4Address.valueOf(ipOffered);
ipv4Reply.setDestinationAddress(ipAddress.toInt());
ipv4Reply.setTtl(packetTTL);
// UDP Datagram.
UDP udpPacket = (UDP) ipv4Packet.getPayload();
UDP udpReply = new UDP();
udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
// DHCP Payload.
DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
DHCP dhcpReply = new DHCP();
dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
ipAddress = Ip4Address.valueOf(ipOffered);
dhcpReply.setYourIPAddress(ipAddress.toInt());
dhcpReply.setServerIPAddress(myIPAddress.toInt());
dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
dhcpReply.setHardwareAddressLength((byte) 6);
// DHCP Options.
DHCPOption option = new DHCPOption();
List<DHCPOption> optionList = new ArrayList<>();
// DHCP Message Type.
option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
option.setLength((byte) 1);
byte[] optionData = {outgoingMessageType};
option.setData(optionData);
optionList.add(option);
// DHCP Server Identifier.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
option.setLength((byte) 4);
option.setData(myIPAddress.toOctets());
optionList.add(option);
// IP Address Lease Time.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
optionList.add(option);
// IP Address Renewal Time.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
optionList.add(option);
// IP Address Rebinding Time.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
optionList.add(option);
// Subnet Mask.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
option.setLength((byte) 4);
ipAddress = Ip4Address.valueOf(subnetMask);
option.setData(ipAddress.toOctets());
optionList.add(option);
// Broadcast Address.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
option.setLength((byte) 4);
ipAddress = Ip4Address.valueOf(broadcastAddress);
option.setData(ipAddress.toOctets());
optionList.add(option);
// Router Address.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
option.setLength((byte) 4);
ipAddress = Ip4Address.valueOf(routerAddress);
option.setData(ipAddress.toOctets());
optionList.add(option);
// DNS Server Address.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
option.setLength((byte) 4);
ipAddress = Ip4Address.valueOf(domainServer);
option.setData(ipAddress.toOctets());
optionList.add(option);
// End Option.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
option.setLength((byte) 1);
optionList.add(option);
dhcpReply.setOptions(optionList);
udpReply.setPayload(dhcpReply);
ipv4Reply.setPayload(udpReply);
ethReply.setPayload(ipv4Reply);
return ethReply;
}
/**
* Sends the Ethernet reply frame via the Packet Service.
*
* @param context the context of the incoming frame
* @param reply the Ethernet reply frame
*/
private void sendReply(PacketContext context, Ethernet reply) {
if (reply != null) {
TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
ConnectPoint sourcePoint = context.inPacket().receivedFrom();
builder.setOutput(sourcePoint.port());
packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
builder.build(), ByteBuffer.wrap(reply.serialize())));
}
}
/**
* Processes the DHCP Payload and initiates a reply to the client.
*
* @param context context of the incoming message
* @param dhcpPayload the extracted DHCP payload
*/
private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
Ethernet packet = context.inPacket().parsed();
boolean flagIfRequestedIP = false;
boolean flagIfServerIP = false;
Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
if (dhcpPayload != null) {
// TODO Convert this to enum value.
byte incomingPacketType = 0;
for (DHCPOption option : dhcpPayload.getOptions()) {
if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
byte[] data = option.getData();
incomingPacketType = data[0];
}
if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
byte[] data = option.getData();
requestedIP = Ip4Address.valueOf(data);
flagIfRequestedIP = true;
}
if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
byte[] data = option.getData();
serverIP = Ip4Address.valueOf(data);
flagIfServerIP = true;
}
}
String ipOffered = "";
DHCP.DHCPMessageType outgoingPacketType;
MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Discover.getValue()) {
outgoingPacketType = DHCP.DHCPMessageType.MessageType_Offer;
ipOffered = dhcpStore.suggestIP(clientMAC, requestedIP).toString();
Ethernet ethReply = buildReply(packet, ipOffered, outgoingPacketType.getValue());
sendReply(context, ethReply);
} else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Request.getValue()) {
outgoingPacketType = DHCP.DHCPMessageType.MessageType_ACK;
if (flagIfServerIP && flagIfRequestedIP) {
// SELECTING state
if (myIP.equals(serverIP.toString()) &&
dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
Ethernet ethReply = buildReply(packet, requestedIP.toString(),
outgoingPacketType.getValue());
sendReply(context, ethReply);
discoverHost(context, requestedIP);
}
} else if (flagIfRequestedIP) {
// INIT-REBOOT state
if (dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
Ethernet ethReply = buildReply(packet, requestedIP.toString(),
outgoingPacketType.getValue());
sendReply(context, ethReply);
discoverHost(context, requestedIP);
}
} else {
// RENEWING and REBINDING state
int ciaadr = dhcpPayload.getClientIPAddress();
if (ciaadr != 0) {
Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
if (dhcpStore.assignIP(clientMAC, clientIaddr, leaseTime)) {
Ethernet ethReply = buildReply(packet, clientIaddr.toString(),
outgoingPacketType.getValue());
sendReply(context, ethReply);
discoverHost(context, clientIaddr);
}
}
}
} else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Release.getValue()) {
dhcpStore.releaseIP(clientMAC);
}
}
}
/**
* Processes the ARP Payload and initiates a reply to the client.
*
* @param context context of the incoming message
* @param packet the ethernet payload
*/
private void processARPPacket(PacketContext context, Ethernet packet) {
ARP arpPacket = (ARP) packet.getPayload();
ARP arpReply = (ARP) arpPacket.clone();
arpReply.setOpCode(ARP.OP_REPLY);
arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
arpReply.setSenderHardwareAddress(myMAC.toBytes());
// Ethernet Frame.
Ethernet ethReply = new Ethernet();
ethReply.setSourceMACAddress(myMAC);
ethReply.setDestinationMACAddress(packet.getSourceMAC());
ethReply.setEtherType(Ethernet.TYPE_ARP);
ethReply.setVlanID(packet.getVlanID());
ethReply.setPayload(arpReply);
sendReply(context, ethReply);
}
/**
* Integrates hosts learned through DHCP into topology.
* @param context context of the incoming message
* @param ipAssigned IP Address assigned to the host by DHCP Manager
*/
private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
Ethernet packet = context.inPacket().parsed();
MacAddress mac = packet.getSourceMAC();
VlanId vlanId = VlanId.vlanId(packet.getVlanID());
HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
Set<IpAddress> ips = new HashSet<>();
ips.add(ipAssigned);
HostId hostId = HostId.hostId(mac, vlanId);
DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
hostProviderService.hostDetected(hostId, desc);
}
@Override
public void process(PacketContext context) {
Ethernet packet = context.inPacket().parsed();
if (packet == null) {
return;
}
if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
IPv4 ipv4Packet = (IPv4) packet.getPayload();
if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
UDP udpPacket = (UDP) ipv4Packet.getPayload();
if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
// This is meant for the dhcp server so process the packet here.
DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
processDHCPPacket(context, dhcpPayload);
}
}
} else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
ARP arpPacket = (ARP) packet.getPayload();
if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
(Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()).toString().equals(myIP))) {
processARPPacket(context, packet);
}
}
}
}
private class InternalConfigListener implements NetworkConfigListener {
/**
* Reconfigures the DHCP Server according to the configuration parameters passed.
*
* @param cfg configuration object
*/
private void reconfigureNetwork(DHCPConfig cfg) {
if (cfg.ip() != null) {
myIP = cfg.ip();
}
if (cfg.mac() != null) {
myMAC = MacAddress.valueOf(cfg.mac());
}
if (cfg.subnetMask() != null) {
subnetMask = cfg.subnetMask();
}
if (cfg.broadcastAddress() != null) {
broadcastAddress = cfg.broadcastAddress();
}
if (cfg.routerAddress() != null) {
routerAddress = cfg.routerAddress();
}
if (cfg.domainServer() != null) {
domainServer = cfg.domainServer();
}
if (cfg.ttl() != null) {
packetTTL = Byte.valueOf(cfg.ttl());
}
if (cfg.leaseTime() != null) {
leaseTime = Integer.valueOf(cfg.leaseTime());
}
if (cfg.renewTime() != null) {
renewalTime = Integer.valueOf(cfg.renewTime());
}
if (cfg.rebindTime() != null) {
rebindingTime = Integer.valueOf(cfg.rebindTime());
}
}
/**
* Reconfigures the DHCP Store according to the configuration parameters passed.
*
* @param cfg configuration object
*/
private void reconfigureStore(DHCPStoreConfig cfg) {
if (cfg.defaultTimeout() != null) {
dhcpStore.setDefaultTimeoutForPurge(Integer.valueOf(cfg.defaultTimeout()));
}
if (cfg.timerDelay() != null) {
dhcpStore.setTimerDelay(Integer.valueOf(cfg.defaultTimeout()));
}
if ((cfg.startIP() != null) && (cfg.endIP() != null)) {
dhcpStore.populateIPPoolfromRange(Ip4Address.valueOf(cfg.startIP()),
Ip4Address.valueOf(cfg.endIP()));
}
}
@Override
public void event(NetworkConfigEvent event) {
if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) {
if (event.configClass().equals(DHCPConfig.class)) {
DHCPConfig cfg = cfgService.getConfig(appId, DHCPConfig.class);
reconfigureNetwork(cfg);
log.info("Reconfigured Manager");
}
if (event.configClass().equals(DHCPStoreConfig.class)) {
DHCPStoreConfig cfg = cfgService.getConfig(appId, DHCPStoreConfig.class);
reconfigureStore(cfg);
log.info("Reconfigured Store");
}
}
}
}
private class InternalHostProvider extends AbstractProvider implements HostProvider {
/**
* Creates a provider with the supplier identifier.
*/
protected InternalHostProvider() {
super(PID);
}
@Override
public void triggerProbe(Host host) {
// nothing to do
}
}
}
\ No newline at end of file
/*
* 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);
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp.impl;
import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.util.KryoNamespace;
import org.onlab.util.Timer;
import org.onosproject.dhcp.DHCPStore;
import org.onosproject.dhcp.IPAssignment;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.DistributedSet;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.Versioned;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Manages the pool of available IP Addresses in the network and
* Remembers the mapping between MAC ID and IP Addresses assigned.
*/
@Component(immediate = true)
@Service
public class DistributedDHCPStore implements DHCPStore {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
private ConsistentMap<MacAddress, IPAssignment> allocationMap;
private DistributedSet<Ip4Address> freeIPPool;
private Timeout timeout;
private static Ip4Address startIPRange;
private static Ip4Address endIPRange;
// Hardcoded values are default values.
private static int timerDelay = 2;
private static int timeoutForPendingAssignments = 60;
@Activate
protected void activate() {
allocationMap = storageService.<MacAddress, IPAssignment>consistentMapBuilder()
.withName("onos-dhcp-assignedIP")
.withSerializer(Serializer.using(
new KryoNamespace.Builder()
.register(KryoNamespaces.API)
.register(IPAssignment.class,
IPAssignment.AssignmentStatus.class,
Date.class,
long.class,
Ip4Address.class)
.build()))
.build();
freeIPPool = storageService.<Ip4Address>setBuilder()
.withName("onos-dhcp-freeIP")
.withSerializer(Serializer.using(KryoNamespaces.API))
.build();
timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
log.info("Started");
}
@Deactivate
protected void deactivate() {
timeout.cancel();
log.info("Stopped");
}
@Override
public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
IPAssignment assignmentInfo;
if (allocationMap.containsKey(macID)) {
assignmentInfo = allocationMap.get(macID).value();
IPAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
Ip4Address ipAddr = assignmentInfo.ipAddress();
if (status == IPAssignment.AssignmentStatus.Option_Assigned ||
status == IPAssignment.AssignmentStatus.Option_Requested) {
// Client has a currently Active Binding.
if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
return ipAddr;
}
} else if (status == IPAssignment.AssignmentStatus.Option_Expired) {
// Client has a Released or Expired Binding.
if (freeIPPool.contains(ipAddr)) {
assignmentInfo = IPAssignment.builder()
.ipAddress(ipAddr)
.timestamp(new Date())
.leasePeriod(timeoutForPendingAssignments)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
.build();
if (freeIPPool.remove(ipAddr)) {
allocationMap.put(macID, assignmentInfo);
return ipAddr;
}
}
}
return assignmentInfo.ipAddress();
} else if (requestedIP.toInt() != 0) {
// Client has requested an IP.
if (freeIPPool.contains(requestedIP)) {
assignmentInfo = IPAssignment.builder()
.ipAddress(requestedIP)
.timestamp(new Date())
.leasePeriod(timeoutForPendingAssignments)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
.build();
if (freeIPPool.remove(requestedIP)) {
allocationMap.put(macID, assignmentInfo);
return requestedIP;
}
}
}
// Allocate a new IP from the server's pool of available IP.
Ip4Address nextIPAddr = fetchNextIP();
assignmentInfo = IPAssignment.builder()
.ipAddress(nextIPAddr)
.timestamp(new Date())
.leasePeriod(timeoutForPendingAssignments)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
.build();
allocationMap.put(macID, assignmentInfo);
return nextIPAddr;
}
@Override
public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
IPAssignment assignmentInfo;
if (allocationMap.containsKey(macID)) {
assignmentInfo = allocationMap.get(macID).value();
if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
(ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
assignmentInfo = IPAssignment.builder()
.ipAddress(ipAddr)
.timestamp(new Date())
.leasePeriod(leaseTime)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
.build();
allocationMap.put(macID, assignmentInfo);
return true;
}
} else if (freeIPPool.contains(ipAddr)) {
assignmentInfo = IPAssignment.builder()
.ipAddress(ipAddr)
.timestamp(new Date())
.leasePeriod(leaseTime)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
.build();
if (freeIPPool.remove(ipAddr)) {
allocationMap.put(macID, assignmentInfo);
return true;
}
}
return false;
}
@Override
public void releaseIP(MacAddress macID) {
if (allocationMap.containsKey(macID)) {
IPAssignment newAssignment = IPAssignment.builder(allocationMap.get(macID).value())
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
.build();
Ip4Address freeIP = newAssignment.ipAddress();
allocationMap.put(macID, newAssignment);
freeIPPool.add(freeIP);
}
}
@Override
public void setDefaultTimeoutForPurge(int timeInSeconds) {
timeoutForPendingAssignments = timeInSeconds;
}
@Override
public void setTimerDelay(int timeInSeconds) {
timerDelay = timeInSeconds;
}
@Override
public Map<MacAddress, Ip4Address> listMapping() {
Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
IPAssignment assignment = entry.getValue().value();
if (assignment.assignmentStatus() == IPAssignment.AssignmentStatus.Option_Assigned) {
allMapping.put(entry.getKey(), assignment.ipAddress());
}
}
return allMapping;
}
@Override
public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
return assignIP(macID, ipAddr, -1);
}
@Override
public boolean removeStaticIP(MacAddress macID) {
if (allocationMap.containsKey(macID)) {
IPAssignment assignment = allocationMap.get(macID).value();
Ip4Address freeIP = assignment.ipAddress();
if (assignment.leasePeriod() < 0) {
allocationMap.remove(macID);
freeIPPool.add(freeIP);
return true;
}
}
return false;
}
@Override
public Iterable<Ip4Address> getAvailableIPs() {
return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
}
@Override
public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
// Clear all entries from previous range.
startIPRange = startIP;
endIPRange = endIP;
freeIPPool.clear();
int lastIP = endIP.toInt();
Ip4Address nextIP;
for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
nextIP = Ip4Address.valueOf(loopCounter);
freeIPPool.add(nextIP);
}
}
/**
* Fetches the next available IP from the free pool pf IPs.
*
* @return the next available IP address
*/
private Ip4Address fetchNextIP() {
for (Ip4Address freeIP : freeIPPool) {
if (freeIPPool.remove(freeIP)) {
return freeIP;
}
}
return null;
}
/**
* Purges the IP allocation map to remove expired entries and returns the freed IPs to the free pool.
*/
private class PurgeListTask implements TimerTask {
@Override
public void run(Timeout to) {
IPAssignment ipAssignment, newAssignment;
Date dateNow = new Date();
for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
ipAssignment = entry.getValue().value();
long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
if ((ipAssignment.assignmentStatus() != IPAssignment.AssignmentStatus.Option_Expired) &&
(ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
Ip4Address freeIP = ipAssignment.ipAddress();
newAssignment = IPAssignment.builder(ipAssignment)
.assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
.build();
allocationMap.put(entry.getKey(), newAssignment);
if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
freeIPPool.add(freeIP);
}
}
}
timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
}
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp.rest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.dhcp.DHCPService;
import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Manage DHCP address assignments.
*/
@Path("dhcp")
public class DHCPWebResource extends AbstractWebResource {
final DHCPService service = get(DHCPService.class);
/**
* Get DHCP server configuration data.
* Shows lease, renewal and rebinding times in seconds.
*
* @return 200 OK
*/
@GET
@Path("config")
public Response getConfigs() {
DHCPService service = get(DHCPService.class);
ObjectNode node = mapper().createObjectNode()
.put("leaseTime", service.getLeaseTime())
.put("renewalTime", service.getRenewalTime())
.put("rebindingTime", service.getRebindingTime());
return ok(node.toString()).build();
}
/**
* Get all MAC/IP mappings.
* Shows all MAC/IP mappings held by the DHCP server.
*
* @return 200 OK
*/
@GET
@Path("mappings")
public Response listMappings() {
ObjectNode root = mapper().createObjectNode();
final Map<MacAddress, Ip4Address> intents = service.listMapping();
ArrayNode arrayNode = root.putArray("mappings");
intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
.put("mac", i.getKey().toString())
.put("ip", i.getValue().toString())));
return ok(root.toString()).build();
}
/**
* Get all available IPs.
* Shows all the IPs in the free pool of the DHCP Server.
*
* @return 200 OK
*/
@GET
@Path("available")
public Response listAvailableIPs() {
final Iterable<Ip4Address> availableIPList = service.getAvailableIPs();
final ObjectNode root = mapper().createObjectNode();
ArrayNode arrayNode = root.putArray("availableIP");
availableIPList.forEach(i -> arrayNode.add(i.toString()));
return ok(root.toString()).build();
}
/**
* Post a new static MAC/IP binding.
* Registers a static binding to the DHCP server, and displays the current set of bindings.
*
* @return 200 OK
*/
@POST
@Path("mappings")
@Consumes(MediaType.APPLICATION_JSON)
public Response setMapping(InputStream stream) {
ObjectNode root = mapper().createObjectNode();
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode macID = jsonTree.get("mac");
JsonNode ip = jsonTree.get("ip");
if (macID != null && ip != null) {
if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()),
Ip4Address.valueOf(ip.asText()))) {
throw new IllegalArgumentException("Static Mapping Failed. The IP maybe unavailable.");
}
}
final Map<MacAddress, Ip4Address> intents = service.listMapping();
ArrayNode arrayNode = root.putArray("mappings");
intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
.put("mac", i.getKey().toString())
.put("ip", i.getValue().toString())));
} catch (IOException e) {
throw new IllegalArgumentException(e.getMessage());
}
return ok(root.toString()).build();
}
/**
* Delete a static MAC/IP binding.
* Removes a static binding from the DHCP Server, and displays the current set of bindings.
*
* @return 200 OK
*/
@DELETE
@Path("mappings/{macID}")
public Response deleteMapping(@PathParam("macID") String macID) {
ObjectNode root = mapper().createObjectNode();
if (!service.removeStaticMapping(MacAddress.valueOf(macID))) {
throw new IllegalArgumentException("Static Mapping Removal Failed.");
}
final Map<MacAddress, Ip4Address> intents = service.listMapping();
ArrayNode arrayNode = root.putArray("mappings");
intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
.put("mac", i.getKey().toString())
.put("ip", i.getValue().toString())));
return ok(root.toString()).build();
}
}
<!--
~ 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
<?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>
/*
* 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
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.dhcp.impl;
import com.google.common.collect.ImmutableSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.DHCP;
import org.onlab.packet.DHCPOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.UDP;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.dhcp.DHCPStore;
import org.onosproject.net.config.NetworkConfigRegistryAdapter;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.DefaultPacketContext;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketServiceAdapter;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.AbstractProviderService;
import org.onosproject.net.provider.ProviderId;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.onosproject.net.NetTestTools.connectPoint;
/**
* Set of tests of the ONOS application component.
*/
public class DHCPManagerTest {
private DHCPManager dhcpManager;
protected PacketProcessor packetProcessor;
protected HostProviderService hostProviderService;
private static final MacAddress CLIENT1_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
private static final String EXPECTED_IP = "10.2.0.2";
private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255");
private static final int TRANSACTION_ID = 1000;
private static final ProviderId PID = new ProviderId("of", "foo");
@Before
public void setUp() {
dhcpManager = new DHCPManager();
dhcpManager.cfgService = new TestNetworkConfigRegistry();
dhcpManager.packetService = new TestPacketService();
dhcpManager.coreService = new TestCoreService();
dhcpManager.dhcpStore = new TestDHCPStore();
hostProviderService = new TestHostProviderService(new TestHostProvider());
dhcpManager.hostProviderService = hostProviderService;
dhcpManager.hostProviderRegistry = new TestHostRegistry();
dhcpManager.activate();
}
@After
public void tearDown() {
dhcpManager.deactivate();
}
/**
* Tests the response to a DHCP Discover Packet.
*/
@Test
public void testDiscover() {
Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Discover);
sendPacket(reply);
}
/**
* Tests the response to a DHCP Request Packet.
*/
@Test
public void testRequest() {
Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Request);
sendPacket(reply);
}
/**
* Sends an Ethernet packet to the process method of the Packet Processor.
* @param reply Ethernet packet
*/
private void sendPacket(Ethernet reply) {
final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize());
InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
reply,
byteBuffer);
PacketContext context = new TestPacketContext(127L, inPacket, null, false);
packetProcessor.process(context);
}
/**
* Constructs an Ethernet packet containing a DHCP Payload.
* @param messageType DHCP Message Type
* @return Ethernet packet
*/
private Ethernet constructDHCPPacket(DHCP.DHCPMessageType messageType) {
// Ethernet Frame.
Ethernet ethReply = new Ethernet();
ethReply.setSourceMACAddress(CLIENT1_MAC);
ethReply.setDestinationMACAddress(MacAddress.BROADCAST);
ethReply.setEtherType(Ethernet.TYPE_IPV4);
ethReply.setVlanID((short) 2);
// IP Packet
IPv4 ipv4Reply = new IPv4();
ipv4Reply.setSourceAddress(0);
ipv4Reply.setDestinationAddress(BROADCAST.toInt());
ipv4Reply.setTtl((byte) 127);
// UDP Datagram.
UDP udpReply = new UDP();
udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
// DHCP Payload.
DHCP dhcpReply = new DHCP();
dhcpReply.setOpCode(DHCP.OPCODE_REQUEST);
dhcpReply.setYourIPAddress(0);
dhcpReply.setServerIPAddress(0);
dhcpReply.setTransactionId(TRANSACTION_ID);
dhcpReply.setClientHardwareAddress(CLIENT1_MAC.toBytes());
dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
dhcpReply.setHardwareAddressLength((byte) 6);
// DHCP Options.
DHCPOption option = new DHCPOption();
List<DHCPOption> optionList = new ArrayList<>();
// DHCP Message Type.
option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
option.setLength((byte) 1);
byte[] optionData = {messageType.getValue()};
option.setData(optionData);
optionList.add(option);
// DHCP Requested IP.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
option.setLength((byte) 4);
optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
option.setData(optionData);
optionList.add(option);
// End Option.
option = new DHCPOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
option.setLength((byte) 1);
optionList.add(option);
dhcpReply.setOptions(optionList);
udpReply.setPayload(dhcpReply);
ipv4Reply.setPayload(udpReply);
ethReply.setPayload(ipv4Reply);
return ethReply;
}
/**
* Validates the contents of the packet sent by the DHCP Manager.
* @param packet Ethernet packet received
*/
private void validatePacket(Ethernet packet) {
DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload();
assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_MAC);
assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP));
assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID);
}
/**
* Mocks the DHCPStore.
*/
private final class TestDHCPStore implements DHCPStore {
public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
}
public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
return Ip4Address.valueOf(EXPECTED_IP);
}
public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
return true;
}
public void setDefaultTimeoutForPurge(int timeInSeconds) {
}
public void setTimerDelay(int timeInSeconds) {
}
public void releaseIP(MacAddress macID) {
}
public Map<MacAddress, Ip4Address> listMapping() {
Map<MacAddress, Ip4Address> map = new HashMap<>();
map.put(CLIENT1_MAC, Ip4Address.valueOf(EXPECTED_IP));
return map;
}
public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
return true;
}
public boolean removeStaticIP(MacAddress macID) {
return true;
}
public Iterable<Ip4Address> getAvailableIPs() {
List<Ip4Address> ipList = new ArrayList<>();
ipList.add(Ip4Address.valueOf(EXPECTED_IP));
return ImmutableSet.copyOf(ipList);
}
}
/**
* Mocks the DefaultPacket context.
*/
private final class TestPacketContext extends DefaultPacketContext {
private TestPacketContext(long time, InboundPacket inPkt,
OutboundPacket outPkt, boolean block) {
super(time, inPkt, outPkt, block);
}
@Override
public void send() {
// We don't send anything out.
}
}
/**
* Keeps a reference to the PacketProcessor and verifies the OutboundPackets.
*/
private class TestPacketService extends PacketServiceAdapter {
@Override
public void addProcessor(PacketProcessor processor, int priority) {
packetProcessor = processor;
}
@Override
public void emit(OutboundPacket packet) {
try {
Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
0, packet.data().array().length);
validatePacket(eth);
} catch (Exception e) {
fail(e.getMessage());
}
}
}
/**
* Mocks the CoreService.
*/
private class TestCoreService extends CoreServiceAdapter {
}
/**
* Mocks the NetworkConfigRegistry.
*/
private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
}
/**
* Mocks the HostProviderService.
*/
private class TestHostProviderService extends AbstractProviderService<HostProvider>
implements HostProviderService {
protected TestHostProviderService(HostProvider provider) {
super(provider);
}
@Override
public void hostDetected(HostId hostId, HostDescription hostDescription) {
}
@Override
public void hostVanished(HostId hostId) {
}
}
/**
* Mocks the HostProvider.
*/
private static class TestHostProvider extends AbstractProvider
implements HostProvider {
protected TestHostProvider() {
super(PID);
}
@Override
public ProviderId id() {
return PID;
}
@Override
public void triggerProbe(Host host) {
}
}
/**
* Mocks the HostProviderRegistry.
*/
private class TestHostRegistry implements HostProviderRegistry {
@Override
public HostProviderService register(HostProvider provider) {
return hostProviderService;
}
@Override
public void unregister(HostProvider provider) {
}
@Override
public Set<ProviderId> getProviders() {
return null;
}
}
}
{
"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
......@@ -57,6 +57,7 @@
<module>vtnrsc</module>
<module>vtn</module>
<module>vtnweb</module>
<module>onos-app-dhcp</module>
</modules>
<properties>
......