tom

Adding port, port number, port description implementations and related tests.

......@@ -5,16 +5,29 @@ import java.net.URI;
/**
* Immutable representation of a device identity.
*/
public class DeviceId extends ElementId {
public final class DeviceId extends ElementId {
// Public construction is prohibited
private DeviceId(URI uri) {
super(uri);
}
// TODO: Discuss whether we should just use ElementId for Device and Host alike
/**
* Creates a device id using the supplied URI.
*
* @param uri backing device URI
* @param uri device URI
*/
public DeviceId(URI uri) {
super(uri);
public static DeviceId deviceId(URI uri) {
return new DeviceId(uri);
}
/**
* Creates a device id using the supplied URI string.
*
* @param string device URI string
*/
public static DeviceId deviceId(String string) {
return new DeviceId(URI.create(string));
}
}
......
......@@ -8,7 +8,7 @@ import static com.google.common.base.Objects.toStringHelper;
/**
* Immutable representation of a network element identity.
*/
public class ElementId {
public abstract class ElementId {
private final URI uri;
......@@ -17,7 +17,7 @@ public class ElementId {
*
* @param uri backing URI
*/
public ElementId(URI uri) {
protected ElementId(URI uri) {
this.uri = uri;
}
......@@ -37,14 +37,12 @@ public class ElementId {
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
if (obj instanceof ElementId) {
final ElementId that = (ElementId) obj;
return this.getClass() == that.getClass() &&
Objects.equals(this.uri, that.uri);
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final ElementId other = (ElementId) obj;
return Objects.equals(this.uri, other.uri);
return false;
}
@Override
......
package org.onlab.onos.net;
import java.util.Set;
/**
* Abstraction of a network port.
*/
public interface Port {
// Notion of port state: enabled, disabled, blocked
/**
* Port state.
*/
enum State {
UP, DOWN, BLOCKED, UNKNOWN
}
/**
* Returns the port number.
......@@ -15,6 +22,27 @@ public interface Port {
PortNumber number();
/**
* Returns the port state(s).
*
* @return port state set
*/
Set<State> state();
/**
* Indicates whether or not the port is currently up and active.
*
* @return true if the port is operational
*/
boolean isEnabled();
/**
* Indicates whether or not the port is administratively blocked.
*
* @return true if the port is blocked
*/
boolean isBlocked();
/**
* Returns the identifier of the network element to which this port belongs.
*
* @return parent network element
......
package org.onlab.onos.net;
import com.google.common.primitives.UnsignedLongs;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Representation of a port number.
*/
public interface PortNumber {
public final class PortNumber {
private static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1;
private final long number;
// Public creation is prohibited
private PortNumber(long number) {
checkArgument(number >= 0 && number < MAX_NUMBER,
"Port number %d is outside the supported range [0, %d)",
number, MAX_NUMBER);
this.number = number;
}
/**
* Returns the port number representing the specified long value.
*
* @param number port number as long value
* @return port number
*/
public static PortNumber portNumber(long number) {
return new PortNumber(number);
}
/**
* Returns the port number representing the specified string value.
*
* @param string port number as string value
* @return port number
*/
public static PortNumber portNumber(String string) {
return new PortNumber(UnsignedLongs.decode(string));
}
/**
* Returns the backing long value.
*
* @return port number as long
*/
public long toLong() {
return number;
}
@Override
public String toString() {
return UnsignedLongs.toString(number);
}
@Override
public int hashCode() {
return Objects.hash(number);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof PortNumber) {
final PortNumber other = (PortNumber) obj;
return this.number == other.number;
}
return false;
}
}
......
package org.onlab.onos.net.device;
import com.google.common.collect.ImmutableSet;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import java.util.Set;
/**
* Default implementation of immutable port description.
*/
public class DefaultPortDescription implements PortDescription {
private final PortNumber number;
private final Set<Port.State> state;
public DefaultPortDescription(PortNumber number, Set<Port.State> state) {
this.number = number;
this.state = ImmutableSet.copyOf(state);
}
@Override
public PortNumber portNumber() {
return number;
}
@Override
public Set<Port.State> portState() {
return state;
}
}
......
package org.onlab.onos.net.device;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import java.util.Set;
/**
* Information about a port.
*/
......@@ -7,4 +12,18 @@ public interface PortDescription {
// TODO: possibly relocate this to a common ground so that this can also used by host tracking if required
/**
* Returns the port number.
*
* @return port number
*/
PortNumber portNumber();
/**
* Returns the port state set.
*
* @return set of port states
*/
Set<Port.State> portState();
}
......
......@@ -11,12 +11,46 @@ import static org.onlab.onos.event.TestEvent.Type.FOO;
*/
public class AbstractEventTest {
/**
* Validates the base attributes of an event.
*
* @param event event to validate
* @param type event type
* @param subject event subject
* @param time event time
* @param <T> type of event
* @param <S> type of subject
*/
protected static <T extends Enum, S>
void validateEvent(Event<T, S> event, T type, S subject, long time) {
assertEquals("incorrect type", type, event.type());
assertEquals("incorrect subject", subject, event.subject());
assertEquals("incorrect time", time, event.time());
}
/**
* Validates the base attributes of an event.
*
* @param event event to validate
* @param type event type
* @param subject event subject
* @param minTime minimum event time inclusive
* @param maxTime maximum event time inclusive
* @param <T> type of event
* @param <S> type of subject
*/
protected static <T extends Enum, S>
void validateEvent(Event<T, S> event, T type, S subject,
long minTime, long maxTime) {
assertEquals("incorrect type", type, event.type());
assertEquals("incorrect subject", subject, event.subject());
assertTrue("incorrect time", minTime <= event.time() && event.time() <= maxTime);
}
@Test
public void withTime() {
TestEvent event = new TestEvent(FOO, "foo", 123L);
assertEquals("incorrect type", FOO, event.type());
assertEquals("incorrect subject", "foo", event.subject());
assertEquals("incorrect time", 123L, event.time());
validateEvent(event, FOO, "foo", 123L);
}
@Test
......@@ -24,8 +58,7 @@ public class AbstractEventTest {
long before = System.currentTimeMillis();
TestEvent event = new TestEvent(FOO, "foo");
long after = System.currentTimeMillis();
assertEquals("incorrect type", FOO, event.type());
assertEquals("incorrect subject", "foo", event.subject());
assertTrue("incorrect time", before <= event.time() && event.time() <= after);
validateEvent(event, FOO, "foo", before, after);
}
}
......
......@@ -4,10 +4,9 @@ import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onlab.onos.net.provider.ProviderId;
import java.net.URI;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.Device.Type.SWITCH;
import static org.onlab.onos.net.DeviceId.deviceId;
/**
* Test of the default device model entity.
......@@ -15,8 +14,8 @@ import static org.onlab.onos.net.Device.Type.SWITCH;
public class DefaultDeviceTest {
private static final ProviderId PID = new ProviderId("foo");
private static final DeviceId DID1 = new DeviceId(URI.create("of:foo"));
private static final DeviceId DID2 = new DeviceId(URI.create("of:bar"));
private static final DeviceId DID1 = deviceId("of:foo");
private static final DeviceId DID2 = deviceId("of:bar");
private static final String MFR = "whitebox";
private static final String HW = "1.1.x";
private static final String SW = "3.9.1";
......
......@@ -3,17 +3,19 @@ package org.onlab.onos.net;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import static org.onlab.onos.net.DeviceId.deviceId;
/**
* Test of the provider identifier.
* Test of the device identifier.
*/
public class DeviceIdTest extends ElementIdTest {
@Test
public void basics() {
new EqualsTester()
.addEqualityGroup(new DeviceId(uri("of:foo")),
new DeviceId(uri("of:foo")))
.addEqualityGroup(new DeviceId(uri("of:bar")))
.addEqualityGroup(deviceId("of:foo"),
deviceId("of:foo"))
.addEqualityGroup(deviceId("of:bar"))
.testEquals();
}
......
......@@ -8,10 +8,16 @@ import java.net.URI;
import static org.junit.Assert.assertEquals;
/**
* Test of the provider identifier.
* Test of the network element identifier.
*/
public class ElementIdTest {
private static class FooId extends ElementId {
public FooId(URI uri) {
super(uri);
}
}
public static URI uri(String str) {
return URI.create(str);
}
......@@ -19,12 +25,12 @@ public class ElementIdTest {
@Test
public void basics() {
new EqualsTester()
.addEqualityGroup(new ElementId(uri("of:foo")),
new ElementId(uri("of:foo")))
.addEqualityGroup(new ElementId(uri("of:bar")))
.addEqualityGroup(new FooId(uri("of:foo")),
new FooId(uri("of:foo")))
.addEqualityGroup(new FooId(uri("of:bar")))
.testEquals();
assertEquals("wrong uri", uri("ofcfg:foo"),
new ElementId(uri("ofcfg:foo")).uri());
new FooId(uri("ofcfg:foo")).uri());
}
}
......
package org.onlab.onos.net;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.PortNumber.portNumber;
/**
* Test of the port number.
*/
public class PortNumberTest extends ElementIdTest {
@Test
public void basics() {
new EqualsTester()
.addEqualityGroup(portNumber(123),
portNumber("123"))
.addEqualityGroup(portNumber(321))
.testEquals();
}
@Test
public void number() {
assertEquals("incorrect long value", 12345, portNumber(12345).toLong());
}
@Test(expected = IllegalArgumentException.class)
public void negative() {
portNumber(-1);
}
@Test(expected = IllegalArgumentException.class)
public void tooBig() {
portNumber((2L * Integer.MAX_VALUE) + 2);
}
}
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.Device;
import org.onlab.onos.net.provider.ProviderId;
import static org.onlab.onos.net.DeviceId.deviceId;
/**
* Tests of the device event.
*/
public class DeviceEventTest extends AbstractEventTest {
private Device createDevice() {
return new DefaultDevice(new ProviderId("foo"), deviceId("of:foo"),
Device.Type.SWITCH, "box", "hw", "sw", "sn");
}
@Test
public void withTime() {
Device device = createDevice();
DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED,
device, 123L);
validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, 123L);
}
@Test
public void withoutTime() {
Device device = createDevice();
long before = System.currentTimeMillis();
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.provider.of.device.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.net.URI;
import java.net.URISyntaxException;
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.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.device.DefaultDeviceDescription;
import org.onlab.onos.net.device.DeviceDescription;
......@@ -27,6 +21,12 @@ import org.onlab.onos.of.controller.OpenFlowSwitchListener;
import org.onlab.onos.of.controller.RoleState;
import org.slf4j.Logger;
import java.net.URI;
import java.net.URISyntaxException;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider which uses an OpenFlow controller to detect network
* infrastructure devices.
......@@ -73,19 +73,19 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
@Override
public void roleChanged(Device device, MastershipRole newRole) {
switch (newRole) {
case MASTER:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.MASTER);
break;
case STANDBY:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.EQUAL);
case NONE:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.SLAVE);
break;
default:
log.error("Unknown Mastership state : {}", newRole);
case MASTER:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.MASTER);
break;
case STANDBY:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.EQUAL);
case NONE:
controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
RoleState.SLAVE);
break;
default:
log.error("Unknown Mastership state : {}", newRole);
}
log.info("Accepting mastership role change for device {}", device.id());
......@@ -102,11 +102,11 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
DeviceDescription description =
new DefaultDeviceDescription(buildURI(dpid), Device.Type.SWITCH,
sw.manfacturerDescription(),
sw.hardwareDescription(),
sw.softwareDescription(),
sw.softwareDescription());
providerService.deviceConnected(new DeviceId(uri), description);
sw.manfacturerDescription(),
sw.hardwareDescription(),
sw.softwareDescription(),
sw.softwareDescription());
providerService.deviceConnected(deviceId(uri), description);
}
@Override
......@@ -115,7 +115,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
return;
}
URI uri = buildURI(dpid);
providerService.deviceDisconnected(new DeviceId(uri));
providerService.deviceDisconnected(deviceId(uri));
}
private URI buildURI(Dpid dpid) {
......