tom

Implementing port update in trivial core.

package org.onlab.onos.net;
import java.util.Objects;
import static com.google.common.base.Objects.toStringHelper;
/**
* Default port implementation.
*/
public class DefaultPort implements Port {
private final Element element;
private final PortNumber number;
private final boolean isEnabled;
/**
* Creates a network element attributed to the specified provider.
*
* @param element parent network element
* @param number port number
* @param isEnabled indicator whether the port is up and active
*/
public DefaultPort(Element element, PortNumber number,
boolean isEnabled) {
this.element = element;
this.number = number;
this.isEnabled = isEnabled;
}
@Override
public int hashCode() {
return Objects.hash(number, isEnabled);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DefaultPort) {
final DefaultPort other = (DefaultPort) obj;
return Objects.equals(this.element.id(), other.element.id()) &&
Objects.equals(this.number, other.number) &&
Objects.equals(this.isEnabled, other.isEnabled);
}
return false;
}
@Override
public String toString() {
return toStringHelper(this)
.add("element", element.id())
.add("number", number)
.add("isEnabled", isEnabled)
.toString();
}
@Override
public PortNumber number() {
return number;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public Element element() {
return element;
}
}
......@@ -20,11 +20,11 @@ public interface Port {
boolean isEnabled();
/**
* Returns the identifier of the network element to which this port belongs.
* Returns the parent network element to which this port belongs.
*
* @return parent network element
*/
Element parent();
Element element();
// set of port attributes
......
......@@ -2,12 +2,15 @@ package org.onlab.onos.net.device;
import org.onlab.onos.event.AbstractEvent;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.Port;
/**
* Describes infrastructure device event.
*/
public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
private final Port port;
/**
* Type of device events.
*/
......@@ -42,7 +45,22 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
* Signifies that the current controller instance relationship has
* changed with respect to a device.
*/
DEVICE_MASTERSHIP_CHANGED
DEVICE_MASTERSHIP_CHANGED,
/**
* Signifies that a port has been added.
*/
PORT_ADDED,
/**
* Signifies that a port has been updated.
*/
PORT_UPDATED,
/**
* Signifies that a port has been removed.
*/
PORT_REMOVED
}
/**
......@@ -53,7 +71,20 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
* @param device event device subject
*/
public DeviceEvent(Type type, Device device) {
this(type, device, null);
}
/**
* Creates an event of a given type and for the specified device, port
* and the current time.
*
* @param type device event type
* @param device event device subject
* @param port optional port subject
*/
public DeviceEvent(Type type, Device device, Port port) {
super(type, device);
this.port = port;
}
/**
......@@ -61,10 +92,21 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
*
* @param type device event type
* @param device event device subject
* @param port optional port subject
* @param time occurrence time
*/
public DeviceEvent(Type type, Device device, long time) {
public DeviceEvent(Type type, Device device, Port port, long time) {
super(type, device, time);
this.port = port;
}
/**
* Returns the port subject.
*
* @return port subject or null if the event is not port specific.
*/
Port port() {
return port;
}
}
......
......@@ -3,9 +3,13 @@ package org.onlab.onos.net.device;
import org.junit.Test;
import org.onlab.onos.event.AbstractEventTest;
import org.onlab.onos.net.DefaultDevice;
import org.onlab.onos.net.DefaultPort;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.provider.ProviderId;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.DeviceId.deviceId;
/**
......@@ -21,17 +25,19 @@ public class DeviceEventTest extends AbstractEventTest {
@Test
public void withTime() {
Device device = createDevice();
Port port = new DefaultPort(device, PortNumber.portNumber(123L), true);
DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED,
device, 123L);
device, port, 123L);
validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, 123L);
assertEquals("incorrect port", port, event.port());
}
@Test
public void withoutTime() {
Device device = createDevice();
Port port = new DefaultPort(device, PortNumber.portNumber(123L), true);
long before = System.currentTimeMillis();
DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED,
device);
DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
long after = System.currentTimeMillis();
validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, before, after);
}
......
package org.onlab.onos.net.trivial.impl;
import org.onlab.onos.net.DefaultDevice;
import org.onlab.onos.net.DefaultPort;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
......@@ -13,7 +14,9 @@ import org.onlab.onos.net.provider.ProviderId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
......@@ -21,18 +24,19 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_MASTERSHIP_CHANGED;
import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_REMOVED;
import static org.onlab.onos.net.device.DeviceEvent.Type.*;
/**
* Manages inventory of infrastructure devices.
*/
class SimpleDeviceStore {
public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
private final Map<DeviceId, DefaultDevice> devices = new ConcurrentHashMap<>();
private final Map<DeviceId, MastershipRole> roles = new ConcurrentHashMap<>();
private final Set<DeviceId> availableDevices = new HashSet<>();
private final Map<DeviceId, Map<PortNumber, Port>> devicePorts = new HashMap<>();
/**
* Returns an iterable collection of all devices known to the system.
......@@ -82,7 +86,7 @@ class SimpleDeviceStore {
devices.put(deviceId, device);
availableDevices.add(deviceId);
}
return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null);
}
// Updates the device and returns the appropriate event if necessary.
......@@ -101,13 +105,14 @@ class SimpleDeviceStore {
devices.put(device.id(), updated);
availableDevices.add(device.id());
}
return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, device);
return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, device, null);
}
// Otherwise merely attempt to change availability
synchronized (this) {
boolean added = availableDevices.add(device.id());
return added ? new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device) : null;
return !added ? null :
new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null);
}
}
......@@ -120,9 +125,10 @@ class SimpleDeviceStore {
DeviceEvent markOffline(DeviceId deviceId) {
synchronized (this) {
Device device = devices.get(deviceId);
checkArgument(device != null, "Device with ID %s is not found", deviceId);
checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
boolean removed = availableDevices.remove(deviceId);
return removed ? new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device) : null;
return !removed ? null :
new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null);
}
}
......@@ -136,7 +142,79 @@ class SimpleDeviceStore {
*/
List<DeviceEvent> updatePorts(DeviceId deviceId,
List<PortDescription> portDescriptions) {
return new ArrayList<>();
List<DeviceEvent> events = new ArrayList<>();
synchronized (this) {
Device device = devices.get(deviceId);
checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
Map<PortNumber, Port> ports = getPortMap(deviceId);
// Add new ports
Set<PortNumber> processed = new HashSet<>();
for (PortDescription portDescription : portDescriptions) {
Port port = ports.get(portDescription.portNumber());
DeviceEvent event = port == null ?
createPort(device, portDescription, ports) :
updatePort(device, port, portDescription, ports);
processed.add(portDescription.portNumber());
}
events.addAll(pruneOldPorts(device, ports, processed));
}
return events;
}
// Creates a new port based on the port description adds it to the map and
// Returns corresponding event.
private DeviceEvent createPort(Device device, PortDescription portDescription,
Map<PortNumber, Port> ports) {
DefaultPort port = new DefaultPort(device, portDescription.portNumber(),
portDescription.isEnabled());
ports.put(port.number(), port);
return new DeviceEvent(PORT_ADDED, device, port);
}
// CHecks if the specified port requires update and if so, it replaces the
// existing entry in the map and returns corresponding event.
private DeviceEvent updatePort(Device device, Port port,
PortDescription portDescription,
Map<PortNumber, Port> ports) {
if (port.isEnabled() != portDescription.isEnabled()) {
DefaultPort updatedPort =
new DefaultPort(device, portDescription.portNumber(),
portDescription.isEnabled());
ports.put(port.number(), updatedPort);
return new DeviceEvent(PORT_UPDATED, device, port);
}
return null;
}
// Prunes the specified list of ports based on which ports are in the
// processed list and returns list of corresponding events.
private List<DeviceEvent> pruneOldPorts(Device device,
Map<PortNumber, Port> ports,
Set<PortNumber> processed) {
List<DeviceEvent> events = new ArrayList<>();
Iterator<PortNumber> iterator = ports.keySet().iterator();
while (iterator.hasNext()) {
PortNumber portNumber = iterator.next();
if (processed.contains(portNumber)) {
events.add(new DeviceEvent(PORT_REMOVED, device,
ports.get(portNumber)));
iterator.remove();
}
}
return events;
}
// Gets the map of ports for the specified device; if one does not already
// exist, it creates and registers a new one.
private Map<PortNumber, Port> getPortMap(DeviceId deviceId) {
Map<PortNumber, Port> ports = devicePorts.get(deviceId);
if (ports == null) {
ports = new HashMap<>();
devicePorts.put(deviceId, ports);
}
return ports;
}
/**
......@@ -194,9 +272,10 @@ class SimpleDeviceStore {
DeviceEvent setRole(DeviceId deviceId, MastershipRole role) {
synchronized (this) {
Device device = getDevice(deviceId);
checkArgument(device != null, "Device with ID %s not found");
checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
MastershipRole oldRole = roles.put(deviceId, role);
return oldRole == role ? null : new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device);
return oldRole == role ? null :
new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device, null);
}
}
......@@ -209,7 +288,9 @@ class SimpleDeviceStore {
synchronized (this) {
roles.remove(deviceId);
Device device = devices.remove(deviceId);
return device != null ? new DeviceEvent(DEVICE_REMOVED, device) : null;
return device == null ? null :
new DeviceEvent(DEVICE_REMOVED, device, null);
}
}
}
......
......@@ -24,6 +24,8 @@ import org.projectfloodlight.openflow.types.*;
import org.projectfloodlight.openflow.util.*;
import org.projectfloodlight.openflow.exceptions.*;
import org.jboss.netty.buffer.ChannelBuffer;
import java.nio.ByteBuffer;
import java.util.Set;
abstract class OFActionBsnVer13 {
......@@ -36,7 +38,7 @@ abstract class OFActionBsnVer13 {
static class Reader implements OFMessageReader<OFActionBsn> {
@Override
public OFActionBsn readFrom(ChannelBuffer bb) throws OFParseError {
public OFActionBsn readFrom(ByteBuffer bb) throws OFParseError {
if(bb.readableBytes() < MINIMUM_LENGTH)
return null;
int start = bb.readerIndex();
......