Ayaka Koshibe

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Conflicts:
	core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoPoolUtil.java

Change-Id: I6a8fc884f0c0b6578762d7b439177378e838735f
Showing 75 changed files with 1479 additions and 1123 deletions
......@@ -16,4 +16,11 @@
<description>ONOS simple reactive forwarding app</description>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
</dependencies>
</project>
......
package org.onlab.onos.fwd;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Set;
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.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
......@@ -29,8 +27,14 @@ import org.onlab.onos.net.packet.PacketProcessor;
import org.onlab.onos.net.packet.PacketService;
import org.onlab.onos.net.topology.TopologyService;
import org.onlab.packet.Ethernet;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Dictionary;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Sample reactive forwarding application.
*/
......@@ -61,6 +65,10 @@ public class ReactiveForwarding {
private ApplicationId appId;
@Property(name = "enabled", boolValue = true,
label = "Enable forwarding; default is true")
private boolean isEnabled = true;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.fwd");
......@@ -76,6 +84,22 @@ public class ReactiveForwarding {
log.info("Stopped");
}
@Modified
public void modified(ComponentContext context) {
Dictionary properties = context.getProperties();
String flag = (String) properties.get("enabled");
if (flag != null) {
boolean enabled = flag.equals("true");
if (isEnabled != enabled) {
isEnabled = enabled;
if (!isEnabled) {
flowRuleService.removeFlowRulesById(appId);
}
log.info("Reconfigured. Forwarding is {}",
isEnabled ? "enabled" : "disabled");
}
}
}
/**
* Packet processor responsible for forwarding packets along their paths.
......@@ -86,7 +110,7 @@ public class ReactiveForwarding {
public void process(PacketContext context) {
// Stop processing if the packet has been handled, since we
// can't do any more to it.
if (context.isHandled()) {
if (!isEnabled || context.isHandled()) {
return;
}
......@@ -114,8 +138,8 @@ public class ReactiveForwarding {
// Otherwise, get a set of paths that lead from here to the
// destination edge switch.
Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
pkt.receivedFrom().deviceId(),
dst.location().deviceId());
pkt.receivedFrom().deviceId(),
dst.location().deviceId());
if (paths.isEmpty()) {
// If there are no paths, flood and bail.
flood(context);
......@@ -127,8 +151,8 @@ public class ReactiveForwarding {
Path path = pickForwardPath(paths, pkt.receivedFrom().port());
if (path == null) {
log.warn("Doh... don't know where to go... {} -> {} received on {}",
ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
pkt.receivedFrom());
ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
pkt.receivedFrom());
flood(context);
return;
}
......@@ -152,7 +176,7 @@ public class ReactiveForwarding {
// Floods the specified packet if permissible.
private void flood(PacketContext context) {
if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
context.inPacket().receivedFrom())) {
context.inPacket().receivedFrom())) {
packetOut(context, PortNumber.FLOOD);
} else {
context.block();
......@@ -174,18 +198,17 @@ public class ReactiveForwarding {
Ethernet inPkt = context.inPacket().parsed();
TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
builder.matchEthType(inPkt.getEtherType())
.matchEthSrc(inPkt.getSourceMAC())
.matchEthDst(inPkt.getDestinationMAC())
.matchInport(context.inPacket().receivedFrom().port());
.matchEthSrc(inPkt.getSourceMAC())
.matchEthDst(inPkt.getDestinationMAC())
.matchInport(context.inPacket().receivedFrom().port());
TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
treat.setOutput(portNumber);
FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
flowRuleService.applyFlowRules(f);
}
}
......
......@@ -36,6 +36,12 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-thirdparty</artifactId>
</dependency>
</dependencies>
</project>
......
......@@ -126,8 +126,8 @@ public class PeerConnectivity {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpDst(BGP_PORT)
.build();
......@@ -147,8 +147,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpSrc(BGP_PORT)
.build();
......@@ -165,8 +165,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpDst(BGP_PORT)
.build();
......@@ -183,8 +183,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpSrc(BGP_PORT)
.build();
......@@ -251,8 +251,8 @@ public class PeerConnectivity {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
......@@ -269,8 +269,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.build();
PointToPointIntent reversedIntent = new PointToPointIntent(
......
package org.onlab.onos.sdnip;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import com.google.common.base.MoreObjects;
/**
* Represents a route entry for an IP prefix.
*/
public class RouteEntry {
private final IpPrefix prefix; // The IP prefix
private final IpAddress nextHop; // Next-hop IP address
/**
* Class constructor.
*
* @param prefix the IP prefix of the route
* @param nextHop the next hop IP address for the route
*/
public RouteEntry(IpPrefix prefix, IpAddress nextHop) {
this.prefix = checkNotNull(prefix);
this.nextHop = checkNotNull(nextHop);
}
/**
* Returns the IP prefix of the route.
*
* @return the IP prefix of the route
*/
public IpPrefix prefix() {
return prefix;
}
/**
* Returns the next hop IP address for the route.
*
* @return the next hop IP address for the route
*/
public IpAddress nextHop() {
return nextHop;
}
/**
* Creates the binary string representation of an IPv4 prefix.
* The string length is equal to the prefix length.
*
* @param ip4Prefix the IPv4 prefix to use
* @return the binary string representation
*/
static String createBinaryString(IpPrefix ip4Prefix) {
if (ip4Prefix.prefixLength() == 0) {
return "";
}
StringBuilder result = new StringBuilder(ip4Prefix.prefixLength());
long value = ip4Prefix.toInt();
for (int i = 0; i < ip4Prefix.prefixLength(); i++) {
long mask = 1 << (IpAddress.MAX_INET_MASK - 1 - i);
result.append(((value & mask) == 0) ? "0" : "1");
}
return result.toString();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
//
// NOTE: Subclasses are considered as change of identity, hence
// equals() will return false if the class type doesn't match.
//
if (other == null || getClass() != other.getClass()) {
return false;
}
RouteEntry otherRoute = (RouteEntry) other;
return Objects.equals(this.prefix, otherRoute.prefix) &&
Objects.equals(this.nextHop, otherRoute.nextHop);
}
@Override
public int hashCode() {
return Objects.hash(prefix, nextHop);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("prefix", prefix)
.add("nextHop", nextHop)
.toString();
}
}
package org.onlab.onos.sdnip;
/**
* An interface to receive route updates from route providers.
*/
public interface RouteListener {
/**
* Receives a route update from a route provider.
*
* @param routeUpdate the updated route information
*/
public void update(RouteUpdate routeUpdate);
}
package org.onlab.onos.sdnip;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import com.google.common.base.MoreObjects;
/**
* Represents a change in routing information.
*/
public class RouteUpdate {
private final Type type; // The route update type
private final RouteEntry routeEntry; // The updated route entry
/**
* Specifies the type of a route update.
* <p/>
* Route updates can either provide updated information for a route, or
* withdraw a previously updated route.
*/
public enum Type {
/**
* The update contains updated route information for a route.
*/
UPDATE,
/**
* The update withdraws the route, meaning any previous information is
* no longer valid.
*/
DELETE
}
/**
* Class constructor.
*
* @param type the type of the route update
* @param routeEntry the route entry with the update
*/
public RouteUpdate(Type type, RouteEntry routeEntry) {
this.type = type;
this.routeEntry = checkNotNull(routeEntry);
}
/**
* Returns the type of the route update.
*
* @return the type of the update
*/
public Type type() {
return type;
}
/**
* Returns the route entry the route update is for.
*
* @return the route entry the route update is for
*/
public RouteEntry routeEntry() {
return routeEntry;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof RouteUpdate)) {
return false;
}
RouteUpdate otherUpdate = (RouteUpdate) other;
return Objects.equals(this.type, otherUpdate.type) &&
Objects.equals(this.routeEntry, otherUpdate.routeEntry);
}
@Override
public int hashCode() {
return Objects.hash(type, routeEntry);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("type", type)
.add("routeEntry", routeEntry)
.toString();
}
}
This diff is collapsed. Click to expand it.
......@@ -9,7 +9,11 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.sdnip.RouteUpdate.Type;
import org.onlab.onos.sdnip.bgp.BgpSessionManager;
import org.onlab.onos.sdnip.config.SdnIpConfigReader;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.slf4j.Logger;
/**
......@@ -28,6 +32,8 @@ public class SdnIp {
private SdnIpConfigReader config;
private PeerConnectivity peerConnectivity;
private Router router;
private BgpSessionManager bgpSessionManager;
@Activate
protected void activate() {
......@@ -41,6 +47,17 @@ public class SdnIp {
peerConnectivity = new PeerConnectivity(config, interfaceService, intentService);
peerConnectivity.start();
router = new Router(intentService, hostService, config, interfaceService);
router.start();
bgpSessionManager = new BgpSessionManager(router);
bgpSessionManager.startUp(2000); // TODO
// TODO need to disable link discovery on external ports
router.update(new RouteUpdate(Type.UPDATE, new RouteEntry(
IpPrefix.valueOf("172.16.20.0/24"),
IpAddress.valueOf("192.168.10.1"))));
}
@Deactivate
......
package org.onlab.onos.sdnip.bgp;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class for handling the decoding of the BGP messages.
*/
class BgpFrameDecoder extends FrameDecoder {
private static final Logger log =
LoggerFactory.getLogger(BgpFrameDecoder.class);
private final BgpSession bgpSession;
/**
* Constructor for a given BGP Session.
*
* @param bgpSession the BGP session state to use.
*/
BgpFrameDecoder(BgpSession bgpSession) {
this.bgpSession = bgpSession;
}
@Override
protected Object decode(ChannelHandlerContext ctx,
Channel channel,
ChannelBuffer buf) throws Exception {
//
// NOTE: If we close the channel during the decoding, we might still
// see some incoming messages while the channel closing is completed.
//
if (bgpSession.isClosed()) {
return null;
}
log.trace("BGP Peer: decode(): remoteAddr = {} localAddr = {} " +
"messageSize = {}",
ctx.getChannel().getRemoteAddress(),
ctx.getChannel().getLocalAddress(),
buf.readableBytes());
// Test for minimum length of the BGP message
if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
// No enough data received
return null;
}
//
// Mark the current buffer position in case we haven't received
// the whole message.
//
buf.markReaderIndex();
//
// Read and check the BGP message Marker field: it must be all ones
// (See RFC 4271, Section 4.1)
//
byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
buf.readBytes(marker);
for (int i = 0; i < marker.length; i++) {
if (marker[i] != (byte) 0xff) {
log.debug("BGP RX Error: invalid marker {} at position {}",
marker[i], i);
//
// ERROR: Connection Not Synchronized
//
// Send NOTIFICATION and close the connection
int errorCode = MessageHeaderError.ERROR_CODE;
int errorSubcode =
MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED;
ChannelBuffer txMessage =
bgpSession.prepareBgpNotification(errorCode, errorSubcode,
null);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
}
//
// Read and check the BGP message Length field
//
int length = buf.readUnsignedShort();
if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
(length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
log.debug("BGP RX Error: invalid Length field {}. " +
"Must be between {} and {}",
length,
BgpConstants.BGP_HEADER_LENGTH,
BgpConstants.BGP_MESSAGE_MAX_LENGTH);
//
// ERROR: Bad Message Length
//
// Send NOTIFICATION and close the connection
ChannelBuffer txMessage =
bgpSession.prepareBgpNotificationBadMessageLength(length);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
//
// Test whether the rest of the message is received:
// So far we have read the Marker (16 octets) and the
// Length (2 octets) fields.
//
int remainingMessageLen =
length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
if (buf.readableBytes() < remainingMessageLen) {
// No enough data received
buf.resetReaderIndex();
return null;
}
//
// Read the BGP message Type field, and process based on that type
//
int type = buf.readUnsignedByte();
remainingMessageLen--; // Adjust after reading the type
ChannelBuffer message = buf.readBytes(remainingMessageLen);
//
// Process the remaining of the message based on the message type
//
switch (type) {
case BgpConstants.BGP_TYPE_OPEN:
bgpSession.processBgpOpen(ctx, message);
break;
case BgpConstants.BGP_TYPE_UPDATE:
bgpSession.processBgpUpdate(ctx, message);
break;
case BgpConstants.BGP_TYPE_NOTIFICATION:
bgpSession.processBgpNotification(ctx, message);
break;
case BgpConstants.BGP_TYPE_KEEPALIVE:
bgpSession.processBgpKeepalive(ctx, message);
break;
default:
//
// ERROR: Bad Message Type
//
// Send NOTIFICATION and close the connection
int errorCode = MessageHeaderError.ERROR_CODE;
int errorSubcode = MessageHeaderError.BAD_MESSAGE_TYPE;
ChannelBuffer data = ChannelBuffers.buffer(1);
data.writeByte(type);
ChannelBuffer txMessage =
bgpSession.prepareBgpNotification(errorCode, errorSubcode,
data);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
return null;
}
}
/**
* Implementation of the BGP protocol.
*/
package org.onlab.onos.sdnip.bgp;
\ No newline at end of file
package org.onlab.onos.sdnip;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
/**
* Unit tests for the RouteEntry class.
*/
public class RouteEntryTest {
/**
* Tests valid class constructor.
*/
@Test
public void testConstructor() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
}
/**
* Tests invalid class constructor for null IPv4 prefix.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullPrefix() {
IpPrefix prefix = null;
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
new RouteEntry(prefix, nextHop);
}
/**
* Tests invalid class constructor for null IPv4 next-hop.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullNextHop() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = null;
new RouteEntry(prefix, nextHop);
}
/**
* Tests getting the fields of a route entry.
*/
@Test
public void testGetFields() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.prefix(), is(prefix));
assertThat(routeEntry.nextHop(), is(nextHop));
}
/**
* Tests creating a binary string from IPv4 prefix.
*/
@Test
public void testCreateBinaryString() {
IpPrefix prefix;
prefix = IpPrefix.valueOf("0.0.0.0/0");
assertThat(RouteEntry.createBinaryString(prefix), is(""));
prefix = IpPrefix.valueOf("192.168.166.0/22");
assertThat(RouteEntry.createBinaryString(prefix),
is("1100000010101000101001"));
prefix = IpPrefix.valueOf("192.168.166.0/23");
assertThat(RouteEntry.createBinaryString(prefix),
is("11000000101010001010011"));
prefix = IpPrefix.valueOf("192.168.166.0/24");
assertThat(RouteEntry.createBinaryString(prefix),
is("110000001010100010100110"));
prefix = IpPrefix.valueOf("130.162.10.1/25");
assertThat(RouteEntry.createBinaryString(prefix),
is("1000001010100010000010100"));
prefix = IpPrefix.valueOf("255.255.255.255/32");
assertThat(RouteEntry.createBinaryString(prefix),
is("11111111111111111111111111111111"));
}
/**
* Tests equality of {@link RouteEntry}.
*/
@Test
public void testEquality() {
IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
assertThat(routeEntry1, is(routeEntry2));
}
/**
* Tests non-equality of {@link RouteEntry}.
*/
@Test
public void testNonEquality() {
IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/25"); // Different
IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
IpPrefix prefix3 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop3 = IpAddress.valueOf("5.6.7.9"); // Different
RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3);
assertThat(routeEntry1, is(not(routeEntry2)));
assertThat(routeEntry1, is(not(routeEntry3)));
}
/**
* Tests object string representation.
*/
@Test
public void testToString() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
}
}
......@@ -26,6 +26,16 @@
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-osgi</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>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
......
package org.onlab.onos.cli;
import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceNotFoundException;
......@@ -9,6 +10,10 @@ import org.onlab.osgi.ServiceNotFoundException;
*/
public abstract class AbstractShellCommand extends OsgiCommandSupport {
@Option(name = "-j", aliases = "--json", description = "Output JSON",
required = false, multiValued = false)
private boolean json = false;
/**
* Returns the reference to the implementation of the specified service.
*
......@@ -46,6 +51,15 @@ public abstract class AbstractShellCommand extends OsgiCommandSupport {
*/
protected abstract void execute();
/**
* Indicates whether JSON format should be output.
*
* @return true if JSON is requested
*/
protected boolean outputJson() {
return json;
}
@Override
protected Object doExecute() throws Exception {
try {
......
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.cluster.ControllerNode;
......@@ -26,15 +28,50 @@ public class MastersListCommand extends AbstractShellCommand {
MastershipService mastershipService = get(MastershipService.class);
List<ControllerNode> nodes = newArrayList(service.getNodes());
Collections.sort(nodes, Comparators.NODE_COMPARATOR);
if (outputJson()) {
print("%s", json(service, mastershipService, nodes));
} else {
for (ControllerNode node : nodes) {
List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id()));
Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR);
print("%s: %d devices", node.id(), ids.size());
for (DeviceId deviceId : ids) {
print(" %s", deviceId);
}
}
}
}
// Produces JSON structure.
private JsonNode json(ClusterService service, MastershipService mastershipService,
List<ControllerNode> nodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id()));
Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR);
print("%s: %d devices", node.id(), ids.size());
for (DeviceId deviceId : ids) {
print(" %s", deviceId);
}
result.add(mapper.createObjectNode()
.put("id", node.id().toString())
.put("size", ids.size())
.set("devices", json(mapper, ids)));
}
return result;
}
/**
* Produces a JSON array containing the specified device identifiers.
*
* @param mapper object mapper
* @param ids collection of device identifiers
* @return JSON array
*/
public static JsonNode json(ObjectMapper mapper, Iterable<DeviceId> ids) {
ArrayNode result = mapper.createArrayNode();
for (DeviceId deviceId : ids) {
result.add(deviceId.toString());
}
return result;
}
}
......
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.cluster.ControllerNode;
......@@ -24,12 +27,32 @@ public class NodesListCommand extends AbstractShellCommand {
ClusterService service = get(ClusterService.class);
List<ControllerNode> nodes = newArrayList(service.getNodes());
Collections.sort(nodes, Comparators.NODE_COMPARATOR);
if (outputJson()) {
print("%s", json(service, nodes));
} else {
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
print(FMT, node.id(), node.ip(), node.tcpPort(),
service.getState(node.id()),
node.equals(self) ? "*" : "");
}
}
}
// Produces JSON structure.
private JsonNode json(ClusterService service, List<ControllerNode> nodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
print(FMT, node.id(), node.ip(), node.tcpPort(),
service.getState(node.id()),
node.equals(self) ? "*" : "");
result.add(mapper.createObjectNode()
.put("id", node.id().toString())
.put("ip", node.ip().toString())
.put("tcpPort", node.tcpPort())
.put("state", service.getState(node.id()).toString())
.put("self", node.equals(self)));
}
return result;
}
}
......
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.CoreService;
import org.onlab.onos.cluster.ClusterService;
......@@ -22,18 +23,32 @@ public class SummaryCommand extends AbstractShellCommand {
protected void execute() {
TopologyService topologyService = get(TopologyService.class);
Topology topology = topologyService.currentTopology();
print("node=%s, version=%s",
get(ClusterService.class).getLocalNode().ip(),
get(CoreService.class).version().toString());
print("nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
get(ClusterService.class).getNodes().size(),
get(DeviceService.class).getDeviceCount(),
get(LinkService.class).getLinkCount(),
get(HostService.class).getHostCount(),
topologyService.getClusters(topology).size(),
topology.pathCount(),
get(FlowRuleService.class).getFlowRuleCount(),
get(IntentService.class).getIntentCount());
if (outputJson()) {
print("%s", new ObjectMapper().createObjectNode()
.put("node", get(ClusterService.class).getLocalNode().ip().toString())
.put("version", get(CoreService.class).version().toString())
.put("nodes", get(ClusterService.class).getNodes().size())
.put("devices", get(DeviceService.class).getDeviceCount())
.put("links", get(LinkService.class).getLinkCount())
.put("hosts", get(HostService.class).getHostCount())
.put("clusters", topologyService.getClusters(topology).size())
.put("paths", topology.pathCount())
.put("flows", get(FlowRuleService.class).getFlowRuleCount())
.put("intents", get(IntentService.class).getIntentCount()));
} else {
print("node=%s, version=%s",
get(ClusterService.class).getLocalNode().ip(),
get(CoreService.class).version().toString());
print("nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
get(ClusterService.class).getNodes().size(),
get(DeviceService.class).getDeviceCount(),
get(LinkService.class).getLinkCount(),
get(HostService.class).getHostCount(),
topologyService.getClusters(topology).size(),
topology.pathCount(),
get(FlowRuleService.class).getFlowRuleCount(),
get(IntentService.class).getIntentCount());
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
......@@ -10,6 +11,7 @@ import org.onlab.onos.net.topology.TopologyCluster;
import java.util.Collections;
import java.util.List;
import static org.onlab.onos.cli.MastersListCommand.json;
import static org.onlab.onos.net.topology.ClusterId.clusterId;
/**
......@@ -33,11 +35,14 @@ public class ClusterDevicesCommand extends ClustersListCommand {
} else {
List<DeviceId> ids = Lists.newArrayList(service.getClusterDevices(topology, cluster));
Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR);
for (DeviceId deviceId : ids) {
print("%s", deviceId);
if (outputJson()) {
print("%s", json(new ObjectMapper(), ids));
} else {
for (DeviceId deviceId : ids) {
print("%s", deviceId);
}
}
}
}
}
......
......@@ -5,6 +5,7 @@ import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.topology.TopologyCluster;
import static org.onlab.onos.cli.net.LinksListCommand.json;
import static org.onlab.onos.cli.net.LinksListCommand.linkString;
import static org.onlab.onos.net.topology.ClusterId.clusterId;
......@@ -26,6 +27,8 @@ public class ClusterLinksCommand extends ClustersListCommand {
TopologyCluster cluster = service.getCluster(topology, clusterId(cid));
if (cluster == null) {
error("No such cluster %s", cid);
} else if (outputJson()) {
print("%s", json(service.getClusterLinks(topology, cluster)));
} else {
for (Link link : service.getClusterLinks(topology, cluster)) {
print(linkString(link));
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.Comparators;
......@@ -24,9 +27,26 @@ public class ClustersListCommand extends TopologyCommand {
List<TopologyCluster> clusters = Lists.newArrayList(service.getClusters(topology));
Collections.sort(clusters, Comparators.CLUSTER_COMPARATOR);
if (outputJson()) {
print("%s", json(clusters));
} else {
for (TopologyCluster cluster : clusters) {
print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount());
}
}
}
// Produces a JSON result.
private JsonNode json(Iterable<TopologyCluster> clusters) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (TopologyCluster cluster : clusters) {
print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount());
result.add(mapper.createObjectNode()
.put("id", cluster.id().index())
.put("deviceCount", cluster.deviceCount())
.put("linkCount", cluster.linkCount()));
}
return result;
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onlab.onos.cli.Comparators;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.Port;
......@@ -22,6 +27,14 @@ public class DevicePortsListCommand extends DevicesListCommand {
private static final String FMT = " port=%s, state=%s";
@Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
required = false, multiValued = false)
private boolean enabled = false;
@Option(name = "-d", aliases = "--disabled", description = "Show only disabled ports",
required = false, multiValued = false)
private boolean disabled = false;
@Argument(index = 0, name = "uri", description = "Device ID",
required = false, multiValued = false)
String uri = null;
......@@ -30,26 +43,78 @@ public class DevicePortsListCommand extends DevicesListCommand {
protected void execute() {
DeviceService service = get(DeviceService.class);
if (uri == null) {
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
if (outputJson()) {
print("%s", jsonPorts(service, getSortedDevices(service)));
} else {
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
}
}
} else {
Device device = service.getDevice(deviceId(uri));
if (device == null) {
error("No such device %s", uri);
} else if (outputJson()) {
print("%s", jsonPorts(service, new ObjectMapper(), device));
} else {
printDevice(service, device);
}
}
}
/**
* Produces JSON array containing ports of the specified devices.
*
* @param service device service
* @param devices collection of devices
* @return JSON array
*/
public JsonNode jsonPorts(DeviceService service, Iterable<Device> devices) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(jsonPorts(service, mapper, device));
}
return result;
}
/**
* Produces JSON array containing ports of the specified device.
*
* @param service device service
* @param mapper object mapper
* @param device infrastructure devices
* @return JSON array
*/
public JsonNode jsonPorts(DeviceService service, ObjectMapper mapper, Device device) {
ObjectNode result = mapper.createObjectNode();
ArrayNode ports = mapper.createArrayNode();
for (Port port : service.getPorts(device.id())) {
if (isIncluded(port)) {
ports.add(mapper.createObjectNode()
.put("port", port.number().toString())
.put("isEnabled", port.isEnabled()));
}
}
return result.put("device", device.id().toString()).set("ports", ports);
}
// Determines if a port should be included in output.
private boolean isIncluded(Port port) {
return enabled && port.isEnabled() || disabled && !port.isEnabled() ||
!enabled && !disabled;
}
@Override
protected void printDevice(DeviceService service, Device device) {
super.printDevice(service, device);
List<Port> ports = new ArrayList<>(service.getPorts(device.id()));
Collections.sort(ports, Comparators.PORT_COMPARATOR);
for (Port port : ports) {
print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled");
if (isIncluded(port)) {
print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled");
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.cli.Comparators;
......@@ -24,12 +28,55 @@ public class DevicesListCommand extends AbstractShellCommand {
@Override
protected void execute() {
DeviceService service = get(DeviceService.class);
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
if (outputJson()) {
print("%s", json(service, getSortedDevices(service)));
} else {
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
}
}
}
/**
* Returns JSON node representing the specified devices.
*
* @param service device service
* @param devices collection of devices
* @return JSON node
*/
public static JsonNode json(DeviceService service, Iterable<Device> devices) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(json(service, mapper, device));
}
return result;
}
/**
* Returns JSON node representing the specified device.
*
* @param service device service
* @param mapper object mapper
* @param device infrastructure device
* @return JSON node
*/
public static ObjectNode json(DeviceService service, ObjectMapper mapper,
Device device) {
ObjectNode result = mapper.createObjectNode();
if (device != null) {
result.put("id", device.id().toString())
.put("available", service.isAvailable(device.id()))
.put("role", service.getRole(device.id()).toString())
.put("mfr", device.manufacturer())
.put("hw", device.hwVersion())
.put("sw", device.swVersion())
.put("serial", device.serialNumber());
}
return result;
}
/**
* Returns the list of devices sorted using the device ID URIs.
*
* @param service device service
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
......@@ -12,6 +16,8 @@ import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import java.util.Collections;
import java.util.List;
......@@ -48,9 +54,73 @@ public class FlowsListCommand extends AbstractShellCommand {
DeviceService deviceService = get(DeviceService.class);
FlowRuleService service = get(FlowRuleService.class);
Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service);
for (Device d : getSortedDevices(deviceService)) {
printFlows(d, flows.get(d), coreService);
if (outputJson()) {
print("%s", json(coreService, getSortedDevices(deviceService), flows));
} else {
for (Device d : getSortedDevices(deviceService)) {
printFlows(d, flows.get(d), coreService);
}
}
}
/**
* Produces a JSON array of flows grouped by the each device.
*
* @param coreService core service
* @param devices collection of devices to group flow by
* @param flows collection of flows per each device
* @return JSON array
*/
private JsonNode json(CoreService coreService, Iterable<Device> devices,
Map<Device, List<FlowEntry>> flows) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(json(coreService, mapper, device, flows.get(device)));
}
return result;
}
// Produces JSON object with the flows of the given device.
private ObjectNode json(CoreService coreService, ObjectMapper mapper,
Device device, List<FlowEntry> flows) {
ObjectNode result = mapper.createObjectNode();
ArrayNode array = mapper.createArrayNode();
for (FlowEntry flow : flows) {
array.add(json(coreService, mapper, flow));
}
result.put("device", device.id().toString())
.put("flowCount", flows.size())
.put("flows", array);
return result;
}
// Produces JSON structure with the specified flow data.
private ObjectNode json(CoreService coreService, ObjectMapper mapper,
FlowEntry flow) {
ObjectNode result = mapper.createObjectNode();
ArrayNode crit = mapper.createArrayNode();
for (Criterion c : flow.selector().criteria()) {
crit.add(c.toString());
}
ArrayNode instr = mapper.createArrayNode();
for (Instruction i : flow.treatment().instructions()) {
instr.add(i.toString());
}
result.put("flowId", Long.toHexString(flow.id().value()))
.put("state", flow.state().toString())
.put("bytes", flow.bytes())
.put("packets", flow.packets())
.put("life", flow.life())
.put("appId", coreService.getAppId(flow.appId()).name());
result.set("selector", crit);
result.set("treatment", instr);
return result;
}
/**
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.cli.Comparators;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.host.HostService;
import org.onlab.packet.IpPrefix;
import java.util.Collections;
import java.util.List;
......@@ -15,7 +20,7 @@ import static com.google.common.collect.Lists.newArrayList;
* Lists all currently-known hosts.
*/
@Command(scope = "onos", name = "hosts",
description = "Lists all currently-known hosts.")
description = "Lists all currently-known hosts.")
public class HostsListCommand extends AbstractShellCommand {
private static final String FMT =
......@@ -24,11 +29,42 @@ public class HostsListCommand extends AbstractShellCommand {
@Override
protected void execute() {
HostService service = get(HostService.class);
for (Host host : getSortedHosts(service)) {
printHost(host);
if (outputJson()) {
print("%s", json(getSortedHosts(service)));
} else {
for (Host host : getSortedHosts(service)) {
printHost(host);
}
}
}
// Produces JSON structure.
private static JsonNode json(Iterable<Host> hosts) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Host host : hosts) {
result.add(json(mapper, host));
}
return result;
}
// Produces JSON structure.
private static JsonNode json(ObjectMapper mapper, Host host) {
ObjectNode loc = LinksListCommand.json(mapper, host.location())
.put("time", host.location().time());
ArrayNode ips = mapper.createArrayNode();
for (IpPrefix ip : host.ipAddresses()) {
ips.add(ip.toString());
}
ObjectNode result = mapper.createObjectNode()
.put("id", host.id().toString())
.put("mac", host.mac().toString())
.put("vlan", host.vlan().toString());
result.set("location", loc);
result.set("ips", ips);
return result;
}
/**
* Returns the list of devices sorted using the device ID URIs.
*
......@@ -44,14 +80,14 @@ public class HostsListCommand extends AbstractShellCommand {
/**
* Prints information about a host.
*
* @param host
* @param host end-station host
*/
protected void printHost(Host host) {
if (host != null) {
print(FMT, host.id(), host.mac(),
host.location().deviceId(),
host.location().port(),
host.vlan(), host.ipAddresses());
host.location().deviceId(),
host.location().port(),
host.vlan(), host.ipAddresses());
}
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.link.LinkService;
......@@ -27,9 +32,55 @@ public class LinksListCommand extends AbstractShellCommand {
LinkService service = get(LinkService.class);
Iterable<Link> links = uri != null ?
service.getDeviceLinks(deviceId(uri)) : service.getLinks();
if (outputJson()) {
print("%s", json(links));
} else {
for (Link link : links) {
print(linkString(link));
}
}
}
/**
* Produces a JSON array containing the specified links.
*
* @param links collection of links
* @return JSON array
*/
public static JsonNode json(Iterable<Link> links) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Link link : links) {
print(linkString(link));
result.add(json(mapper, link));
}
return result;
}
/**
* Produces a JSON object for the specified link.
*
* @param mapper object mapper
* @param link link to encode
* @return JSON object
*/
public static ObjectNode json(ObjectMapper mapper, Link link) {
ObjectNode result = mapper.createObjectNode();
result.set("src", json(mapper, link.src()));
result.set("dst", json(mapper, link.dst()));
return result;
}
/**
* Produces a JSON object for the specified connect point.
*
* @param mapper object mapper
* @param connectPoint connection point to encode
* @return JSON object
*/
public static ObjectNode json(ObjectMapper mapper, ConnectPoint connectPoint) {
return mapper.createObjectNode()
.put("device", connectPoint.deviceId().toString())
.put("port", connectPoint.port().toString());
}
/**
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.Link;
......@@ -32,9 +35,30 @@ public class PathListCommand extends TopologyCommand {
protected void execute() {
init();
Set<Path> paths = service.getPaths(topology, deviceId(src), deviceId(dst));
if (outputJson()) {
print("%s", json(paths));
} else {
for (Path path : paths) {
print(pathString(path));
}
}
}
/**
* Produces a JSON array containing the specified paths.
*
* @param paths collection of paths
* @return JSON array
*/
public static JsonNode json(Iterable<Path> paths) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Path path : paths) {
print(pathString(path));
result.add(LinksListCommand.json(mapper, path)
.put("cost", path.cost())
.set("links", LinksListCommand.json(path.links())));
}
return result;
}
/**
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.topology.Topology;
......@@ -30,8 +31,17 @@ public class TopologyCommand extends AbstractShellCommand {
@Override
protected void execute() {
init();
print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(),
topology.clusterCount(), topology.pathCount());
if (outputJson()) {
print("%s", new ObjectMapper().createObjectNode()
.put("time", topology.time())
.put("deviceCount", topology.deviceCount())
.put("linkCount", topology.linkCount())
.put("clusterCount", topology.clusterCount())
.put("pathCount", topology.pathCount()));
} else {
print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(),
topology.clusterCount(), topology.pathCount());
}
}
}
......
......@@ -12,7 +12,11 @@ public final class ControllerNodeToNodeId
@Override
public NodeId apply(ControllerNode input) {
return input.id();
if (input == null) {
return null;
} else {
return input.id();
}
}
/**
......
package org.onlab.onos.net.host;
import java.util.Collections;
import java.util.Set;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.SparseAnnotations;
......@@ -7,6 +10,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.ImmutableSet;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
......@@ -18,7 +23,7 @@ public class DefaultHostDescription extends AbstractDescription
private final MacAddress mac;
private final VlanId vlan;
private final HostLocation location;
private final IpPrefix ip;
private final Set<IpPrefix> ip;
/**
* Creates a host description using the supplied information.
......@@ -31,7 +36,7 @@ public class DefaultHostDescription extends AbstractDescription
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location,
SparseAnnotations... annotations) {
this(mac, vlan, location, null, annotations);
this(mac, vlan, location, Collections.<IpPrefix>emptySet(), annotations);
}
/**
......@@ -46,11 +51,26 @@ public class DefaultHostDescription extends AbstractDescription
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, IpPrefix ip,
SparseAnnotations... annotations) {
this(mac, vlan, location, ImmutableSet.of(ip), annotations);
}
/**
* Creates a host description using the supplied information.
*
* @param mac host MAC address
* @param vlan host VLAN identifier
* @param location host location
* @param ip host IP addresses
* @param annotations optional key/value annotations map
*/
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, Set<IpPrefix> ip,
SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
this.location = location;
this.ip = ip;
this.ip = ImmutableSet.copyOf(ip);
}
@Override
......@@ -69,7 +89,7 @@ public class DefaultHostDescription extends AbstractDescription
}
@Override
public IpPrefix ipAddress() {
public Set<IpPrefix> ipAddress() {
return ip;
}
......
package org.onlab.onos.net.host;
import java.util.Set;
import org.onlab.onos.net.Description;
import org.onlab.onos.net.HostLocation;
import org.onlab.packet.IpPrefix;
......@@ -38,6 +40,6 @@ public interface HostDescription extends Description {
* @return host IP address
*/
// FIXME: Switch to IpAddress
IpPrefix ipAddress();
Set<IpPrefix> ipAddress();
}
......
package org.onlab.onos.cluster;
import static com.google.common.base.Predicates.notNull;
import static org.junit.Assert.*;
import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId;
......@@ -30,12 +31,13 @@ public class ControllerNodeToNodeIdTest {
@Test
public final void testToNodeId() {
final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3);
final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3, null);
final List<NodeId> nodeIds = Arrays.asList(NID1, NID2, NID3);
assertEquals(nodeIds,
FluentIterable.from(nodes)
.transform(toNodeId())
.filter(notNull())
.toList());
}
......
......@@ -8,6 +8,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.ImmutableSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
......@@ -33,7 +35,7 @@ public class DefualtHostDecriptionTest {
assertEquals("incorrect mac", MAC, host.hwAddress());
assertEquals("incorrect vlan", VLAN, host.vlan());
assertEquals("incorrect location", LOC, host.location());
assertEquals("incorrect ip's", IP, host.ipAddress());
assertEquals("incorrect ip's", ImmutableSet.of(IP), host.ipAddress());
assertTrue("incorrect toString", host.toString().contains("vlan=10"));
}
......
/**
*
* Miscellaneous core system implementations.
*/
package org.onlab.onos.impl;
\ No newline at end of file
......
......@@ -355,7 +355,7 @@ public class ProxyArpManager implements ProxyArpService {
arp.setTargetProtocolAddress(((ARP) request.getPayload())
.getSenderProtocolAddress());
arp.setSenderProtocolAddress(srcIp.toRealInt());
arp.setSenderProtocolAddress(srcIp.toInt());
eth.setPayload(arp);
return eth;
}
......
......@@ -515,12 +515,12 @@ public class GossipDeviceStore
Map<PortNumber, Port> ports,
Set<PortNumber> processed) {
List<DeviceEvent> events = new ArrayList<>();
Iterator<PortNumber> iterator = ports.keySet().iterator();
Iterator<Entry<PortNumber, Port>> iterator = ports.entrySet().iterator();
while (iterator.hasNext()) {
PortNumber portNumber = iterator.next();
Entry<PortNumber, Port> e = iterator.next();
PortNumber portNumber = e.getKey();
if (!processed.contains(portNumber)) {
events.add(new DeviceEvent(PORT_REMOVED, device,
ports.get(portNumber)));
events.add(new DeviceEvent(PORT_REMOVED, device, e.getValue()));
iterator.remove();
}
}
......
......@@ -4,6 +4,11 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject;
public final class GossipHostStoreMessageSubjects {
private GossipHostStoreMessageSubjects() {}
public static final MessageSubject HOST_UPDATED = new MessageSubject("peer-host-updated");
public static final MessageSubject HOST_REMOVED = new MessageSubject("peer-host-removed");
public static final MessageSubject HOST_UPDATED
= new MessageSubject("peer-host-updated");
public static final MessageSubject HOST_REMOVED
= new MessageSubject("peer-host-removed");
public static final MessageSubject HOST_ANTI_ENTROPY_ADVERTISEMENT
= new MessageSubject("host-enti-entropy-advertisement");;
}
......
package org.onlab.onos.store.host.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.HostId;
import org.onlab.onos.store.Timestamp;
/**
* Host AE Advertisement message.
*/
public final class HostAntiEntropyAdvertisement {
private final NodeId sender;
private final Map<HostFragmentId, Timestamp> timestamps;
private final Map<HostId, Timestamp> tombstones;
public HostAntiEntropyAdvertisement(NodeId sender,
Map<HostFragmentId, Timestamp> timestamps,
Map<HostId, Timestamp> tombstones) {
this.sender = checkNotNull(sender);
this.timestamps = checkNotNull(timestamps);
this.tombstones = checkNotNull(tombstones);
}
public NodeId sender() {
return sender;
}
public Map<HostFragmentId, Timestamp> timestamps() {
return timestamps;
}
public Map<HostId, Timestamp> tombstones() {
return tombstones;
}
// For serializer
@SuppressWarnings("unused")
private HostAntiEntropyAdvertisement() {
this.sender = null;
this.timestamps = null;
this.tombstones = null;
}
}
package org.onlab.onos.store.host.impl;
import java.util.Objects;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.provider.ProviderId;
import com.google.common.base.MoreObjects;
/**
* Identifier for HostDescription from a Provider.
*/
public final class HostFragmentId {
public final ProviderId providerId;
public final HostId hostId;
public HostFragmentId(HostId hostId, ProviderId providerId) {
this.providerId = providerId;
this.hostId = hostId;
}
public HostId hostId() {
return hostId;
}
public ProviderId providerId() {
return providerId;
}
@Override
public int hashCode() {
return Objects.hash(providerId, hostId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof HostFragmentId)) {
return false;
}
HostFragmentId that = (HostFragmentId) obj;
return Objects.equals(this.hostId, that.hostId) &&
Objects.equals(this.providerId, that.providerId);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("providerId", providerId)
.add("hostId", hostId)
.toString();
}
// for serializer
@SuppressWarnings("unused")
private HostFragmentId() {
this.providerId = null;
this.hostId = null;
}
}
/**
* Implementation of host store using distributed p2p synchronization protocol.
*/
package org.onlab.onos.store.host.impl;
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-core-hz-net</artifactId>
<packaging>bundle</packaging>
<description>ONOS Hazelcast based distributed store subsystems</description>
<dependencies>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-api</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz-common</artifactId>
<classifier>tests</classifier>
<scope>test</scope>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package org.onlab.onos.store.device.impl;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.mastership.MastershipTerm;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.device.DeviceClockProviderService;
// FIXME: Code clone in onos-core-trivial, onos-core-hz-net
/**
* Dummy implementation of {@link DeviceClockProviderService}.
*/
@Component(immediate = true)
@Service
public class NoOpClockProviderService implements DeviceClockProviderService {
@Override
public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) {
}
}
package org.onlab.onos.store.flow.impl;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.Collections;
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.Service;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.DefaultFlowEntry;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleEvent.Type;
import org.onlab.onos.net.flow.FlowRuleStore;
import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
/**
* Manages inventory of flow rules using trivial in-memory implementation.
*/
//FIXME I LIE. I AIN'T DISTRIBUTED
@Component(immediate = true)
@Service
public class DistributedFlowRuleStore
extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
implements FlowRuleStore {
private final Logger log = getLogger(getClass());
// store entries as a pile of rules, no info about device tables
private final Multimap<DeviceId, FlowEntry> flowEntries =
ArrayListMultimap.<DeviceId, FlowEntry>create();
private final Multimap<Short, FlowRule> flowEntriesById =
ArrayListMultimap.<Short, FlowRule>create();
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public int getFlowRuleCount() {
return flowEntries.size();
}
@Override
public synchronized FlowEntry getFlowEntry(FlowRule rule) {
for (FlowEntry f : flowEntries.get(rule.deviceId())) {
if (f.equals(rule)) {
return f;
}
}
return null;
}
@Override
public synchronized Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
Collection<FlowEntry> rules = flowEntries.get(deviceId);
if (rules == null) {
return Collections.emptyList();
}
return ImmutableSet.copyOf(rules);
}
@Override
public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
Collection<FlowRule> rules = flowEntriesById.get(appId.id());
if (rules == null) {
return Collections.emptyList();
}
return ImmutableSet.copyOf(rules);
}
@Override
public synchronized void storeFlowRule(FlowRule rule) {
FlowEntry f = new DefaultFlowEntry(rule);
DeviceId did = f.deviceId();
if (!flowEntries.containsEntry(did, f)) {
flowEntries.put(did, f);
flowEntriesById.put(rule.appId(), f);
}
}
@Override
public synchronized void deleteFlowRule(FlowRule rule) {
FlowEntry entry = getFlowEntry(rule);
if (entry == null) {
return;
}
entry.setState(FlowEntryState.PENDING_REMOVE);
}
@Override
public synchronized FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) {
DeviceId did = rule.deviceId();
// check if this new rule is an update to an existing entry
FlowEntry stored = getFlowEntry(rule);
if (stored != null) {
stored.setBytes(rule.bytes());
stored.setLife(rule.life());
stored.setPackets(rule.packets());
if (stored.state() == FlowEntryState.PENDING_ADD) {
stored.setState(FlowEntryState.ADDED);
return new FlowRuleEvent(Type.RULE_ADDED, rule);
}
return new FlowRuleEvent(Type.RULE_UPDATED, rule);
}
flowEntries.put(did, rule);
return null;
}
@Override
public synchronized FlowRuleEvent removeFlowRule(FlowEntry rule) {
// This is where one could mark a rule as removed and still keep it in the store.
if (flowEntries.remove(rule.deviceId(), rule)) {
return new FlowRuleEvent(RULE_REMOVED, rule);
} else {
return null;
}
}
}
package org.onlab.onos.store.host.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
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.Service;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultHost;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
import org.onlab.onos.net.host.HostStoreDelegate;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.AbstractStore;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
* TEMPORARY: Manages inventory of end-station hosts using distributed
* structures implementation.
*/
//FIXME: I LIE I AM NOT DISTRIBUTED
@Component(immediate = true)
@Service
public class DistributedHostStore
extends AbstractStore<HostEvent, HostStoreDelegate>
implements HostStore {
private final Logger log = getLogger(getClass());
// Host inventory
private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
private final Map<ConnectPoint, PortAddresses> portAddresses =
new ConcurrentHashMap<>();
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
HostDescription hostDescription) {
StoredHost host = hosts.get(hostId);
if (host == null) {
return createHost(providerId, hostId, hostDescription);
}
return updateHost(providerId, host, hostDescription);
}
// creates a new host and sends HOST_ADDED
private HostEvent createHost(ProviderId providerId, HostId hostId,
HostDescription descr) {
StoredHost newhost = new StoredHost(providerId, hostId,
descr.hwAddress(),
descr.vlan(),
descr.location(),
ImmutableSet.of(descr.ipAddress()));
synchronized (this) {
hosts.put(hostId, newhost);
locations.put(descr.location(), newhost);
}
return new HostEvent(HOST_ADDED, newhost);
}
// checks for type of update to host, sends appropriate event
private HostEvent updateHost(ProviderId providerId, StoredHost host,
HostDescription descr) {
HostEvent event;
if (!host.location().equals(descr.location())) {
host.setLocation(descr.location());
return new HostEvent(HOST_MOVED, host);
}
if (host.ipAddresses().contains(descr.ipAddress())) {
return null;
}
Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
addresses.add(descr.ipAddress());
StoredHost updated = new StoredHost(providerId, host.id(),
host.mac(), host.vlan(),
descr.location(), addresses);
event = new HostEvent(HOST_UPDATED, updated);
synchronized (this) {
hosts.put(host.id(), updated);
locations.remove(host.location(), host);
locations.put(updated.location(), updated);
}
return event;
}
@Override
public HostEvent removeHost(HostId hostId) {
synchronized (this) {
Host host = hosts.remove(hostId);
if (host != null) {
locations.remove((host.location()), host);
return new HostEvent(HOST_REMOVED, host);
}
return null;
}
}
@Override
public int getHostCount() {
return hosts.size();
}
@Override
public Iterable<Host> getHosts() {
return ImmutableSet.<Host>copyOf(hosts.values());
}
@Override
public Host getHost(HostId hostId) {
return hosts.get(hostId);
}
@Override
public Set<Host> getHosts(VlanId vlanId) {
Set<Host> vlanset = new HashSet<>();
for (Host h : hosts.values()) {
if (h.vlan().equals(vlanId)) {
vlanset.add(h);
}
}
return vlanset;
}
@Override
public Set<Host> getHosts(MacAddress mac) {
Set<Host> macset = new HashSet<>();
for (Host h : hosts.values()) {
if (h.mac().equals(mac)) {
macset.add(h);
}
}
return macset;
}
@Override
public Set<Host> getHosts(IpPrefix ip) {
Set<Host> ipset = new HashSet<>();
for (Host h : hosts.values()) {
if (h.ipAddresses().contains(ip)) {
ipset.add(h);
}
}
return ipset;
}
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
return ImmutableSet.copyOf(locations.get(connectPoint));
}
@Override
public Set<Host> getConnectedHosts(DeviceId deviceId) {
Set<Host> hostset = new HashSet<>();
for (ConnectPoint p : locations.keySet()) {
if (p.deviceId().equals(deviceId)) {
hostset.addAll(locations.get(p));
}
}
return hostset;
}
@Override
public void updateAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing == null) {
portAddresses.put(addresses.connectPoint(), addresses);
} else {
Set<IpPrefix> union = Sets.union(existing.ips(), addresses.ips())
.immutableCopy();
MacAddress newMac = (addresses.mac() == null) ? existing.mac()
: addresses.mac();
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), union, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
}
@Override
public void removeAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing != null) {
Set<IpPrefix> difference =
Sets.difference(existing.ips(), addresses.ips()).immutableCopy();
// If they removed the existing mac, set the new mac to null.
// Otherwise, keep the existing mac.
MacAddress newMac = existing.mac();
if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
newMac = null;
}
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), difference, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
}
@Override
public void clearAddressBindings(ConnectPoint connectPoint) {
synchronized (portAddresses) {
portAddresses.remove(connectPoint);
}
}
@Override
public Set<PortAddresses> getAddressBindings() {
synchronized (portAddresses) {
return new HashSet<>(portAddresses.values());
}
}
@Override
public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
PortAddresses addresses;
synchronized (portAddresses) {
addresses = portAddresses.get(connectPoint);
}
if (addresses == null) {
addresses = new PortAddresses(connectPoint, null, null);
}
return addresses;
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private HostLocation location;
/**
* Creates an end-station host using the supplied information.
*
* @param providerId provider identity
* @param id host identifier
* @param mac host MAC address
* @param vlan host VLAN identifier
* @param location host location
* @param ips host IP addresses
* @param annotations optional key/value annotations
*/
public StoredHost(ProviderId providerId, HostId id,
MacAddress mac, VlanId vlan, HostLocation location,
Set<IpPrefix> ips, Annotations... annotations) {
super(providerId, id, mac, vlan, location, ips, annotations);
this.location = location;
}
void setLocation(HostLocation location) {
this.location = location;
}
@Override
public HostLocation location() {
return location;
}
}
}
package org.onlab.onos.store.link.impl;
import static com.google.common.cache.CacheBuilder.newBuilder;
import static org.onlab.onos.net.Link.Type.DIRECT;
import static org.onlab.onos.net.Link.Type.INDIRECT;
import static org.onlab.onos.net.LinkKey.linkKey;
import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashSet;
import java.util.Set;
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.Service;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultLink;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.LinkKey;
import org.onlab.onos.net.link.LinkDescription;
import org.onlab.onos.net.link.LinkEvent;
import org.onlab.onos.net.link.LinkStore;
import org.onlab.onos.net.link.LinkStoreDelegate;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.common.AbsentInvalidatingLoadingCache;
import org.onlab.onos.store.common.AbstractHazelcastStore;
import org.onlab.onos.store.common.OptionalCacheLoader;
import org.slf4j.Logger;
import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.ImmutableSet.Builder;
import com.hazelcast.core.IMap;
//TODO: Add support for multiple provider and annotations
/**
* Manages inventory of infrastructure links using Hazelcast-backed map.
*/
@Component(immediate = true)
@Service
public class DistributedLinkStore
extends AbstractHazelcastStore<LinkEvent, LinkStoreDelegate>
implements LinkStore {
private final Logger log = getLogger(getClass());
// Link inventory
private IMap<byte[], byte[]> rawLinks;
private LoadingCache<LinkKey, Optional<DefaultLink>> links;
// TODO synchronize?
// Egress and ingress link sets
private final Multimap<DeviceId, Link> srcLinks = HashMultimap.create();
private final Multimap<DeviceId, Link> dstLinks = HashMultimap.create();
private String linksListener;
@Override
@Activate
public void activate() {
super.activate();
boolean includeValue = true;
// TODO decide on Map name scheme to avoid collision
rawLinks = theInstance.getMap("links");
final OptionalCacheLoader<LinkKey, DefaultLink> linkLoader
= new OptionalCacheLoader<>(serializer, rawLinks);
links = new AbsentInvalidatingLoadingCache<>(newBuilder().build(linkLoader));
// refresh/populate cache based on notification from other instance
linksListener = rawLinks.addEntryListener(new RemoteLinkEventHandler(links), includeValue);
loadLinkCache();
log.info("Started");
}
@Deactivate
public void deactivate() {
rawLinks.removeEntryListener(linksListener);
log.info("Stopped");
}
private void loadLinkCache() {
for (byte[] keyBytes : rawLinks.keySet()) {
final LinkKey id = deserialize(keyBytes);
links.refresh(id);
}
}
@Override
public int getLinkCount() {
return links.asMap().size();
}
@Override
public Iterable<Link> getLinks() {
Builder<Link> builder = ImmutableSet.builder();
for (Optional<DefaultLink> e : links.asMap().values()) {
if (e.isPresent()) {
builder.add(e.get());
}
}
return builder.build();
}
@Override
public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
return ImmutableSet.copyOf(srcLinks.get(deviceId));
}
@Override
public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
return ImmutableSet.copyOf(dstLinks.get(deviceId));
}
@Override
public Link getLink(ConnectPoint src, ConnectPoint dst) {
return links.getUnchecked(linkKey(src, dst)).orNull();
}
@Override
public Set<Link> getEgressLinks(ConnectPoint src) {
Set<Link> egress = new HashSet<>();
for (Link link : srcLinks.get(src.deviceId())) {
if (link.src().equals(src)) {
egress.add(link);
}
}
return egress;
}
@Override
public Set<Link> getIngressLinks(ConnectPoint dst) {
Set<Link> ingress = new HashSet<>();
for (Link link : dstLinks.get(dst.deviceId())) {
if (link.dst().equals(dst)) {
ingress.add(link);
}
}
return ingress;
}
@Override
public LinkEvent createOrUpdateLink(ProviderId providerId,
LinkDescription linkDescription) {
LinkKey key = linkKey(linkDescription.src(), linkDescription.dst());
Optional<DefaultLink> link = links.getUnchecked(key);
if (!link.isPresent()) {
return createLink(providerId, key, linkDescription);
}
return updateLink(providerId, link.get(), key, linkDescription);
}
// Creates and stores the link and returns the appropriate event.
private LinkEvent createLink(ProviderId providerId, LinkKey key,
LinkDescription linkDescription) {
DefaultLink link = new DefaultLink(providerId, key.src(), key.dst(),
linkDescription.type());
synchronized (this) {
final byte[] keyBytes = serialize(key);
rawLinks.put(keyBytes, serialize(link));
links.asMap().putIfAbsent(key, Optional.of(link));
addNewLink(link);
}
return new LinkEvent(LINK_ADDED, link);
}
// update Egress and ingress link sets
private void addNewLink(DefaultLink link) {
synchronized (this) {
srcLinks.put(link.src().deviceId(), link);
dstLinks.put(link.dst().deviceId(), link);
}
}
// Updates, if necessary the specified link and returns the appropriate event.
private LinkEvent updateLink(ProviderId providerId, DefaultLink link,
LinkKey key, LinkDescription linkDescription) {
// FIXME confirm Link update condition is OK
if (link.type() == INDIRECT && linkDescription.type() == DIRECT) {
synchronized (this) {
DefaultLink updated =
new DefaultLink(providerId, link.src(), link.dst(),
linkDescription.type());
final byte[] keyBytes = serialize(key);
rawLinks.put(keyBytes, serialize(updated));
links.asMap().replace(key, Optional.of(link), Optional.of(updated));
replaceLink(link, updated);
return new LinkEvent(LINK_UPDATED, updated);
}
}
return null;
}
// update Egress and ingress link sets
private void replaceLink(DefaultLink link, DefaultLink updated) {
synchronized (this) {
srcLinks.remove(link.src().deviceId(), link);
dstLinks.remove(link.dst().deviceId(), link);
srcLinks.put(link.src().deviceId(), updated);
dstLinks.put(link.dst().deviceId(), updated);
}
}
@Override
public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
synchronized (this) {
LinkKey key = linkKey(src, dst);
byte[] keyBytes = serialize(key);
Link link = deserialize(rawLinks.remove(keyBytes));
links.invalidate(key);
if (link != null) {
removeLink(link);
return new LinkEvent(LINK_REMOVED, link);
}
return null;
}
}
// update Egress and ingress link sets
private void removeLink(Link link) {
synchronized (this) {
srcLinks.remove(link.src().deviceId(), link);
dstLinks.remove(link.dst().deviceId(), link);
}
}
private class RemoteLinkEventHandler extends RemoteCacheEventHandler<LinkKey, DefaultLink> {
public RemoteLinkEventHandler(LoadingCache<LinkKey, Optional<DefaultLink>> cache) {
super(cache);
}
@Override
protected void onAdd(LinkKey key, DefaultLink newVal) {
addNewLink(newVal);
notifyDelegate(new LinkEvent(LINK_ADDED, newVal));
}
@Override
protected void onUpdate(LinkKey key, DefaultLink oldVal, DefaultLink newVal) {
replaceLink(oldVal, newVal);
notifyDelegate(new LinkEvent(LINK_UPDATED, newVal));
}
@Override
protected void onRemove(LinkKey key, DefaultLink val) {
removeLink(val);
notifyDelegate(new LinkEvent(LINK_REMOVED, val));
}
}
}
package org.onlab.onos.store.topology.impl;
import org.onlab.graph.AdjacencyListsGraph;
import org.onlab.onos.net.topology.TopologyEdge;
import org.onlab.onos.net.topology.TopologyGraph;
import org.onlab.onos.net.topology.TopologyVertex;
import java.util.Set;
/**
* Default implementation of an immutable topology graph based on a generic
* implementation of adjacency lists graph.
*/
public class DefaultTopologyGraph
extends AdjacencyListsGraph<TopologyVertex, TopologyEdge>
implements TopologyGraph {
/**
* Creates a topology graph comprising of the specified vertexes and edges.
*
* @param vertexes set of graph vertexes
* @param edges set of graph edges
*/
public DefaultTopologyGraph(Set<TopologyVertex> vertexes, Set<TopologyEdge> edges) {
super(vertexes, edges);
}
}
package org.onlab.onos.store.topology.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
import java.util.Set;
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.Service;
import org.onlab.onos.event.Event;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.topology.ClusterId;
import org.onlab.onos.net.topology.GraphDescription;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyCluster;
import org.onlab.onos.net.topology.TopologyEvent;
import org.onlab.onos.net.topology.TopologyGraph;
import org.onlab.onos.net.topology.TopologyStore;
import org.onlab.onos.net.topology.TopologyStoreDelegate;
import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
/**
* TEMPORARY: Manages inventory of topology snapshots using distributed
* structures implementation.
*/
//FIXME: I LIE I AM NOT DISTRIBUTED
@Component(immediate = true)
@Service
public class DistributedTopologyStore
extends AbstractStore<TopologyEvent, TopologyStoreDelegate>
implements TopologyStore {
private final Logger log = getLogger(getClass());
private volatile DefaultTopology current;
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public Topology currentTopology() {
return current;
}
@Override
public boolean isLatest(Topology topology) {
// Topology is current only if it is the same as our current topology
return topology == current;
}
@Override
public TopologyGraph getGraph(Topology topology) {
return defaultTopology(topology).getGraph();
}
@Override
public Set<TopologyCluster> getClusters(Topology topology) {
return defaultTopology(topology).getClusters();
}
@Override
public TopologyCluster getCluster(Topology topology, ClusterId clusterId) {
return defaultTopology(topology).getCluster(clusterId);
}
@Override
public Set<DeviceId> getClusterDevices(Topology topology, TopologyCluster cluster) {
return defaultTopology(topology).getClusterDevices(cluster);
}
@Override
public Set<Link> getClusterLinks(Topology topology, TopologyCluster cluster) {
return defaultTopology(topology).getClusterLinks(cluster);
}
@Override
public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
return defaultTopology(topology).getPaths(src, dst);
}
@Override
public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
LinkWeight weight) {
return defaultTopology(topology).getPaths(src, dst, weight);
}
@Override
public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
return defaultTopology(topology).isInfrastructure(connectPoint);
}
@Override
public boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint) {
return defaultTopology(topology).isBroadcastPoint(connectPoint);
}
@Override
public TopologyEvent updateTopology(ProviderId providerId,
GraphDescription graphDescription,
List<Event> reasons) {
// First off, make sure that what we're given is indeed newer than
// what we already have.
if (current != null && graphDescription.timestamp() < current.time()) {
return null;
}
// Have the default topology construct self from the description data.
DefaultTopology newTopology =
new DefaultTopology(providerId, graphDescription);
// Promote the new topology to current and return a ready-to-send event.
synchronized (this) {
current = newTopology;
return new TopologyEvent(TopologyEvent.Type.TOPOLOGY_CHANGED,
current, reasons);
}
}
// Validates the specified topology and returns it as a default
private DefaultTopology defaultTopology(Topology topology) {
if (topology instanceof DefaultTopology) {
return (DefaultTopology) topology;
}
throw new IllegalArgumentException("Topology class " + topology.getClass() +
" not supported");
}
}
package org.onlab.onos.store.topology.impl;
import org.onlab.onos.net.DeviceId;
import java.util.Objects;
/**
* Key for filing pre-computed paths between source and destination devices.
*/
class PathKey {
private final DeviceId src;
private final DeviceId dst;
/**
* Creates a path key from the given source/dest pair.
* @param src source device
* @param dst destination device
*/
PathKey(DeviceId src, DeviceId dst) {
this.src = src;
this.dst = dst;
}
@Override
public int hashCode() {
return Objects.hash(src, dst);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof PathKey) {
final PathKey other = (PathKey) obj;
return Objects.equals(this.src, other.src) && Objects.equals(this.dst, other.dst);
}
return false;
}
}
......@@ -17,7 +17,6 @@
<modules>
<module>common</module>
<module>cluster</module>
<module>net</module>
</modules>
<dependencies>
......
package org.onlab.onos.store.serializers;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.PortNumber;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* Kryo Serializer for {@link HostLocation}.
*/
public class HostLocationSerializer extends Serializer<HostLocation> {
/**
* Creates {@link HostLocation} serializer instance.
*/
public HostLocationSerializer() {
// non-null, immutable
super(false, true);
}
@Override
public void write(Kryo kryo, Output output, HostLocation object) {
kryo.writeClassAndObject(output, object.deviceId());
kryo.writeClassAndObject(output, object.port());
output.writeLong(object.time());
}
@Override
public HostLocation read(Kryo kryo, Input input, Class<HostLocation> type) {
DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
PortNumber portNumber = (PortNumber) kryo.readClassAndObject(input);
long time = input.readLong();
return new HostLocation(deviceId, portNumber, time);
}
}
......@@ -20,8 +20,7 @@ public class IpAddressSerializer extends Serializer<IpAddress> {
}
@Override
public void write(Kryo kryo, Output output,
IpAddress object) {
public void write(Kryo kryo, Output output, IpAddress object) {
byte[] octs = object.toOctets();
output.writeInt(octs.length);
output.writeBytes(octs);
......@@ -29,11 +28,10 @@ public class IpAddressSerializer extends Serializer<IpAddress> {
}
@Override
public IpAddress read(Kryo kryo, Input input,
Class<IpAddress> type) {
int octLen = input.readInt();
public IpAddress read(Kryo kryo, Input input, Class<IpAddress> type) {
final int octLen = input.readInt();
byte[] octs = new byte[octLen];
input.read(octs);
input.readBytes(octs);
int prefLen = input.readInt();
return IpAddress.valueOf(octs, prefLen);
}
......
......@@ -34,7 +34,7 @@ public final class IpPrefixSerializer extends Serializer<IpPrefix> {
Class<IpPrefix> type) {
int octLen = input.readInt();
byte[] octs = new byte[octLen];
input.read(octs);
input.readBytes(octs);
int prefLen = input.readInt();
return IpPrefix.valueOf(octs, prefLen);
}
......
......@@ -17,21 +17,28 @@ import org.onlab.onos.net.DefaultPort;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Element;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.LinkKey;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DefaultDeviceDescription;
import org.onlab.onos.net.device.DefaultPortDescription;
import org.onlab.onos.net.host.DefaultHostDescription;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.link.DefaultLinkDescription;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.Timestamp;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.KryoPool;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public final class KryoPoolUtil {
......@@ -41,6 +48,8 @@ public final class KryoPoolUtil {
public static final KryoPool MISC = KryoPool.newBuilder()
.register(IpPrefix.class, new IpPrefixSerializer())
.register(IpAddress.class, new IpAddressSerializer())
.register(MacAddress.class, new MacAddressSerializer())
.register(VlanId.class)
.build();
// TODO: Populate other classes
......@@ -51,6 +60,7 @@ public final class KryoPoolUtil {
.register(MISC)
.register(ImmutableMap.class, new ImmutableMapSerializer())
.register(ImmutableList.class, new ImmutableListSerializer())
.register(ImmutableSet.class, new ImmutableSetSerializer())
.register(
//
ArrayList.class,
......@@ -69,8 +79,10 @@ public final class KryoPoolUtil {
DefaultPortDescription.class,
Element.class,
Link.Type.class,
Timestamp.class
Timestamp.class,
HostId.class,
HostDescription.class,
DefaultHostDescription.class
)
.register(URI.class, new URISerializer())
.register(NodeId.class, new NodeIdSerializer())
......@@ -82,6 +94,8 @@ public final class KryoPoolUtil {
.register(ConnectPoint.class, new ConnectPointSerializer())
.register(DefaultLink.class, new DefaultLinkSerializer())
.register(MastershipTerm.class, new MastershipTermSerializer())
.register(MastershipRole.class, new MastershipRoleSerializer())
.register(HostLocation.class, new HostLocationSerializer())
.build();
......
package org.onlab.onos.store.serializers;
import org.onlab.packet.MacAddress;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* Kryo Serializer for {@link MacAddress}.
*/
public class MacAddressSerializer extends Serializer<MacAddress> {
/**
* Creates {@link MacAddress} serializer instance.
*/
public MacAddressSerializer() {
super(false, true);
}
@Override
public void write(Kryo kryo, Output output, MacAddress object) {
output.writeBytes(object.getAddress());
}
@Override
public MacAddress read(Kryo kryo, Input input, Class<MacAddress> type) {
return MacAddress.valueOf(input.readBytes(MacAddress.MAC_ADDRESS_LENGTH));
}
}
......@@ -84,7 +84,7 @@ public class SimpleHostStore
descr.hwAddress(),
descr.vlan(),
descr.location(),
ImmutableSet.of(descr.ipAddress()));
ImmutableSet.copyOf(descr.ipAddress()));
synchronized (this) {
hosts.put(hostId, newhost);
locations.put(descr.location(), newhost);
......@@ -101,12 +101,12 @@ public class SimpleHostStore
return new HostEvent(HOST_MOVED, host);
}
if (host.ipAddresses().contains(descr.ipAddress())) {
if (host.ipAddresses().containsAll(descr.ipAddress())) {
return null;
}
Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
addresses.add(descr.ipAddress());
addresses.addAll(descr.ipAddress());
StoredHost updated = new StoredHost(providerId, host.id(),
host.mac(), host.vlan(),
descr.location(), addresses);
......
......@@ -30,6 +30,7 @@
<bundle>mvn:org.codehaus.jackson/jackson-core-asl/1.9.13</bundle>
<bundle>mvn:org.codehaus.jackson/jackson-mapper-asl/1.9.13</bundle>
<bundle>mvn:org.onlab.onos/onlab-thirdparty/1.0.0-SNAPSHOT</bundle>
</feature>
<feature name="onos-thirdparty-web" version="1.0.0"
......
......@@ -107,7 +107,13 @@
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<groupId>com.googlecode.concurrent-trees</groupId>
<artifactId>concurrent-trees</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
......@@ -164,6 +170,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.8</version>
......@@ -260,6 +272,13 @@
<artifactId>onos-of-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-thirdparty</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-of-api</artifactId>
......
......@@ -161,10 +161,10 @@ public class FlowModBuilder {
switch (l3m.subtype()) {
case IP_DST:
ip = (ModIPInstruction) i;
return factory.actions().setNwDst(IPv4Address.of(ip.ip().toRealInt()));
return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
case IP_SRC:
ip = (ModIPInstruction) i;
return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toRealInt()));
return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
default:
log.warn("Unimplemented action type {}.", l3m.subtype());
break;
......@@ -220,21 +220,21 @@ public class FlowModBuilder {
case IPV4_DST:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toRealInt()),
IPv4Address.of(ip.ip().netmask().toRealInt()));
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
mBuilder.setMasked(MatchField.IPV4_DST, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toRealInt()));
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
}
break;
case IPV4_SRC:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toRealInt()),
IPv4Address.of(ip.ip().netmask().toRealInt()));
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toRealInt()));
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt()));
}
break;
case IP_PROTO:
......
......@@ -339,9 +339,14 @@ public class LinkDiscovery implements TimerTask {
final Iterator<Integer> fastIterator = this.fastPorts.iterator();
while (fastIterator.hasNext()) {
final Integer portNumber = fastIterator.next();
OFPortDesc port = findPort(portNumber);
if (port == null) {
// port can be null
// #removePort modifies `ports` outside synchronized block
continue;
}
final int probeCount = this.portProbeCount.get(portNumber)
.getAndIncrement();
OFPortDesc port = findPort(portNumber);
if (probeCount < LinkDiscovery.MAX_PROBE_COUNT) {
this.log.debug("sending fast probe to port");
......
......@@ -25,6 +25,9 @@ export ONOS_STAGE=$ONOS_STAGE_ROOT/$ONOS_BITS
export ONOS_TAR=$ONOS_STAGE.tar.gz
# Defaults for ONOS testing using remote machines.
if [ -n "${ONOS_CELL}" -a -f $ONOS_ROOT/tools/test/cells/${ONOS_CELL} ]; then
. $ONOS_ROOT/tools/test/cells/${ONOS_CELL}
fi
export ONOS_INSTALL_DIR="/opt/onos" # Installation directory on remote
export OCI="${OCI:-192.168.56.101}" # ONOS Controller Instance
export ONOS_USER="sdn" # ONOS user on remote system
......
......@@ -6,7 +6,13 @@
export ONOS_ROOT=${ONOS_ROOT:-~/onos-next}
# Setup some environmental context for developers
export JAVA_HOME=${JAVA_HOME:-$(/usr/libexec/java_home -v 1.7)}
if [ -z "${JAVA_HOME}" ]; then
if [ -x /usr/libexec/java_home ]; then
export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)
elif [ -d /usr/lib/jvm/java-7-openjdk-amd64 ]; then
export JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64"
fi
fi
export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2}
export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1}
export KARAF_LOG=$KARAF/data/log/karaf.log
......@@ -15,7 +21,6 @@ export KARAF_LOG=$KARAF/data/log/karaf.log
export PATH="$PATH:$ONOS_ROOT/tools/dev/bin:$ONOS_ROOT/tools/test/bin"
export PATH="$PATH:$ONOS_ROOT/tools/build"
export PATH="$PATH:$MAVEN/bin:$KARAF/bin"
export PATH="$PATH:."
# Convenience utility to warp to various ONOS source projects
# e.g. 'o api', 'o dev', 'o'
......
......@@ -2,13 +2,15 @@ package org.onlab.packet;
import java.util.Arrays;
/**
* A class representing an IPv4 address.
* <p/>
* TODO this class is a clone of IpPrefix and still needs to be modified to
* look more like an IpAddress.
*/
public final class IpAddress {
public final class IpAddress implements Comparable<IpAddress> {
// TODO a comparator for netmasks? E.g. for sorting by prefix match order.
......@@ -121,7 +123,7 @@ public final class IpAddress {
int mask = DEFAULT_MASK;
if (parts.length == 2) {
mask = Integer.valueOf(parts[1]);
mask = Integer.parseInt(parts[1]);
if (mask > MAX_INET_MASK) {
throw new IllegalArgumentException(
"Value of subnet mask cannot exceed "
......@@ -174,14 +176,6 @@ public final class IpAddress {
* @return the IP address's value as an integer
*/
public int toInt() {
int address = 0;
for (int i = 0; i < INET_LEN; i++) {
address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
}
return address;
}
public int toRealInt() {
int val = 0;
for (int i = 0; i < octets.length; i++) {
val <<= 8;
......@@ -191,6 +185,15 @@ public final class IpAddress {
}
/**
* Converts the IP address to a /32 IP prefix.
*
* @return the new IP prefix
*/
public IpPrefix toPrefix() {
return IpPrefix.valueOf(octets, MAX_INET_MASK);
}
/**
* Helper for computing the mask value from CIDR.
*
* @return an integer bitmask
......@@ -280,6 +283,13 @@ public final class IpAddress {
}
@Override
public int compareTo(IpAddress o) {
Long lv = ((long) this.toInt()) & 0xffffffffL;
Long rv = ((long) o.toInt()) & 0xffffffffL;
return lv.compareTo(rv);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
......
......@@ -120,7 +120,7 @@ public final class IpPrefix {
int mask = DEFAULT_MASK;
if (parts.length == 2) {
mask = Integer.valueOf(parts[1]);
mask = Integer.parseInt(parts[1]);
if (mask > MAX_INET_MASK) {
throw new IllegalArgumentException(
"Value of subnet mask cannot exceed "
......@@ -173,14 +173,6 @@ public final class IpPrefix {
* @return the IP address's value as an integer
*/
public int toInt() {
int address = 0;
for (int i = 0; i < INET_LEN; i++) {
address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
}
return address;
}
public int toRealInt() {
int val = 0;
for (int i = 0; i < octets.length; i++) {
val <<= 8;
......
......@@ -23,6 +23,7 @@
<module>nio</module>
<module>osgi</module>
<module>rest</module>
<module>thirdparty</module>
</modules>
<dependencies>
......
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-utils</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onlab-thirdparty</artifactId>
<packaging>bundle</packaging>
<description>ONLab third-party dependencies</description>
<dependencies>
<dependency>
<groupId>com.googlecode.concurrent-trees</groupId>
<artifactId>concurrent-trees</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<filters>
<filter>
<artifact>com.googlecode.concurrent-trees:concurrent-trees</artifact>
<includes>
<include>com/googlecode/**</include>
</includes>
</filter>
<filter>
<artifact>com.google.guava:guava</artifact>
<excludes>
<exclude>**</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Export-Package>
com.googlecode.concurrenttrees.*
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
package org.onlab.thirdparty;
/**
* Empty class required to get the onlab-thirdparty module to build properly.
* <p/>
* TODO Figure out how to remove this.
*/
public class OnlabThirdparty {
}