Merge branch 'optical_path_provisioner'
Conflicts:
core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
Change-Id: I3449d508668835307d9b00a87d047599a83de81d
diff --git a/apps/foo/src/main/java/org/onlab/onos/foo/SimpleNettyClient.java b/apps/foo/src/main/java/org/onlab/onos/foo/SimpleNettyClient.java
index 6f77924..a14c568 100644
--- a/apps/foo/src/main/java/org/onlab/onos/foo/SimpleNettyClient.java
+++ b/apps/foo/src/main/java/org/onlab/onos/foo/SimpleNettyClient.java
@@ -4,6 +4,7 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -12,7 +13,6 @@
import org.onlab.metrics.MetricsManager;
import org.onlab.netty.Endpoint;
import org.onlab.netty.NettyMessagingService;
-import org.onlab.netty.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -74,10 +74,10 @@
for (int i = 0; i < warmup; i++) {
messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
- Response response = messaging
+ Future<byte[]> responseFuture = messaging
.sendAndReceive(endpoint, "echo",
"Hello World".getBytes());
- response.get(100000, TimeUnit.MILLISECONDS);
+ responseFuture.get(100000, TimeUnit.MILLISECONDS);
}
log.info("measuring round-trip send & receive");
@@ -85,13 +85,13 @@
int timeouts = 0;
for (int i = 0; i < iterations; i++) {
- Response response;
+ Future<byte[]> responseFuture;
Timer.Context context = sendAndReceiveTimer.time();
try {
- response = messaging
+ responseFuture = messaging
.sendAndReceive(endpoint, "echo",
"Hello World".getBytes());
- response.get(10000, TimeUnit.MILLISECONDS);
+ responseFuture.get(10000, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
timeouts++;
log.info("timeout:" + timeouts + " at iteration:" + i);
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
index 0300079..c3fd6ed 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
@@ -201,7 +201,7 @@
@Override
public TrafficTreatment build() {
- //If we are dropping should we just return an emptry list?
+ //If we are dropping should we just return an empty list?
List<Instruction> instructions = new LinkedList<Instruction>();
instructions.addAll(modifications);
instructions.addAll(groups);
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
index 11bd4ad..736dc9d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -20,7 +20,6 @@
import java.util.concurrent.Future;
-import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.store.Store;
@@ -53,14 +52,6 @@
Iterable<FlowEntry> getFlowEntries(DeviceId deviceId);
/**
- * Returns the flow entries associated with an application.
- *
- * @param appId the application id
- * @return the flow entries
- */
- Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId);
-
- /**
// TODO: Better description of method behavior.
* Stores a new flow rule without generating events.
*
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/InterfaceIpAddress.java b/core/api/src/main/java/org/onlab/onos/net/host/InterfaceIpAddress.java
new file mode 100644
index 0000000..afdfdde
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/host/InterfaceIpAddress.java
@@ -0,0 +1,157 @@
+package org.onlab.onos.net.host;
+
+import java.util.Objects;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a single IP address information on an interface.
+ *
+ * TODO:
+ * - Add computation for the default broadcast address if it is not
+ * specified
+ * - Add explicit checks that each IP address or prefix belong to the
+ * same IP version: IPv4/IPv6.
+ * - Inside the copy constructor we should use copy constructors for each
+ * field
+ */
+public class InterfaceIpAddress {
+ private final IpAddress ipAddress;
+ private final IpPrefix subnetAddress;
+ private final IpAddress broadcastAddress;
+ private final IpAddress peerAddress;
+
+ /**
+ * Copy constructor.
+ *
+ * @param other the object to copy from
+ */
+ public InterfaceIpAddress(InterfaceIpAddress other) {
+ // TODO: we should use copy constructors for each field
+ this.ipAddress = other.ipAddress;
+ this.subnetAddress = other.subnetAddress;
+ this.broadcastAddress = other.broadcastAddress;
+ this.peerAddress = other.peerAddress;
+ }
+
+ /**
+ * Constructor for a given IP address and a subnet address.
+ *
+ * @param ipAddress the IP address
+ * @param subnetAddress the IP subnet address
+ */
+ public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress) {
+ this.ipAddress = checkNotNull(ipAddress);
+ this.subnetAddress = checkNotNull(subnetAddress);
+ // TODO: Recompute the default broadcast address from the subnet
+ // address
+ this.broadcastAddress = null;
+ this.peerAddress = null;
+ }
+
+ /**
+ * Constructor for a given IP address and a subnet address.
+ *
+ * @param ipAddress the IP address
+ * @param subnetAddress the IP subnet address
+ * @param broadcastAddress the IP broadcast address. It can be used
+ * to specify non-default broadcast address
+ */
+ public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress,
+ IpAddress broadcastAddress) {
+ this.ipAddress = checkNotNull(ipAddress);
+ this.subnetAddress = checkNotNull(subnetAddress);
+ this.broadcastAddress = broadcastAddress;
+ this.peerAddress = null;
+ }
+
+ /**
+ * Constructor for a given IP address and a subnet address.
+ *
+ * @param ipAddress the IP address
+ * @param subnetAddress the IP subnet address
+ * @param broadcastAddress the IP broadcast address. It can be used
+ * to specify non-default broadcast address. It should be null for
+ * point-to-point interfaces with a peer address
+ * @param peerAddress the peer IP address for point-to-point interfaces
+ */
+ public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress,
+ IpAddress broadcastAddress,
+ IpAddress peerAddress) {
+ this.ipAddress = checkNotNull(ipAddress);
+ this.subnetAddress = checkNotNull(subnetAddress);
+ this.broadcastAddress = broadcastAddress;
+ this.peerAddress = peerAddress;
+ }
+
+ /**
+ * Gets the IP address.
+ *
+ * @return the IP address
+ */
+ public IpAddress ipAddress() {
+ return ipAddress;
+ }
+
+ /**
+ * Gets the IP subnet address.
+ *
+ * @return the IP subnet address
+ */
+ public IpPrefix subnetAddress() {
+ return subnetAddress;
+ }
+
+ /**
+ * Gets the subnet IP broadcast address.
+ *
+ * @return the subnet IP broadcast address
+ */
+ public IpAddress broadcastAddress() {
+ return broadcastAddress;
+ }
+
+ /**
+ * Gets the IP point-to-point interface peer address.
+ *
+ * @return the IP point-to-point interface peer address
+ */
+ public IpAddress peerAddress() {
+ return peerAddress;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof InterfaceIpAddress)) {
+ return false;
+ }
+ InterfaceIpAddress otherAddr = (InterfaceIpAddress) other;
+
+ return Objects.equals(this.ipAddress, otherAddr.ipAddress)
+ && Objects.equals(this.subnetAddress, otherAddr.subnetAddress)
+ && Objects.equals(this.broadcastAddress,
+ otherAddr.broadcastAddress)
+ && Objects.equals(this.peerAddress, otherAddr.peerAddress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipAddress, subnetAddress, broadcastAddress,
+ peerAddress);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("ipAddress", ipAddress)
+ .add("subnetAddress", subnetAddress)
+ .add("broadcastAddress", broadcastAddress)
+ .add("peerAddress", peerAddress)
+ .omitNullValues().toString();
+ }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
index 5ae5187..43cc61c 100644
--- a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
@@ -24,6 +24,16 @@
void releaseResources(LinkResourceAllocations allocations);
/**
+ * Updates previously made allocations with a new resource request.
+ *
+ * @param req updated resource request
+ * @param oldAllocations old resource allocations
+ * @return new resource allocations
+ */
+ LinkResourceAllocations updateResources(LinkResourceRequest req,
+ LinkResourceAllocations oldAllocations);
+
+ /**
* Returns all allocated resources.
*
* @return allocated resources
@@ -61,4 +71,15 @@
* @return available resources for the target link
*/
ResourceRequest getAvailableResources(Link link);
+
+ /**
+ * Returns available resources for given link.
+ *
+ * @param link a target link
+ * @param allocations allocations to be included as available
+ * @return available resources for the target link
+ */
+ ResourceRequest getAvailableResources(Link link,
+ LinkResourceAllocations allocations);
+
}
diff --git a/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterCommunicationService.java b/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterCommunicationService.java
index 6fc150c..2cff64a 100644
--- a/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterCommunicationService.java
+++ b/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterCommunicationService.java
@@ -5,6 +5,8 @@
import org.onlab.onos.cluster.NodeId;
+import com.google.common.util.concurrent.ListenableFuture;
+
// TODO: remove IOExceptions?
/**
* Service for assisting communications between controller cluster nodes.
@@ -40,10 +42,10 @@
* Sends a message synchronously.
* @param message message to send
* @param toNodeId recipient node identifier
- * @return ClusterMessageResponse which is reply future.
+ * @return reply future.
* @throws IOException
*/
- ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException;
+ ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException;
/**
* Adds a new subscriber for the specified message subject.
diff --git a/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterMessageResponse.java b/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterMessageResponse.java
deleted file mode 100644
index d2a0039..0000000
--- a/core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterMessageResponse.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.onlab.onos.store.cluster.messaging;
-
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.onlab.onos.cluster.NodeId;
-
-public interface ClusterMessageResponse extends Future<byte[]> {
-
- public NodeId sender();
-
- // TODO InterruptedException, ExecutionException removed from original
- // Future declaration. Revisit if we ever need those.
- @Override
- public byte[] get(long timeout, TimeUnit unit) throws TimeoutException;
-
-}
diff --git a/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java b/core/api/src/test/java/org/onlab/onos/net/host/DefaultHostDecriptionTest.java
similarity index 96%
rename from core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java
rename to core/api/src/test/java/org/onlab/onos/net/host/DefaultHostDecriptionTest.java
index f2b9475..2cd0edc 100644
--- a/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/host/DefaultHostDecriptionTest.java
@@ -16,7 +16,7 @@
/**
* Test for the default host description.
*/
-public class DefualtHostDecriptionTest {
+public class DefaultHostDecriptionTest {
private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
private static final VlanId VLAN = VlanId.vlanId((short) 10);
diff --git a/core/api/src/test/java/org/onlab/onos/net/host/InterfaceIpAddressTest.java b/core/api/src/test/java/org/onlab/onos/net/host/InterfaceIpAddressTest.java
new file mode 100644
index 0000000..f436eca
--- /dev/null
+++ b/core/api/src/test/java/org/onlab/onos/net/host/InterfaceIpAddressTest.java
@@ -0,0 +1,241 @@
+package org.onlab.onos.net.host;
+
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for class {@link InterfaceIpAddress}.
+ */
+public class InterfaceIpAddressTest {
+ private static final IpAddress IP_ADDRESS = IpAddress.valueOf("1.2.3.4");
+ private static final IpPrefix SUBNET_ADDRESS =
+ IpPrefix.valueOf("1.2.0.0/16");
+ private static final IpAddress BROADCAST_ADDRESS =
+ IpAddress.valueOf("1.2.0.255"); // NOTE: non-default broadcast
+ private static final IpAddress PEER_ADDRESS = IpAddress.valueOf("5.6.7.8");
+
+ private static final IpAddress IP_ADDRESS2 = IpAddress.valueOf("10.2.3.4");
+ private static final IpPrefix SUBNET_ADDRESS2 =
+ IpPrefix.valueOf("10.2.0.0/16");
+ private static final IpAddress BROADCAST_ADDRESS2 =
+ IpAddress.valueOf("10.2.0.255"); // NOTE: non-default broadcast
+ private static final IpAddress PEER_ADDRESS2 =
+ IpAddress.valueOf("50.6.7.8");
+
+ /**
+ * Tests valid class copy constructor.
+ */
+ @Test
+ public void testCopyConstructor() {
+ InterfaceIpAddress fromAddr;
+ InterfaceIpAddress toAddr;
+
+ // Regular interface address with default broadcast address
+ fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ toAddr = new InterfaceIpAddress(fromAddr);
+ assertThat(toAddr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16}"));
+
+ // Interface address with non-default broadcast address
+ fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ toAddr = new InterfaceIpAddress(fromAddr);
+ assertThat(toAddr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, broadcastAddress=1.2.0.255}"));
+
+ // Point-to-point address with peer IP address
+ fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ toAddr = new InterfaceIpAddress(fromAddr);
+ assertThat(toAddr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, peerAddress=5.6.7.8}"));
+ }
+
+ /**
+ * Tests invalid class copy constructor for a null object to copy from.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullObject() {
+ InterfaceIpAddress fromAddr = null;
+ InterfaceIpAddress toAddr = new InterfaceIpAddress(fromAddr);
+ }
+
+ /**
+ * Tests valid class constructor for regular interface address with
+ * default broadcast address.
+ */
+ @Test
+ public void testConstructorForDefaultBroadcastAddress() {
+ InterfaceIpAddress addr =
+ new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16}"));
+ }
+
+ /**
+ * Tests valid class constructor for interface address with
+ * non-default broadcast address.
+ */
+ @Test
+ public void testConstructorForNonDefaultBroadcastAddress() {
+ InterfaceIpAddress addr =
+ new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, broadcastAddress=1.2.0.255}"));
+ }
+
+ /**
+ * Tests valid class constructor for point-to-point interface address with
+ * peer address.
+ */
+ @Test
+ public void testConstructorForPointToPointAddress() {
+ InterfaceIpAddress addr =
+ new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, peerAddress=5.6.7.8}"));
+ }
+
+ /**
+ * Tests getting the fields of an interface address.
+ */
+ @Test
+ public void testGetFields() {
+ InterfaceIpAddress addr;
+
+ // Regular interface address with default broadcast address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ assertThat(addr.ipAddress().toString(), is("1.2.3.4"));
+ assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16"));
+ assertThat(addr.broadcastAddress(), is(nullValue())); // TODO: Fix
+ assertThat(addr.peerAddress(), is(nullValue()));
+
+ // Interface address with non-default broadcast address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ assertThat(addr.ipAddress().toString(), is("1.2.3.4"));
+ assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16"));
+ assertThat(addr.broadcastAddress().toString(), is("1.2.0.255"));
+ assertThat(addr.peerAddress(), is(nullValue()));
+
+ // Point-to-point address with peer IP address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ assertThat(addr.ipAddress().toString(), is("1.2.3.4"));
+ assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16"));
+ assertThat(addr.broadcastAddress(), is(nullValue()));
+ assertThat(addr.peerAddress().toString(), is("5.6.7.8"));
+ }
+
+ /**
+ * Tests equality of {@link InterfaceIpAddress}.
+ */
+ @Test
+ public void testEquality() {
+ InterfaceIpAddress addr1, addr2;
+
+ // Regular interface address with default broadcast address
+ addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ assertThat(addr1, is(addr2));
+
+ // Interface address with non-default broadcast address
+ addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ assertThat(addr1, is(addr2));
+
+ // Point-to-point address with peer IP address
+ addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ assertThat(addr1, is(addr2));
+ }
+
+ /**
+ * Tests non-equality of {@link InterfaceIpAddress}.
+ */
+ @Test
+ public void testNonEquality() {
+ InterfaceIpAddress addr1, addr2, addr3, addr4;
+
+ // Regular interface address with default broadcast address
+ addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ // Interface address with non-default broadcast address
+ addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ // Point-to-point address with peer IP address
+ addr3 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+
+ // Test interface addresses with different properties:
+ // - default-broadcast vs non-default broadcast
+ // - regular vs point-to-point
+ assertThat(addr1, is(not(addr2)));
+ assertThat(addr1, is(not(addr3)));
+ assertThat(addr2, is(not(addr3)));
+
+ // Test regular interface address with default broadcast address
+ addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS);
+ assertThat(addr1, is(not(addr4)));
+ addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2);
+ assertThat(addr1, is(not(addr4)));
+
+ // Test interface address with non-default broadcast address
+ addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ assertThat(addr2, is(not(addr4)));
+ addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2,
+ BROADCAST_ADDRESS);
+ assertThat(addr2, is(not(addr4)));
+ addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS2);
+ assertThat(addr2, is(not(addr4)));
+
+ // Test point-to-point address with peer IP address
+ addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ assertThat(addr3, is(not(addr4)));
+ addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2, null,
+ PEER_ADDRESS);
+ assertThat(addr3, is(not(addr4)));
+ addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS2);
+ assertThat(addr3, is(not(addr4)));
+ }
+
+ /**
+ * Tests object string representation.
+ */
+ @Test
+ public void testToString() {
+ InterfaceIpAddress addr;
+
+ // Regular interface address with default broadcast address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16}"));
+
+ // Interface address with non-default broadcast address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS,
+ BROADCAST_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, broadcastAddress=1.2.0.255}"));
+
+ // Point-to-point address with peer IP address
+ addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null,
+ PEER_ADDRESS);
+ assertThat(addr.toString(),
+ is("InterfaceIpAddress{ipAddress=1.2.3.4, subnetAddress=1.2.0.0/16, peerAddress=5.6.7.8}"));
+ }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index 60ab307..0c07bab 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -50,6 +50,7 @@
import org.slf4j.Logger;
import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
@@ -116,71 +117,38 @@
@Override
public void applyFlowRules(FlowRule... flowRules) {
+ Set<FlowRuleBatchEntry> toAddBatchEntries = Sets.newHashSet();
for (int i = 0; i < flowRules.length; i++) {
- FlowRule f = flowRules[i];
- store.storeFlowRule(f);
+ toAddBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, flowRules[i]));
}
- }
-
- private void applyFlowRulesToProviders(FlowRule... flowRules) {
- DeviceId did = null;
- FlowRuleProvider frp = null;
- for (FlowRule f : flowRules) {
- if (!f.deviceId().equals(did)) {
- did = f.deviceId();
- final Device device = deviceService.getDevice(did);
- frp = getProvider(device.providerId());
- }
- if (frp != null) {
- frp.applyFlowRule(f);
- }
- }
+ applyBatch(new FlowRuleBatchOperation(toAddBatchEntries));
}
@Override
public void removeFlowRules(FlowRule... flowRules) {
- FlowRule f;
+ Set<FlowRuleBatchEntry> toRemoveBatchEntries = Sets.newHashSet();
for (int i = 0; i < flowRules.length; i++) {
- f = flowRules[i];
- store.deleteFlowRule(f);
+ toRemoveBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, flowRules[i]));
}
- }
-
- private void removeFlowRulesFromProviders(FlowRule... flowRules) {
- DeviceId did = null;
- FlowRuleProvider frp = null;
- for (FlowRule f : flowRules) {
- if (!f.deviceId().equals(did)) {
- did = f.deviceId();
- final Device device = deviceService.getDevice(did);
- frp = getProvider(device.providerId());
- }
- if (frp != null) {
- frp.removeFlowRule(f);
- }
- }
+ applyBatch(new FlowRuleBatchOperation(toRemoveBatchEntries));
}
@Override
public void removeFlowRulesById(ApplicationId id) {
- Iterable<FlowRule> rules = getFlowRulesById(id);
- FlowRuleProvider frp;
- Device device;
-
- for (FlowRule f : rules) {
- store.deleteFlowRule(f);
- // FIXME: only accept request and push to provider on internal event
- device = deviceService.getDevice(f.deviceId());
- frp = getProvider(device.providerId());
- // FIXME: flows removed from store and flows removed from might diverge
- // get rid of #removeRulesById?
- frp.removeRulesById(id, f);
- }
+ removeFlowRules(Iterables.toArray(getFlowRulesById(id), FlowRule.class));
}
@Override
public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
- return store.getFlowRulesByAppId(id);
+ Set<FlowRule> flowEntries = Sets.newHashSet();
+ for (Device d : deviceService.getDevices()) {
+ for (FlowEntry flowEntry : store.getFlowEntries(d.id())) {
+ if (flowEntry.appId() == id.id()) {
+ flowEntries.add(flowEntry);
+ }
+ }
+ }
+ return flowEntries;
}
@Override
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
index a877b76..d528ed6 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
@@ -1,8 +1,30 @@
package org.onlab.onos.net.intent.impl;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.onos.net.intent.IntentState.COMPILING;
+import static org.onlab.onos.net.intent.IntentState.FAILED;
+import static org.onlab.onos.net.intent.IntentState.INSTALLED;
+import static org.onlab.onos.net.intent.IntentState.INSTALLING;
+import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
+import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
+import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
+import static org.onlab.util.Tools.namedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -29,24 +51,9 @@
import org.onlab.onos.net.intent.IntentStoreDelegate;
import org.slf4j.Logger;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static org.onlab.onos.net.intent.IntentState.*;
-import static org.onlab.util.Tools.namedThreads;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
/**
* An implementation of Intent Manager.
diff --git a/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java b/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
index ad15f56..75e0818 100644
--- a/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
@@ -79,6 +79,12 @@
}
@Override
+ public LinkResourceAllocations updateResources(LinkResourceRequest req,
+ LinkResourceAllocations oldAllocations) {
+ return null;
+ }
+
+ @Override
public Iterable<LinkResourceAllocations> getAllocations() {
// TODO Auto-generated method stub
return null;
@@ -108,4 +114,10 @@
return null;
}
+ @Override
+ public ResourceRequest getAvailableResources(Link link,
+ LinkResourceAllocations allocations) {
+ return null;
+ }
+
}
diff --git a/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
index c5c152c..96b8ae0 100644
--- a/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
@@ -68,15 +68,15 @@
@Test
public void relinquishMastership() {
- //no backups - should turn to standby and no master for device
+ //no backups - should just turn to NONE for device.
mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
assertEquals("wrong role:", MASTER, mgr.getLocalRole(DEV_MASTER));
mgr.relinquishMastership(DEV_MASTER);
assertNull("wrong master:", mgr.getMasterFor(DEV_OTHER));
- assertEquals("wrong role:", STANDBY, mgr.getLocalRole(DEV_MASTER));
+ assertEquals("wrong role:", NONE, mgr.getLocalRole(DEV_MASTER));
//not master, nothing should happen
- mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY);
+ mgr.setRole(NID_LOCAL, DEV_OTHER, NONE);
mgr.relinquishMastership(DEV_OTHER);
assertNull("wrong role:", mgr.getMasterFor(DEV_OTHER));
diff --git a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
index 659a2c4..85ceb3f 100644
--- a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
@@ -12,6 +12,7 @@
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -461,12 +462,12 @@
@Override
public int getDeviceCount() {
- return 0;
+ return 1;
}
@Override
public Iterable<Device> getDevices() {
- return null;
+ return Arrays.asList(DEV);
}
@Override
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/impl/ClusterCommunicationManager.java b/core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/impl/ClusterCommunicationManager.java
index b2f679c..d8e5fab 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/impl/ClusterCommunicationManager.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/impl/ClusterCommunicationManager.java
@@ -4,9 +4,7 @@
import java.io.IOException;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -20,7 +18,6 @@
import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
import org.onlab.onos.store.cluster.messaging.ClusterMessage;
import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
-import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
import org.onlab.onos.store.cluster.messaging.MessageSubject;
import org.onlab.onos.store.serializers.ClusterMessageSerializer;
import org.onlab.onos.store.serializers.KryoNamespaces;
@@ -32,10 +29,11 @@
import org.onlab.netty.MessageHandler;
import org.onlab.netty.MessagingService;
import org.onlab.netty.NettyMessagingService;
-import org.onlab.netty.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.util.concurrent.ListenableFuture;
+
@Component(immediate = true)
@Service
public class ClusterCommunicationManager
@@ -133,14 +131,12 @@
}
@Override
- public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException {
+ public ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException {
ControllerNode node = clusterService.getNode(toNodeId);
checkArgument(node != null, "Unknown nodeId: %s", toNodeId);
Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort());
try {
- Response responseFuture =
- messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message));
- return new InternalClusterMessageResponse(toNodeId, responseFuture);
+ return messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message));
} catch (IOException e) {
log.error("Failed interaction with remote nodeId: " + toNodeId, e);
@@ -188,60 +184,4 @@
rawMessage.respond(response);
}
}
-
- private static final class InternalClusterMessageResponse
- implements ClusterMessageResponse {
-
- private final NodeId sender;
- private final Response responseFuture;
- private volatile boolean isCancelled = false;
- private volatile boolean isDone = false;
-
- public InternalClusterMessageResponse(NodeId sender, Response responseFuture) {
- this.sender = sender;
- this.responseFuture = responseFuture;
- }
- @Override
- public NodeId sender() {
- return sender;
- }
-
- @Override
- public byte[] get(long timeout, TimeUnit timeunit)
- throws TimeoutException {
- final byte[] result = responseFuture.get(timeout, timeunit);
- isDone = true;
- return result;
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (isDone()) {
- return false;
- }
- // doing nothing for now
- // when onlab.netty Response support cancel, call them.
- isCancelled = true;
- return true;
- }
-
- @Override
- public boolean isCancelled() {
- return isCancelled;
- }
-
- @Override
- public boolean isDone() {
- return this.isDone || isCancelled();
- }
-
- @Override
- public byte[] get() throws InterruptedException, ExecutionException {
- // TODO: consider forbidding this call and force the use of timed get
- // to enforce handling of remote peer failure scenario
- final byte[] result = responseFuture.get();
- isDone = true;
- return result;
- }
- }
-}
+}
\ No newline at end of file
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
index cac31c2..dbd2688 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
@@ -12,6 +12,7 @@
import java.util.Collections;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -26,7 +27,6 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
-import org.onlab.onos.ApplicationId;
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
@@ -50,7 +50,6 @@
import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
import org.onlab.onos.store.cluster.messaging.ClusterMessage;
import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
-import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
import org.onlab.onos.store.flow.ReplicaInfo;
import org.onlab.onos.store.flow.ReplicaInfoService;
import org.onlab.onos.store.serializers.DistributedStoreSerializers;
@@ -58,6 +57,7 @@
import org.onlab.util.KryoNamespace;
import org.slf4j.Logger;
+import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -214,9 +214,9 @@
SERIALIZER.encode(rule));
try {
- ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
- return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
- } catch (IOException | TimeoutException e) {
+ Future<byte[]> responseFuture = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
+ return SERIALIZER.decode(responseFuture.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
// FIXME: throw a FlowStoreException
throw new RuntimeException(e);
}
@@ -248,9 +248,9 @@
SERIALIZER.encode(deviceId));
try {
- ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
- return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
- } catch (IOException | TimeoutException e) {
+ Future<byte[]> responseFuture = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
+ return SERIALIZER.decode(responseFuture.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
// FIXME: throw a FlowStoreException
throw new RuntimeException(e);
}
@@ -265,15 +265,6 @@
}
@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 void storeFlowRule(FlowRule rule) {
storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule))));
}
@@ -301,14 +292,17 @@
SERIALIZER.encode(operation));
try {
- ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
- response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (IOException | TimeoutException e) {
- // FIXME: throw a FlowStoreException
- throw new RuntimeException(e);
+ ListenableFuture<byte[]> responseFuture =
+ clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
+ return Futures.transform(responseFuture, new Function<byte[], CompletedBatchOperation>() {
+ @Override
+ public CompletedBatchOperation apply(byte[] input) {
+ return SERIALIZER.decode(input);
+ }
+ });
+ } catch (IOException e) {
+ return Futures.immediateFailedFuture(e);
}
-
- return null;
}
private ListenableFuture<CompletedBatchOperation> storeBatchInternal(FlowRuleBatchOperation operation) {
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
index 273e3cc..7106aef 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
@@ -4,6 +4,7 @@
import static org.slf4j.LoggerFactory.getLogger;
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;
@@ -21,7 +22,6 @@
import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
import org.onlab.onos.store.cluster.messaging.ClusterMessage;
import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
-import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
import org.onlab.onos.store.flow.ReplicaInfo;
import org.onlab.onos.store.flow.ReplicaInfoService;
import org.onlab.onos.store.serializers.KryoNamespaces;
@@ -34,6 +34,8 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -184,11 +186,11 @@
SERIALIZER.encode(connectPoint));
try {
- ClusterMessageResponse response =
+ Future<byte[]> response =
clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS));
- } catch (IOException | TimeoutException e) {
+ } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
// FIXME: throw a StatsStoreException
throw new RuntimeException(e);
}
@@ -212,11 +214,11 @@
SERIALIZER.encode(connectPoint));
try {
- ClusterMessageResponse response =
+ Future<byte[]> response =
clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS));
- } catch (IOException | TimeoutException e) {
+ } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
// FIXME: throw a StatsStoreException
throw new RuntimeException(e);
}
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
index 82ea4e2..8d925bd 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
@@ -7,7 +7,6 @@
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.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowEntry;
@@ -31,9 +30,7 @@
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -143,20 +140,6 @@
}
@Override
- public Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
-
- Set<FlowRule> rules = new HashSet<>();
- for (DeviceId did : flowEntries.keySet()) {
- for (FlowEntry fe : getFlowEntries(did)) {
- if (fe.appId() == appId.id()) {
- rules.add(fe);
- }
- }
- }
- return rules;
- }
-
- @Override
public void storeFlowRule(FlowRule rule) {
storeFlowRuleInternal(rule);
}
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
index 709c95a..a0ac4c7 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
@@ -226,12 +226,34 @@
break;
}
}
+ backups.remove(backup);
return backup;
}
@Override
public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
- return setStandby(nodeId, deviceId);
+ MastershipRole role = getRole(nodeId, deviceId);
+ synchronized (this) {
+ switch (role) {
+ case MASTER:
+ NodeId backup = reelect(nodeId);
+ backups.remove(nodeId);
+ if (backup == null) {
+ masterMap.remove(deviceId);
+ } else {
+ masterMap.put(deviceId, backup);
+ termMap.get(deviceId).incrementAndGet();
+ return new MastershipEvent(MASTER_CHANGED, deviceId,
+ new RoleInfo(backup, Lists.newLinkedList(backups)));
+ }
+ case STANDBY:
+ backups.remove(nodeId);
+ case NONE:
+ default:
+ log.warn("unknown Mastership Role {}", role);
+ }
+ }
+ return null;
}
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
index e04d87c..2a91b5b 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
@@ -33,7 +33,7 @@
import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
@@ -104,8 +104,8 @@
case OF_13:
List<OFInstruction> ins = entry.getInstructions();
for (OFInstruction in : ins) {
- if (in.getType().equals(OFInstructionType.APPLY_ACTIONS)) {
- OFInstructionApplyActions apply = (OFInstructionApplyActions) in;
+ if (in.getType().equals(OFInstructionType.WRITE_ACTIONS)) {
+ OFInstructionWriteActions apply = (OFInstructionWriteActions) in;
return apply.getActions();
}
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
index e1fde8a..e0fb7d9 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
@@ -2,14 +2,8 @@
import static org.slf4j.LoggerFactory.getLogger;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.onlab.onos.net.flow.FlowId;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.TrafficSelector;
-import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
@@ -20,22 +14,10 @@
import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onlab.onos.net.flow.criteria.Criterion;
-import org.onlab.onos.net.flow.instructions.Instruction;
-import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
-import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
-import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowAdd;
import org.projectfloodlight.openflow.protocol.OFFlowDelete;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.CircuitSignalID;
@@ -44,181 +26,82 @@
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.Masked;
-import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.TransportPort;
-import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.types.VlanPcp;
import org.projectfloodlight.openflow.types.VlanVid;
import org.slf4j.Logger;
-
-public class FlowModBuilder {
+/**
+ * Builder for OpenFlow flow mods based on FlowRules.
+ */
+public abstract class FlowModBuilder {
private final Logger log = getLogger(getClass());
private final OFFactory factory;
- private final TrafficTreatment treatment;
+ private final FlowRule flowRule;
private final TrafficSelector selector;
- private final int priority;
+ /**
+ * Creates a new flow mod builder.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @return the new flow mod builder
+ */
+ public static FlowModBuilder builder(FlowRule flowRule, OFFactory factory) {
+ switch (factory.getVersion()) {
+ case OF_10:
+ return new FlowModBuilderVer10(flowRule, factory);
+ case OF_13:
+ return new FlowModBuilderVer13(flowRule, factory);
+ default:
+ throw new UnsupportedOperationException(
+ "No flow mod builder for protocol version " + factory.getVersion());
+ }
+ }
- private final FlowId cookie;
-
-
-
- public FlowModBuilder(FlowRule flowRule, OFFactory factory) {
+ /**
+ * Constructs a flow mod builder.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ */
+ protected FlowModBuilder(FlowRule flowRule, OFFactory factory) {
this.factory = factory;
- this.treatment = flowRule.treatment();
+ this.flowRule = flowRule;
this.selector = flowRule.selector();
- this.priority = flowRule.priority();
- this.cookie = flowRule.id();
}
- public OFFlowAdd buildFlowAdd() {
- Match match = buildMatch();
- List<OFAction> actions = buildActions();
+ /**
+ * Builds an ADD flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowAdd buildFlowAdd();
- //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
- OFFlowAdd fm = factory.buildFlowAdd()
- .setXid(cookie.value())
- .setCookie(U64.of(cookie.value()))
- .setBufferId(OFBufferId.NO_BUFFER)
- .setActions(actions)
- .setMatch(match)
- .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
- .setPriority(priority)
- .build();
+ /**
+ * Builds a MODIFY flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowMod buildFlowMod();
- return fm;
+ /**
+ * Builds a DELETE flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowDelete buildFlowDel();
- }
-
- public OFFlowMod buildFlowMod() {
- Match match = buildMatch();
- List<OFAction> actions = buildActions();
-
- //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
- OFFlowMod fm = factory.buildFlowModify()
- .setXid(cookie.value())
- .setCookie(U64.of(cookie.value()))
- .setBufferId(OFBufferId.NO_BUFFER)
- .setActions(actions)
- .setMatch(match)
- .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
- .setPriority(priority)
- .build();
-
- return fm;
-
- }
-
- public OFFlowDelete buildFlowDel() {
- Match match = buildMatch();
- List<OFAction> actions = buildActions();
-
- OFFlowDelete fm = factory.buildFlowDelete()
- .setXid(cookie.value())
- .setCookie(U64.of(cookie.value()))
- .setBufferId(OFBufferId.NO_BUFFER)
- .setActions(actions)
- .setMatch(match)
- .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
- .setPriority(priority)
- .build();
-
- return fm;
- }
-
- private List<OFAction> buildActions() {
- List<OFAction> acts = new LinkedList<>();
- if (treatment == null) {
- return acts;
- }
- for (Instruction i : treatment.instructions()) {
- switch (i.type()) {
- case DROP:
- log.warn("Saw drop action; assigning drop action");
- return new LinkedList<>();
- case L0MODIFICATION:
- acts.add(buildL0Modification(i));
- break;
- case L2MODIFICATION:
- acts.add(buildL2Modification(i));
- break;
- case L3MODIFICATION:
- acts.add(buildL3Modification(i));
- break;
- case OUTPUT:
- OutputInstruction out = (OutputInstruction) i;
- acts.add(factory.actions().buildOutput().setPort(
- OFPort.of((int) out.port().toLong())).build());
- break;
- case GROUP:
- default:
- log.warn("Instruction type {} not yet implemented.", i.type());
- }
- }
-
- return acts;
- }
-
- private OFAction buildL0Modification(Instruction i) {
- L0ModificationInstruction l0m = (L0ModificationInstruction) i;
- switch (l0m.subtype()) {
- case LAMBDA:
- ModLambdaInstruction ml = (ModLambdaInstruction) i;
- return factory.actions().circuit(factory.oxms().ochSigidBasic(
- new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
- default:
- log.warn("Unimplemented action type {}.", l0m.subtype());
- break;
- }
- return null;
- }
-
- private OFAction buildL3Modification(Instruction i) {
- L3ModificationInstruction l3m = (L3ModificationInstruction) i;
- ModIPInstruction ip;
- switch (l3m.subtype()) {
- case IP_DST:
- ip = (ModIPInstruction) i;
- return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
- case IP_SRC:
- ip = (ModIPInstruction) i;
- return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
- default:
- log.warn("Unimplemented action type {}.", l3m.subtype());
- break;
- }
- return null;
- }
-
- private OFAction buildL2Modification(Instruction i) {
- L2ModificationInstruction l2m = (L2ModificationInstruction) i;
- ModEtherInstruction eth;
- switch (l2m.subtype()) {
- case ETH_DST:
- eth = (ModEtherInstruction) l2m;
- return factory.actions().setDlDst(MacAddress.of(eth.mac().toLong()));
- case ETH_SRC:
- eth = (ModEtherInstruction) l2m;
- return factory.actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
- case VLAN_ID:
- ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
- return factory.actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
- case VLAN_PCP:
- ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
- return factory.actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
- default:
- log.warn("Unimplemented action type {}.", l2m.subtype());
- break;
- }
- return null;
- }
-
- private Match buildMatch() {
+ /**
+ * Builds the match for the flow mod.
+ *
+ * @return the match
+ */
+ protected Match buildMatch() {
Match.Builder mBuilder = factory.buildMatch();
EthCriterion eth;
IPCriterion ip;
@@ -323,6 +206,22 @@
return mBuilder.build();
}
+ /**
+ * Returns the flow rule for this builder.
+ *
+ * @return the flow rule
+ */
+ protected FlowRule flowRule() {
+ return flowRule;
+ }
+ /**
+ * Returns the factory used for building OpenFlow constructs.
+ *
+ * @return the factory
+ */
+ protected OFFactory factory() {
+ return factory;
+ }
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java
new file mode 100644
index 0000000..fd54131
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -0,0 +1,191 @@
+package org.onlab.onos.provider.of.flow.impl;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.instructions.Instruction;
+import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow mod builder for OpenFlow 1.0.
+ */
+public class FlowModBuilderVer10 extends FlowModBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+
+ private final TrafficTreatment treatment;
+
+ /**
+ * Constructor for a flow mod builder for OpenFlow 1.0.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ */
+ protected FlowModBuilderVer10(FlowRule flowRule, OFFactory factory) {
+ super(flowRule, factory);
+
+ this.treatment = flowRule.treatment();
+ }
+
+ @Override
+ public OFFlowAdd buildFlowAdd() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ long cookie = flowRule().id().value();
+
+ //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+ OFFlowAdd fm = factory().buildFlowAdd()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowMod buildFlowMod() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ long cookie = flowRule().id().value();
+
+ //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+ OFFlowMod fm = factory().buildFlowModify()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowDelete buildFlowDel() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ long cookie = flowRule().id().value();
+
+ OFFlowDelete fm = factory().buildFlowDelete()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ private List<OFAction> buildActions() {
+ List<OFAction> acts = new LinkedList<>();
+ if (treatment == null) {
+ return acts;
+ }
+ for (Instruction i : treatment.instructions()) {
+ switch (i.type()) {
+ case DROP:
+ log.warn("Saw drop action; assigning drop action");
+ return new LinkedList<>();
+ case L2MODIFICATION:
+ acts.add(buildL2Modification(i));
+ break;
+ case L3MODIFICATION:
+ acts.add(buildL3Modification(i));
+ break;
+ case OUTPUT:
+ OutputInstruction out = (OutputInstruction) i;
+ acts.add(factory().actions().buildOutput().setPort(
+ OFPort.of((int) out.port().toLong())).build());
+ break;
+ case L0MODIFICATION:
+ case GROUP:
+ log.warn("Instruction type {} not supported with protocol version {}",
+ i.type(), factory().getVersion());
+ break;
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+
+ return acts;
+ }
+
+ private OFAction buildL3Modification(Instruction i) {
+ L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+ ModIPInstruction ip;
+ switch (l3m.subtype()) {
+ case IP_DST:
+ ip = (ModIPInstruction) i;
+ return factory().actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
+ case IP_SRC:
+ ip = (ModIPInstruction) i;
+ return factory().actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
+ default:
+ log.warn("Unimplemented action type {}.", l3m.subtype());
+ break;
+ }
+ return null;
+ }
+
+ private OFAction buildL2Modification(Instruction i) {
+ L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+ ModEtherInstruction eth;
+ switch (l2m.subtype()) {
+ case ETH_DST:
+ eth = (ModEtherInstruction) l2m;
+ return factory().actions().setDlDst(MacAddress.of(eth.mac().toLong()));
+ case ETH_SRC:
+ eth = (ModEtherInstruction) l2m;
+ return factory().actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
+ case VLAN_ID:
+ ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+ return factory().actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
+ case VLAN_PCP:
+ ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+ return factory().actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+ default:
+ log.warn("Unimplemented action type {}.", l2m.subtype());
+ break;
+ }
+ return null;
+ }
+
+}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java
new file mode 100644
index 0000000..35e99e1
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -0,0 +1,226 @@
+package org.onlab.onos.provider.of.flow.impl;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.instructions.Instruction;
+import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
+import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.types.CircuitSignalID;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow mod builder for OpenFlow 1.3+.
+ */
+public class FlowModBuilderVer13 extends FlowModBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+
+ private final TrafficTreatment treatment;
+
+ /**
+ * Constructor for a flow mod builder for OpenFlow 1.3.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ */
+ protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory) {
+ super(flowRule, factory);
+
+ this.treatment = flowRule.treatment();
+ }
+
+ @Override
+ public OFFlowAdd buildFlowAdd() {
+ Match match = buildMatch();
+ OFInstruction writeActions =
+ factory().instructions().writeActions(buildActions());
+
+ long cookie = flowRule().id().value();
+
+ //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+ OFFlowAdd fm = factory().buildFlowAdd()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(Collections.singletonList(writeActions))
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowMod buildFlowMod() {
+ Match match = buildMatch();
+ OFInstruction writeActions =
+ factory().instructions().writeActions(buildActions());
+
+ long cookie = flowRule().id().value();
+
+ //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+ OFFlowMod fm = factory().buildFlowModify()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(Collections.singletonList(writeActions))
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowDelete buildFlowDel() {
+ Match match = buildMatch();
+ OFInstruction writeActions =
+ factory().instructions().writeActions(buildActions());
+
+ long cookie = flowRule().id().value();
+
+ OFFlowDelete fm = factory().buildFlowDelete()
+ .setXid(cookie)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(Collections.singletonList(writeActions))
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ private List<OFAction> buildActions() {
+ List<OFAction> actions = new LinkedList<>();
+ if (treatment == null) {
+ return actions;
+ }
+ for (Instruction i : treatment.instructions()) {
+ switch (i.type()) {
+ case DROP:
+ log.warn("Saw drop action; assigning drop action");
+ return new LinkedList<>();
+ case L0MODIFICATION:
+ actions.add(buildL0Modification(i));
+ break;
+ case L2MODIFICATION:
+ actions.add(buildL2Modification(i));
+ break;
+ case L3MODIFICATION:
+ actions.add(buildL3Modification(i));
+ break;
+ case OUTPUT:
+ OutputInstruction out = (OutputInstruction) i;
+ actions.add(factory().actions().buildOutput().setPort(
+ OFPort.of((int) out.port().toLong())).build());
+ break;
+ case GROUP:
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+
+ return actions;
+ }
+
+ private OFAction buildL0Modification(Instruction i) {
+ L0ModificationInstruction l0m = (L0ModificationInstruction) i;
+ switch (l0m.subtype()) {
+ case LAMBDA:
+ ModLambdaInstruction ml = (ModLambdaInstruction) i;
+ return factory().actions().circuit(factory().oxms().ochSigidBasic(
+ new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
+ default:
+ log.warn("Unimplemented action type {}.", l0m.subtype());
+ break;
+ }
+ return null;
+ }
+
+ private OFAction buildL2Modification(Instruction i) {
+ L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+ ModEtherInstruction eth;
+ OFOxm<?> oxm = null;
+ switch (l2m.subtype()) {
+ case ETH_DST:
+ eth = (ModEtherInstruction) l2m;
+ oxm = factory().oxms().ethDst(MacAddress.of(eth.mac().toLong()));
+ break;
+ case ETH_SRC:
+ eth = (ModEtherInstruction) l2m;
+ oxm = factory().oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
+ break;
+ case VLAN_ID:
+ ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+ oxm = factory().oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId.toShort()));
+ break;
+ case VLAN_PCP:
+ ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+ oxm = factory().oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp));
+ break;
+ default:
+ log.warn("Unimplemented action type {}.", l2m.subtype());
+ break;
+ }
+
+ if (oxm != null) {
+ return factory().actions().buildSetField().setField(oxm).build();
+ }
+ return null;
+ }
+
+ private OFAction buildL3Modification(Instruction i) {
+ L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+ ModIPInstruction ip;
+ OFOxm<?> oxm = null;
+ switch (l3m.subtype()) {
+ case IP_DST:
+ ip = (ModIPInstruction) i;
+ oxm = factory().oxms().ipv4Dst(IPv4Address.of(ip.ip().toInt()));
+ case IP_SRC:
+ ip = (ModIPInstruction) i;
+ oxm = factory().oxms().ipv4Src(IPv4Address.of(ip.ip().toInt()));
+ default:
+ log.warn("Unimplemented action type {}.", l3m.subtype());
+ break;
+ }
+
+ if (oxm != null) {
+ return factory().actions().buildSetField().setField(oxm).build();
+ }
+ return null;
+ }
+
+}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 8d3c018..7fbe09a 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -22,6 +22,7 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.flow.BatchOperation;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowEntry;
import org.onlab.onos.net.flow.FlowEntry;
@@ -31,7 +32,6 @@
import org.onlab.onos.net.flow.FlowRuleProvider;
import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
import org.onlab.onos.net.flow.FlowRuleProviderService;
-import org.onlab.onos.net.flow.BatchOperation;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.topology.TopologyService;
@@ -148,7 +148,7 @@
private void applyRule(FlowRule flowRule) {
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
- sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowAdd());
}
@@ -163,7 +163,7 @@
private void removeRule(FlowRule flowRule) {
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
- sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowDel());
}
@Override
@@ -192,7 +192,7 @@
return failed;
}
sws.add(new Dpid(sw.getId()));
- FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory());
+ FlowModBuilder builder = FlowModBuilder.builder(flowRule, sw.factory());
switch (fbe.getOperator()) {
case ADD:
mod = builder.buildFlowAdd();
diff --git a/utils/netty/src/main/java/org/onlab/netty/AsyncResponse.java b/utils/netty/src/main/java/org/onlab/netty/AsyncResponse.java
deleted file mode 100644
index 1772a3c..0000000
--- a/utils/netty/src/main/java/org/onlab/netty/AsyncResponse.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.onlab.netty;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * An asynchronous response.
- * This class provides a base implementation of Response, with methods to retrieve the
- * result and query to see if the result is ready. The result can only be retrieved when
- * it is ready and the get methods will block if the result is not ready yet.
- */
-public class AsyncResponse implements Response {
-
- private byte[] value;
- private boolean done = false;
- private final long start = System.nanoTime();
-
- @Override
- public byte[] get(long timeout, TimeUnit timeUnit) throws TimeoutException {
- timeout = timeUnit.toNanos(timeout);
- boolean interrupted = false;
- try {
- synchronized (this) {
- while (!done) {
- try {
- long timeRemaining = timeout - (System.nanoTime() - start);
- if (timeRemaining <= 0) {
- throw new TimeoutException("Operation timed out.");
- }
- TimeUnit.NANOSECONDS.timedWait(this, timeRemaining);
- } catch (InterruptedException e) {
- interrupted = true;
- }
- }
- }
- } finally {
- if (interrupted) {
- Thread.currentThread().interrupt();
- }
- }
- return value;
- }
-
- @Override
- public byte[] get() throws InterruptedException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isReady() {
- return done;
- }
-
- /**
- * Sets response value and unblocks any thread blocking on the response to become
- * available.
- * @param data response data.
- */
- public synchronized void setResponse(byte[] data) {
- if (!done) {
- done = true;
- value = data;
- this.notifyAll();
- }
- }
-}
diff --git a/utils/netty/src/main/java/org/onlab/netty/MessagingService.java b/utils/netty/src/main/java/org/onlab/netty/MessagingService.java
index 08676ac..bf93331 100644
--- a/utils/netty/src/main/java/org/onlab/netty/MessagingService.java
+++ b/utils/netty/src/main/java/org/onlab/netty/MessagingService.java
@@ -2,6 +2,8 @@
import java.io.IOException;
+import com.google.common.util.concurrent.ListenableFuture;
+
/**
* Interface for low level messaging primitives.
*/
@@ -24,7 +26,7 @@
* @return a response future
* @throws IOException
*/
- public Response sendAndReceive(Endpoint ep, String type, byte[] payload) throws IOException;
+ public ListenableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload) throws IOException;
/**
* Registers a new message handler for message type.
diff --git a/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java b/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
index 26d835d..1b579f9 100644
--- a/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
+++ b/utils/netty/src/main/java/org/onlab/netty/NettyMessagingService.java
@@ -5,6 +5,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
@@ -26,7 +27,6 @@
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
-import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.slf4j.Logger;
@@ -34,6 +34,8 @@
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
/**
* A Netty based implementation of MessagingService.
@@ -44,7 +46,8 @@
private final Endpoint localEp;
private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>();
- private final Cache<Long, AsyncResponse> responseFutures = CacheBuilder.newBuilder()
+ private final AtomicLong messageIdGenerator = new AtomicLong(0);
+ private final Cache<Long, SettableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder()
.maximumSize(100000)
.weakValues()
// TODO: Once the entry expires, notify blocking threads (if any).
@@ -68,7 +71,7 @@
clientChannelClass = EpollSocketChannel.class;
return;
} catch (Throwable t) {
- log.warn("Failed to initialize native (epoll) transport. Proceeding with nio.", t);
+ log.warn("Failed to initialize native (epoll) transport. Reason: {}. Proceeding with nio.", t.getMessage());
}
clientGroup = new NioEventLoopGroup();
serverGroup = new NioEventLoopGroup();
@@ -119,7 +122,7 @@
@Override
public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException {
InternalMessage message = new InternalMessage.Builder(this)
- .withId(RandomUtils.nextLong())
+ .withId(messageIdGenerator.incrementAndGet())
.withSender(localEp)
.withType(type)
.withPayload(payload)
@@ -142,10 +145,10 @@
}
@Override
- public Response sendAndReceive(Endpoint ep, String type, byte[] payload)
+ public ListenableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload)
throws IOException {
- AsyncResponse futureResponse = new AsyncResponse();
- Long messageId = RandomUtils.nextLong();
+ SettableFuture<byte[]> futureResponse = SettableFuture.create();
+ Long messageId = messageIdGenerator.incrementAndGet();
responseFutures.put(messageId, futureResponse);
InternalMessage message = new InternalMessage.Builder(this)
.withId(messageId)
@@ -267,10 +270,10 @@
String type = message.type();
if (type.equals(InternalMessage.REPLY_MESSAGE_TYPE)) {
try {
- AsyncResponse futureResponse =
+ SettableFuture<byte[]> futureResponse =
NettyMessagingService.this.responseFutures.getIfPresent(message.id());
if (futureResponse != null) {
- futureResponse.setResponse(message.payload());
+ futureResponse.set(message.payload());
} else {
log.warn("Received a reply. But was unable to locate the request handle");
}
diff --git a/utils/netty/src/main/java/org/onlab/netty/Response.java b/utils/netty/src/main/java/org/onlab/netty/Response.java
deleted file mode 100644
index 150755e..0000000
--- a/utils/netty/src/main/java/org/onlab/netty/Response.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.onlab.netty;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Response object returned when making synchronous requests.
- * Can you used to check is a response is ready and/or wait for a response
- * to become available.
- */
-public interface Response {
-
- /**
- * Gets the response waiting for a designated timeout period.
- * @param timeout timeout period (since request was sent out)
- * @param tu unit of time.
- * @return response payload
- * @throws TimeoutException if the timeout expires before the response arrives.
- */
- public byte[] get(long timeout, TimeUnit tu) throws TimeoutException;
-
- /**
- * Gets the response waiting for indefinite timeout period.
- * @return response payload
- * @throws InterruptedException if the thread is interrupted before the response arrives.
- */
- public byte[] get() throws InterruptedException;
-
- /**
- * Checks if the response is ready without blocking.
- * @return true if response is ready, false otherwise.
- */
- public boolean isReady();
-}
diff --git a/utils/netty/src/test/java/org/onlab/netty/PingPongTest.java b/utils/netty/src/test/java/org/onlab/netty/PingPongTest.java
index 36d2a1e..ddcdd6f 100644
--- a/utils/netty/src/test/java/org/onlab/netty/PingPongTest.java
+++ b/utils/netty/src/test/java/org/onlab/netty/PingPongTest.java
@@ -1,9 +1,12 @@
package org.onlab.netty;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.RandomUtils;
+
import static org.junit.Assert.*;
+
import org.junit.Test;
/**
@@ -20,8 +23,8 @@
ponger.activate();
ponger.registerHandler("echo", new EchoHandler());
byte[] payload = RandomUtils.nextBytes(100);
- Response response = pinger.sendAndReceive(new Endpoint("localhost", 9086), "echo", payload);
- assertArrayEquals(payload, response.get(10000, TimeUnit.MILLISECONDS));
+ Future<byte[]> responseFuture = pinger.sendAndReceive(new Endpoint("localhost", 9086), "echo", payload);
+ assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS));
} finally {
pinger.deactivate();
ponger.deactivate();
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyResource.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyResource.java
new file mode 100644
index 0000000..1a97a56
--- /dev/null
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyResource.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.onlab.onos.gui;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Device;
+import org.onlab.onos.net.Host;
+import org.onlab.onos.net.HostLocation;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.device.DeviceService;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.link.LinkService;
+import org.onlab.onos.net.topology.Topology;
+import org.onlab.onos.net.topology.TopologyGraph;
+import org.onlab.onos.net.topology.TopologyService;
+import org.onlab.onos.net.topology.TopologyVertex;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.rest.BaseResource;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Topology viewer resource.
+ */
+@javax.ws.rs.Path("topology")
+public class TopologyResource extends BaseResource {
+
+ @javax.ws.rs.Path("/graph")
+ @GET
+ @Produces("application/json")
+ public Response graph() {
+ // Fetch the services we'll be using.
+ DeviceService deviceService = get(DeviceService.class);
+ HostService hostService = get(HostService.class);
+ TopologyService topologyService = get(TopologyService.class);
+
+ // Fetch the current topology and its graph that we'll use to render.
+ Topology topo = topologyService.currentTopology();
+ TopologyGraph graph = topologyService.getGraph(topo);
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.set("devices", getDevices(mapper, deviceService, graph));
+ rootNode.set("links", getLinks(mapper, topo, graph));
+ rootNode.set("hosts", getHosts(mapper, hostService));
+ return Response.ok(rootNode.toString()).build();
+ }
+
+ // Encodes all infrastructure devices.
+ private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService,
+ TopologyGraph graph) {
+ ArrayNode devices = mapper.createArrayNode();
+ for (TopologyVertex vertex : graph.getVertexes()) {
+ devices.add(json(mapper, deviceService.getDevice(vertex.deviceId()),
+ deviceService.isAvailable(vertex.deviceId())));
+ }
+ return devices;
+ }
+
+ // Encodes all infrastructure links.
+ private ArrayNode getLinks(ObjectMapper mapper, Topology topo, TopologyGraph graph) {
+ // Now scan all links and count number of them between the same devices
+ // using a normalized link key.
+ Map<String, AggLink> linkRecords = aggregateLinks();
+
+ // Now build all interior edges using the aggregated links.
+ ArrayNode links = mapper.createArrayNode();
+ for (AggLink lr : linkRecords.values()) {
+ links.add(json(mapper, lr));
+ }
+ return links;
+ }
+
+ // Encodes all end-station hosts.
+ private ArrayNode getHosts(ObjectMapper mapper, HostService hostService) {
+ ArrayNode hosts = mapper.createArrayNode();
+ for (Host host : hostService.getHosts()) {
+ Set<IpPrefix> ipAddresses = host.ipAddresses();
+ IpPrefix ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
+ String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
+ hosts.add(json(mapper, host));
+ }
+ return hosts;
+ }
+
+ // Scan all links and counts number of them between the same devices
+ // using a normalized link key.
+ private Map<String, AggLink> aggregateLinks() {
+ Map<String, AggLink> aggLinks = new HashMap<>();
+ LinkService linkService = get(LinkService.class);
+ for (Link link : linkService.getLinks()) {
+ String key = key(link);
+ AggLink lr = aggLinks.get(key);
+ if (lr == null) {
+ lr = new AggLink(key);
+ aggLinks.put(key, lr);
+ }
+ lr.addLink(link);
+ }
+ return aggLinks;
+ }
+
+ // Produces JSON for a device.
+ private ObjectNode json(ObjectMapper mapper, Device device, boolean isOnline) {
+ ObjectNode node = mapper.createObjectNode()
+ .put("id", device.id().toString())
+ .put("type", device.type().toString().toLowerCase())
+ .put("online", isOnline);
+ node.set("labels", labels(mapper,
+ device.id().uri().getSchemeSpecificPart(),
+ MacAddress.valueOf(device.chassisId().value()).toString(),
+ device.serialNumber()));
+ return node;
+ }
+
+ // Produces JSON for a link.
+ private ObjectNode json(ObjectMapper mapper, AggLink aggLink) {
+ Link link = aggLink.link;
+ return mapper.createObjectNode()
+ .put("src", link.src().deviceId().toString())
+ .put("dst", link.dst().deviceId().toString())
+ .put("type", link.type().toString().toLowerCase())
+ .put("linkWidth", aggLink.links.size());
+ }
+
+ // Produces JSON for a device.
+ private ObjectNode json(ObjectMapper mapper, Host host) {
+ ObjectNode json = mapper.createObjectNode()
+ .put("id", host.id().toString());
+ json.set("cp", location(mapper, host.location()));
+ json.set("labels", labels(mapper, ip(host.ipAddresses()),
+ host.mac().toString()));
+ return json;
+ }
+
+ private String ip(Set<IpPrefix> ipPrefixes) {
+ Iterator<IpPrefix> it = ipPrefixes.iterator();
+ return it.hasNext() ? it.next().toString() : "unknown";
+ }
+
+ private ObjectNode location(ObjectMapper mapper, HostLocation location) {
+ return mapper.createObjectNode()
+ .put("device", location.deviceId().toString())
+ .put("port", location.port().toLong());
+ }
+
+ private ArrayNode labels(ObjectMapper mapper, String... labels) {
+ ArrayNode json = mapper.createArrayNode();
+ for (String label : labels) {
+ json.add(label);
+ }
+ return json;
+ }
+
+ // Aggregate link of all links between the same devices regardless of
+ // their direction.
+ private class AggLink {
+ Link link; // representative links
+
+ final String key;
+ final Set<Link> links = new HashSet<>();
+
+ AggLink(String key) {
+ this.key = key;
+ }
+
+ void addLink(Link link) {
+ links.add(link);
+ if (this.link == null) {
+ this.link = link;
+ }
+ }
+ }
+
+ // Returns a canonical key for the specified link.
+ static String key(Link link) {
+ String s = id(link.src());
+ String d = id(link.dst());
+ return s.compareTo(d) > 0 ? d + s : s + d;
+ }
+
+ // Returns a formatted string for the element associated with the given
+ // connection point.
+ private static String id(ConnectPoint cp) {
+ return cp.elementId().toString();
+ }
+
+}
diff --git a/web/gui/src/main/webapp/network.js b/web/gui/src/main/webapp/network.js
index c5145ad..6cf1899 100644
--- a/web/gui/src/main/webapp/network.js
+++ b/web/gui/src/main/webapp/network.js
@@ -14,6 +14,7 @@
layering: true,
collisionPrevention: true
},
+ XjsonUrl: 'rs/topology/graph',
jsonUrl: 'network.json',
iconUrl: {
device: 'img/device.png',