Hyunsun Moon
Committed by Gerrit Code Review

Make some DHCP options and host discovery configurable

- Added broadcast option
- Made host discovery from DHCP configurable
- Some code cleanups

Change-Id: I42191c2fd17ef309c73a5382730d708686b835cd
(cherry picked from commit 04b1fe9a)
......@@ -15,7 +15,6 @@
*/
package org.onosproject.cordvtn.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -34,6 +33,7 @@ import org.onosproject.cordvtn.api.Instance;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DhcpService;
import org.onosproject.dhcp.IpAssignment;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
......@@ -70,7 +70,7 @@ import org.onosproject.xosclient.api.XosAccess;
import org.onosproject.xosclient.api.XosClientService;
import org.slf4j.Logger;
import java.util.List;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
......@@ -82,6 +82,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.cordvtn.api.Instance.*;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
import static org.onosproject.xosclient.api.VtnService.NetworkType.MANAGEMENT;
import static org.onosproject.xosclient.api.VtnService.NetworkType.PRIVATE;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -97,6 +99,7 @@ public class CordVtnInstanceManager extends AbstractProvider implements HostProv
private static final String XOS_ACCESS_ERROR = "XOS access is not configured";
private static final String OPENSTACK_ACCESS_ERROR = "OpenStack access is not configured";
private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
private static final int DHCP_INFINITE_LEASE = -1;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
......@@ -273,7 +276,6 @@ public class CordVtnInstanceManager extends AbstractProvider implements HostProv
arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(instance));
}
if (!instance.isNestedInstance()) {
registerDhcpLease(instance, service);
}
......@@ -295,17 +297,25 @@ public class CordVtnInstanceManager extends AbstractProvider implements HostProv
}
private void registerDhcpLease(Instance instance, VtnService service) {
List<Ip4Address> options = Lists.newArrayList();
options.add(Ip4Address.makeMaskPrefix(service.subnet().prefixLength()));
options.add(service.serviceIp().getIp4Address());
options.add(service.serviceIp().getIp4Address());
options.add(DEFAULT_DNS);
Ip4Address broadcast = Ip4Address.makeMaskedAddress(
instance.ipAddress(),
service.subnet().prefixLength());
IpAssignment.Builder ipBuilder = IpAssignment.builder()
.ipAddress(instance.ipAddress())
.leasePeriod(DHCP_INFINITE_LEASE)
.timestamp(new Date())
.subnetMask(Ip4Address.makeMaskPrefix(service.subnet().prefixLength()))
.broadcast(broadcast)
.domainServer(DEFAULT_DNS)
.assignmentStatus(Option_RangeNotEnforced);
if (service.networkType() != MANAGEMENT) {
ipBuilder = ipBuilder.routerAddress(service.serviceIp().getIp4Address());
}
log.debug("Set static DHCP mapping for {} {}", instance.mac(), instance.ipAddress());
dhcpService.setStaticMapping(instance.mac(),
instance.ipAddress(),
true,
options);
dhcpService.setStaticMapping(instance.mac(), ipBuilder.build());
}
private VtnService getVtnService(VtnServiceId serviceId) {
......
......@@ -19,7 +19,6 @@ import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.HostId;
import java.util.List;
import java.util.Map;
......@@ -58,16 +57,12 @@ public interface DhcpService {
/**
* Registers a static IP mapping with the DHCP Server.
* Supports rangeNotEnforced option
*
* @param macID macID of the client
* @param ipAddress IP Address requested for the client
* @param rangeNotEnforced true if rangeNotEnforced was set and the mapping will be eternal
* @param addressList subnetMask, DHCP/Router/DNS IP Addresses if rangeNotEnforced was set
* @param macAddress mac address to have a given ip assignment
* @param ipRequest ip address and dhcp options
* @return true if the mapping was successfully added, false otherwise
*/
boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress, boolean rangeNotEnforced,
List<Ip4Address> addressList);
boolean setStaticMapping(MacAddress macAddress, IpAssignment ipRequest);
/**
* Removes a static IP mapping with the DHCP Server.
......
......@@ -19,7 +19,6 @@ import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.HostId;
import java.util.List;
import java.util.Map;
......@@ -41,7 +40,7 @@ public interface DhcpStore {
*
* @param hostId Host ID of the client requesting an IP
* @param requestedIP requested IP address
* @return IP address assigned to the Mac ID
* @return IP address assigned to the Mac address; null if no available IP
*/
Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP);
......@@ -50,14 +49,10 @@ public interface DhcpStore {
* Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message.
*
* @param hostId Host Id of the client requesting an IP
* @param ipAddr IP Address being requested
* @param leaseTime Lease time offered by the server for this mapping
* @param rangeNotEnforced true if rangeNotEnforced was set
* @param addressList subnetMask, DHCP/Router/DNS IP Addresses if rangeNotEnforced was set
* @param ipAssignment ip assignment
* @return returns true if the assignment was successful, false otherwise
*/
boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime, boolean rangeNotEnforced,
List<Ip4Address> addressList);
boolean assignIP(HostId hostId, IpAssignment ipAssignment);
/**
......@@ -92,21 +87,19 @@ public interface DhcpStore {
/**
* 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
* @param rangeNotEnforced true if rangeNotEnforced was set
* @param addressList subnetMask, DHCP/Router/DNS IP Addresses rangeNotEnforced was set
* @param macAddress mac address of the client
* @param ipAssignment ip address and dhcp options requested for the client
* @return true if the mapping was successfully registered, false otherwise
*/
boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr, boolean rangeNotEnforced, List<Ip4Address> addressList);
boolean assignStaticIP(MacAddress macAddress, IpAssignment ipAssignment);
/**
* Removes a static IP mapping associated with the given MAC ID from the DHCP Server.
*
* @param macID macID of the client
* @param macAddress mac address of the client
* @return true if the mapping was successfully registered, false otherwise
*/
boolean removeStaticIP(MacAddress macID);
boolean removeStaticIP(MacAddress macAddress);
/**
* Returns the list of all the available IPs with the server.
......
......@@ -27,22 +27,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public final class IpAssignment {
// TODO make some dhcp options optional
private final Ip4Address ipAddress;
private final Date timestamp;
private final long leasePeriod;
private final Ip4Address subnetMask;
private final Ip4Address broadcast;
private final Ip4Address dhcpServer;
private final Ip4Address routerAddress;
private final Ip4Address domainServer;
private final boolean rangeNotEnforced;
private final AssignmentStatus assignmentStatus;
public enum AssignmentStatus {
......@@ -52,8 +45,10 @@ public final class IpAssignment {
Option_Requested,
/**
* IP Assignment has been requested by a OpenStack.
* Static IP Assignment with unregistered IP range.
* This assignment can only be added or removed by set or remove static mapping.
*/
// TODO allow multiple IP ranges and remove this option
Option_RangeNotEnforced,
/**
* IP has been assigned to a host.
......@@ -70,30 +65,34 @@ public final class IpAssignment {
* Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp
* and assignment status is supplied.
*
* @param ipAddress
* @param leasePeriod
* @param timestamp
* @param assignmentStatus
* @param subnetMask
* @param dhcpServer
* @param routerAddress
* @param domainServer
* @param rangeNotEnforced
* @param ipAddress ip address to assign
* @param leasePeriod lease period
* @param timestamp time stamp of the assignment
* @param assignmentStatus statue of the assignment
* @param subnetMask subnet mask of assigned ip range
* @param broadcast broadcast address
* @param dhcpServer dhcp server address
* @param routerAddress router address
* @param domainServer domain server address
*/
private IpAssignment(Ip4Address ipAddress,
long leasePeriod,
Date timestamp,
AssignmentStatus assignmentStatus, Ip4Address subnetMask, Ip4Address dhcpServer,
Ip4Address routerAddress, Ip4Address domainServer, boolean rangeNotEnforced) {
AssignmentStatus assignmentStatus,
Ip4Address subnetMask,
Ip4Address broadcast,
Ip4Address dhcpServer,
Ip4Address routerAddress,
Ip4Address domainServer) {
this.ipAddress = ipAddress;
this.leasePeriod = leasePeriod;
this.timestamp = timestamp;
this.assignmentStatus = assignmentStatus;
this.subnetMask = subnetMask;
this.broadcast = broadcast;
this.dhcpServer = dhcpServer;
this.routerAddress = routerAddress;
this.domainServer = domainServer;
this.rangeNotEnforced = rangeNotEnforced;
}
/**
......@@ -141,26 +140,51 @@ public final class IpAssignment {
return (int) this.leasePeriod * 1000;
}
/**
* Returns subnet mask of the IP assignment.
*
* @return subnet mask
*/
public Ip4Address subnetMask() {
return subnetMask;
}
/**
* Returns broadcast address of the IP assignment.
*
* @return broadcast address
*/
public Ip4Address broadcast() {
return broadcast;
}
/**
* Returns dhcp server of the IP assignment.
*
* @return dhcp server ip address
*/
public Ip4Address dhcpServer() {
return dhcpServer;
}
/**
* Returns router address of the IP assignment.
*
* @return router ip address
*/
public Ip4Address routerAddress() {
return routerAddress;
}
/**
* Returns domain server address.
*
* @return domain server ip address
*/
public Ip4Address domainServer() {
return domainServer;
}
public boolean rangeNotEnforced() {
return rangeNotEnforced;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
......@@ -169,10 +193,10 @@ public final class IpAssignment {
.add("lease", leasePeriod)
.add("assignmentStatus", assignmentStatus)
.add("subnetMask", subnetMask)
.add("broadcast", broadcast)
.add("dhcpServer", dhcpServer)
.add("routerAddress", routerAddress)
.add("domainServer", domainServer)
.add("rangeNotEnforced", rangeNotEnforced)
.toString();
}
......@@ -201,25 +225,16 @@ public final class IpAssignment {
public static final class Builder {
private Ip4Address ipAddress;
private Date timeStamp;
private long leasePeriod;
private AssignmentStatus assignmentStatus;
private Ip4Address subnetMask;
private Ip4Address broadcast;
private Ip4Address dhcpServer;
private Ip4Address domainServer;
private Ip4Address routerAddress;
private boolean rangeNotEnforced = false;
private Ip4Address domainServer;
private Builder() {
}
private Builder(IpAssignment ipAssignment) {
......@@ -227,12 +242,24 @@ public final class IpAssignment {
timeStamp = ipAssignment.timestamp();
leasePeriod = ipAssignment.leasePeriod();
assignmentStatus = ipAssignment.assignmentStatus();
subnetMask = ipAssignment.subnetMask();
broadcast = ipAssignment.broadcast();
dhcpServer = ipAssignment.dhcpServer();
routerAddress = ipAssignment.routerAddress();
domainServer = ipAssignment.domainServer();
}
public IpAssignment build() {
validateInputs();
return new IpAssignment(ipAddress, leasePeriod, timeStamp, assignmentStatus, subnetMask,
dhcpServer, routerAddress, domainServer, rangeNotEnforced);
return new IpAssignment(ipAddress,
leasePeriod,
timeStamp,
assignmentStatus,
subnetMask,
broadcast,
dhcpServer,
routerAddress,
domainServer);
}
public Builder ipAddress(Ip4Address addr) {
......@@ -260,6 +287,11 @@ public final class IpAssignment {
return this;
}
public Builder broadcast(Ip4Address broadcast) {
this.broadcast = broadcast;
return this;
}
public Builder dhcpServer(Ip4Address dhcpServer) {
this.dhcpServer = dhcpServer;
return this;
......@@ -275,25 +307,12 @@ public final class IpAssignment {
return this;
}
public Builder rangeNotEnforced(boolean rangeNotEnforced) {
this.rangeNotEnforced = rangeNotEnforced;
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");
if (rangeNotEnforced) {
checkNotNull(subnetMask, "subnetMask must be specified in case of rangeNotEnforced");
checkNotNull(dhcpServer, "dhcpServer must be specified in case of rangeNotEnforced");
checkNotNull(domainServer, "domainServer must be specified in case of rangeNotEnforced");
checkNotNull(routerAddress, "routerAddress must be specified in case of rangeNotEnforced");
}
switch (assignmentStatus) {
case Option_Requested:
case Option_RangeNotEnforced:
......
......@@ -15,13 +15,17 @@
*/
package org.onosproject.dhcp.cli;
import com.google.common.collect.Lists;
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;
import org.onosproject.dhcp.IpAssignment;
import java.util.Date;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_Requested;
/**
* Registers a static MAC Address to IP Mapping with the DHCP Server.
......@@ -49,7 +53,15 @@ public class DhcpSetStaticMapping extends AbstractShellCommand {
try {
MacAddress macID = MacAddress.valueOf(macAddr);
Ip4Address ipAddress = Ip4Address.valueOf(ipAddr);
if (dhcpService.setStaticMapping(macID, ipAddress, false, Lists.newArrayList())) {
IpAssignment ipAssignment = IpAssignment.builder()
.ipAddress(ipAddress)
.leasePeriod(dhcpService.getLeaseTime())
.timestamp(new Date())
.assignmentStatus(Option_Requested)
.build();
if (dhcpService.setStaticMapping(macID, ipAssignment)) {
print(DHCP_SUCCESS);
} else {
print(DHCP_FAILURE);
......
......@@ -39,9 +39,10 @@ import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.Objects;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_Assigned;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
/**
* Manages the pool of available IP Addresses in the network and
......@@ -58,18 +59,13 @@ public class DistributedDhcpStore implements DhcpStore {
protected StorageService storageService;
private ConsistentMap<HostId, IpAssignment> allocationMap;
private DistributedSet<Ip4Address> freeIPPool;
private static Ip4Address startIPRange;
private static Ip4Address endIPRange;
// Hardcoded values are default values.
private static int timeoutForPendingAssignments = 60;
private static final int MAX_RETRIES = 3;
private static final int MAX_BACKOFF = 10;
@Activate
protected void activate() {
......@@ -109,9 +105,9 @@ public class DistributedDhcpStore implements DhcpStore {
IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
Ip4Address ipAddr = assignmentInfo.ipAddress();
if (assignmentInfo.rangeNotEnforced()) {
if (assignmentInfo.assignmentStatus().equals(Option_RangeNotEnforced)) {
return assignmentInfo.ipAddress();
} else if (status == IpAssignment.AssignmentStatus.Option_Assigned ||
} else if (status == Option_Assigned ||
status == IpAssignment.AssignmentStatus.Option_Requested) {
// Client has a currently Active Binding.
if (ipWithinRange(ipAddr)) {
......@@ -166,82 +162,65 @@ public class DistributedDhcpStore implements DhcpStore {
}
@Override
public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime, boolean rangeNotEnforced,
List<Ip4Address> addressList) {
log.debug("Assign IP Called w/ Ip4Address: {}, HostId: {}", ipAddr.toString(), hostId.mac().toString());
public boolean assignIP(HostId hostId, IpAssignment ipAssignment) {
log.trace("Assign IP Called HostId: {}, ipAssignment: {}",
hostId, ipAssignment);
Versioned<IpAssignment> currentAssignment = allocationMap.get(hostId);
IpAssignment newAssignment = null;
if (currentAssignment == null) {
if (rangeNotEnforced) {
newAssignment = IpAssignment.builder()
.ipAddress(ipAddr)
.timestamp(new Date())
.leasePeriod(leaseTime)
.rangeNotEnforced(true)
.assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced)
.subnetMask((Ip4Address) addressList.toArray()[0])
.dhcpServer((Ip4Address) addressList.toArray()[1])
.routerAddress((Ip4Address) addressList.toArray()[2])
.domainServer((Ip4Address) addressList.toArray()[3])
.build();
} else if (freeIPPool.remove(ipAddr)) {
newAssignment = IpAssignment.builder()
.ipAddress(ipAddr)
Versioned<IpAssignment> versionedAssignment = allocationMap.get(hostId);
Ip4Address requestedIp = ipAssignment.ipAddress();
if (versionedAssignment == null) {
// this is new IP assignment of static mapping
// dynamic assignment is done in suggestIP
if (ipAssignment.assignmentStatus().equals(Option_RangeNotEnforced)) {
newAssignment = ipAssignment;
} else if (freeIPPool.remove(requestedIp)) {
newAssignment = IpAssignment.builder(ipAssignment)
.assignmentStatus(Option_Assigned)
.timestamp(new Date())
.leasePeriod(leaseTime)
.assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
.build();
} else {
log.trace("Failed to assign IP for {}", ipAssignment);
return false;
}
log.trace("Assigned {}", newAssignment);
return allocationMap.putIfAbsent(hostId, newAssignment) == null;
// TODO: handle the case where map changed.
} else {
IpAssignment existingAssignment = currentAssignment.value();
if (Objects.equals(existingAssignment.ipAddress(), ipAddr) &&
(existingAssignment.rangeNotEnforced() || ipWithinRange(ipAddr))) {
// this is lease renew or rebinding
// update assignment status and time stamp, and keep the others
IpAssignment existingAssignment = versionedAssignment.value();
if (!existingAssignment.ipAddress().equals(requestedIp)) {
// return false if existing assignment is not for the
// requested host
log.trace("Failed to assign IP for {}", ipAssignment);
return false;
}
switch (existingAssignment.assignmentStatus()) {
case Option_RangeNotEnforced:
newAssignment = IpAssignment.builder()
.ipAddress(ipAddr)
newAssignment = IpAssignment.builder(existingAssignment)
.timestamp(new Date())
.leasePeriod(existingAssignment.leasePeriod())
.rangeNotEnforced(true)
.assignmentStatus(IpAssignment.AssignmentStatus.Option_RangeNotEnforced)
.subnetMask(existingAssignment.subnetMask())
.dhcpServer(existingAssignment.dhcpServer())
.routerAddress(existingAssignment.routerAddress())
.domainServer(existingAssignment.domainServer())
.build();
break;
case Option_Expired:
if (!freeIPPool.remove(requestedIp)) {
// requested IP is expired for this host and reserved to the other host
return false;
}
case Option_Assigned:
case Option_Requested:
newAssignment = IpAssignment.builder()
.ipAddress(ipAddr)
.timestamp(new Date())
.leasePeriod(leaseTime)
.assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
.build();
break;
case Option_Expired:
if (freeIPPool.remove(ipAddr)) {
newAssignment = IpAssignment.builder()
.ipAddress(ipAddr)
newAssignment = IpAssignment.builder(existingAssignment)
.timestamp(new Date())
.leasePeriod(leaseTime)
.assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned)
.assignmentStatus(Option_Assigned)
.build();
}
break;
default:
break;
}
return allocationMap.replace(hostId, currentAssignment.version(), newAssignment);
} else {
return false;
}
log.trace("Assigned {}", newAssignment);
return allocationMap.replace(hostId, versionedAssignment.version(), newAssignment);
}
}
......@@ -273,8 +252,8 @@ public class DistributedDhcpStore implements DhcpStore {
IpAssignment assignment;
for (Map.Entry<HostId, Versioned<IpAssignment>> entry: allocationMap.entrySet()) {
assignment = entry.getValue().value();
if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned
|| assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_RangeNotEnforced) {
if (assignment.assignmentStatus() == Option_Assigned
|| assignment.assignmentStatus() == Option_RangeNotEnforced) {
validMapping.put(entry.getKey(), assignment);
}
}
......@@ -291,10 +270,9 @@ public class DistributedDhcpStore implements DhcpStore {
}
@Override
public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr, boolean rangeNotEnforced,
List<Ip4Address> addressList) {
HostId host = HostId.hostId(macID);
return assignIP(host, ipAddr, -1, rangeNotEnforced, addressList);
public boolean assignStaticIP(MacAddress macAddress, IpAssignment ipAssignment) {
HostId host = HostId.hostId(macAddress);
return assignIP(host, ipAssignment);
}
@Override
......@@ -303,7 +281,7 @@ public class DistributedDhcpStore implements DhcpStore {
if (allocationMap.containsKey(host)) {
IpAssignment assignment = allocationMap.get(host).value();
if (assignment.rangeNotEnforced()) {
if (assignment.assignmentStatus().equals(Option_RangeNotEnforced)) {
allocationMap.remove(host);
return true;
}
......@@ -339,11 +317,16 @@ public class DistributedDhcpStore implements DhcpStore {
nextIP = Ip4Address.valueOf(loopCounter);
freeIPPool.add(nextIP);
}
log.debug("Updated free IP pool {}:{} size:{}", startIP, endIP, freeIPPool.size());
}
@Override
public IpAssignment getIpAssignmentFromAllocationMap(HostId hostId) {
if (allocationMap.get(hostId) != null) {
return allocationMap.get(hostId).value();
} else {
return null;
}
}
/**
......
......@@ -18,7 +18,6 @@ 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 com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.dhcp.DhcpService;
......@@ -36,8 +35,11 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_Requested;
/**
* Manage DHCP address assignments.
*/
......@@ -120,10 +122,15 @@ public class DhcpWebResource extends AbstractWebResource {
JsonNode macID = jsonTree.get("mac");
JsonNode ip = jsonTree.get("ip");
if (macID != null && ip != null) {
IpAssignment ipAssignment = IpAssignment.builder()
.ipAddress(Ip4Address.valueOf(ip.asText()))
.leasePeriod(service.getLeaseTime())
.timestamp(new Date())
.assignmentStatus(Option_Requested)
.build();
if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()),
Ip4Address.valueOf(ip.asText()),
false, Lists.newArrayList())) {
ipAssignment)) {
throw new IllegalArgumentException("Static Mapping Failed. " +
"The IP maybe unavailable.");
}
......
......@@ -28,6 +28,7 @@ import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.UDP;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.dhcp.DhcpStore;
import org.onosproject.dhcp.IpAssignment;
......@@ -93,6 +94,7 @@ public class DhcpManagerTest {
hostProviderService = new TestHostProviderService(new TestHostProvider());
dhcpXManager.hostProviderService = hostProviderService;
dhcpXManager.hostProviderRegistry = new TestHostRegistry();
dhcpXManager.componentConfigService = new TestComponentConfig();
dhcpXManager.activate();
}
......@@ -228,8 +230,7 @@ public class DhcpManagerTest {
return Ip4Address.valueOf(EXPECTED_IP);
}
public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime, boolean fromOpenStack,
List<Ip4Address> addressList) {
public boolean assignIP(HostId hostId, IpAssignment ipAssignment) {
return true;
}
......@@ -256,8 +257,7 @@ public class DhcpManagerTest {
return map;
}
public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr, boolean fromOpenStack,
List<Ip4Address> addressList) {
public boolean assignStaticIP(MacAddress macID, IpAssignment ipAssignment) {
return true;
}
......@@ -327,6 +327,13 @@ public class DhcpManagerTest {
}
/**
* Mocks the ComponentConfigRegistry.
*/
private class TestComponentConfig extends ComponentConfigAdapter {
}
/**
* Mocks the HostProviderService.
*/
private class TestHostProviderService extends AbstractProviderService<HostProvider>
......
......@@ -9,11 +9,11 @@
"router": "10.0.0.1",
"domain": "10.0.0.1",
"ttl": "63",
"lease": "300",
"lease": 300,
"renew": "150",
"rebind": "200",
"rebind": 200,
"delay": "3",
"timeout": "150",
"timeout": 150,
"startip": "10.0.0.110",
"endip": "10.0.0.130"
}
......
......@@ -15,7 +15,6 @@
*/
package org.onosproject.openstacknetworking.switching;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
......@@ -26,9 +25,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpPrefix;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.dhcp.DhcpService;
import org.onosproject.dhcp.IpAssignment;
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -61,13 +62,18 @@ import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Date;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@Service
@Component(immediate = true)
......@@ -117,8 +123,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
public static final String PORTNAME = "portName";
private static final String ROUTER_INTERFACE = "network:router_interface";
public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
public static final String DNS_SERVER_IP = "8.8.8.8";
public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
private static final String FORWARD_SLASH = "/";
private static final int DHCP_INFINITE_LEASE = -1;
private ApplicationId appId;
......@@ -372,42 +379,41 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
}
private void registerDhcpInfo(OpenstackPort openstackPort) {
Ip4Address ip4Address, subnetMask, gatewayIPAddress, dhcpServer, domainServer;
OpenstackSubnet openstackSubnet;
checkNotNull(openstackPort);
checkArgument(!openstackPort.fixedIps().isEmpty());
ip4Address = (Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null);
openstackSubnet = openstackService.subnets().stream()
OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
.filter(n -> n.networkId().equals(openstackPort.networkId()))
.findFirst().get();
subnetMask = Ip4Address.valueOf(buildSubnetMask(openstackSubnet.cidr()));
gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
dhcpServer = gatewayIPAddress;
// TODO: supports multiple DNS servers
if (openstackSubnet.dnsNameservers().isEmpty()) {
domainServer = Ip4Address.valueOf(DNS_SERVER_IP);
} else {
domainServer = openstackSubnet.dnsNameservers().get(0);
}
List<Ip4Address> options = ImmutableList.of(subnetMask, dhcpServer, gatewayIPAddress, domainServer);
dhcpService.setStaticMapping(openstackPort.macAddress(), ip4Address, true, options);
.findFirst().orElse(null);
if (openstackSubnet == null) {
log.warn("Failed to find subnet for {}", openstackPort);
return;
}
private byte[] buildSubnetMask(String cidr) {
int prefix;
String[] parts = cidr.split(FORWARD_SLASH);
prefix = Integer.parseInt(parts[1]);
int mask = 0xffffffff << (32 - prefix);
byte[] bytes = new byte[]{(byte) (mask >>> 24),
(byte) (mask >> 16 & 0xff), (byte) (mask >> 8 & 0xff), (byte) (mask & 0xff)};
Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
Ip4Address broadcast = Ip4Address.makeMaskedAddress(
ipAddress,
subnetPrefix.prefixLength());
return bytes;
// TODO: supports multiple DNS servers
Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
IpAssignment ipAssignment = IpAssignment.builder()
.ipAddress(ipAddress)
.leasePeriod(DHCP_INFINITE_LEASE)
.timestamp(new Date())
.subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
.broadcast(broadcast)
.domainServer(domainServer)
.assignmentStatus(Option_RangeNotEnforced)
.routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
.build();
dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
}
private class InternalPacketProcessor implements PacketProcessor {
@Override
......