Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/cli/src/main/java/org/onlab/onos/cli/GreetCommand.java b/cli/src/main/java/org/onlab/onos/cli/GreetCommand.java
deleted file mode 100644
index 71e56f1..0000000
--- a/cli/src/main/java/org/onlab/onos/cli/GreetCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.onlab.onos.cli;
-
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.onlab.onos.GreetService;
-
-/**
- * Simple command example to demonstrate use of Karaf shell extensions; shows
- * use of an optional parameter as well.
- */
-@Command(scope = "onos", name = "greet", description = "Issues a greeting")
-public class GreetCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "name", description = "Name to greet",
- required = false, multiValued = false)
- String name = "dude";
-
- @Override
- protected Object doExecute() throws Exception {
- print(getService(GreetService.class).yo(name));
- return null;
- }
-}
diff --git a/cli/src/main/java/org/onlab/onos/cli/NameCompleter.java b/cli/src/main/java/org/onlab/onos/cli/NameCompleter.java
deleted file mode 100644
index bcf0707..0000000
--- a/cli/src/main/java/org/onlab/onos/cli/NameCompleter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.onlab.onos.cli;
-
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.onlab.onos.GreetService;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-
-/**
- * Simple example of a command-line parameter completer.
- * For a more open-ended sets a more efficient implementation would be required.
- */
-public class NameCompleter implements Completer {
- @Override
- public int complete(String buffer, int cursor, List<String> candidates) {
- // Delegate string completer
- StringsCompleter delegate = new StringsCompleter();
-
- // Fetch our service and feed it's offerings to the string completer
- GreetService greetService = AbstractShellCommand.get(GreetService.class);
- Iterator<String> it = greetService.names().iterator();
- SortedSet<String> strings = delegate.getStrings();
- while (it.hasNext()) {
- strings.add(it.next());
- }
-
- // Now let the completer do the work for figuring out what to offer.
- return delegate.complete(buffer, cursor, candidates);
- }
-
-}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 96c494d..fb44199 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -30,18 +30,9 @@
<ref component-id="deviceIdCompleter"/>
</completers>
</command>
-
- <command>
- <action class="org.onlab.onos.cli.GreetCommand"/>
- <completers>
- <ref component-id="nameCompleter"/>
- </completers>
- </command>
</command-bundle>
<bean id="deviceIdCompleter" class="org.onlab.onos.cli.net.DeviceIdCompleter"/>
<bean id="roleCompleter" class="org.onlab.onos.cli.net.RoleCompleter"/>
- <bean id="nameCompleter" class="org.onlab.onos.cli.NameCompleter"/>
-
</blueprint>
diff --git a/core/api/src/main/java/org/onlab/onos/net/DefaultLink.java b/core/api/src/main/java/org/onlab/onos/net/DefaultLink.java
index 1f7783c..e937bf3 100644
--- a/core/api/src/main/java/org/onlab/onos/net/DefaultLink.java
+++ b/core/api/src/main/java/org/onlab/onos/net/DefaultLink.java
@@ -16,7 +16,7 @@
private final Type type;
/**
- * Creates a link description using the supplied information.
+ * Creates an infrastructure link using the supplied information.
*
* @param providerId provider identity
* @param src link source
diff --git a/core/api/src/main/java/org/onlab/onos/net/DefaultPath.java b/core/api/src/main/java/org/onlab/onos/net/DefaultPath.java
new file mode 100644
index 0000000..63c9e88
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/DefaultPath.java
@@ -0,0 +1,71 @@
+package org.onlab.onos.net;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.onos.net.provider.ProviderId;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of a network path.
+ */
+public class DefaultPath extends DefaultLink implements Path {
+
+ private final List<Link> links;
+ private final double cost;
+
+ /**
+ * Creates a path from the specified source and destination using the
+ * supplied list of links.
+ *
+ * @param providerId provider identity
+ * @param links contiguous links that comprise the path
+ * @param cost unit-less path cost
+ */
+ public DefaultPath(ProviderId providerId, List<Link> links, double cost) {
+ super(providerId, source(links), destination(links), Type.INDIRECT);
+ this.links = ImmutableList.copyOf(links);
+ this.cost = cost;
+ }
+
+ @Override
+ public List<Link> links() {
+ return links;
+ }
+
+ @Override
+ public double cost() {
+ return cost;
+ }
+
+ // Returns the source of the first link.
+ private static ConnectPoint source(List<Link> links) {
+ checkNotNull(links, "List of path links cannot be null");
+ checkArgument(!links.isEmpty(), "List of path links cannot be empty");
+ return links.get(0).src();
+ }
+
+ // Returns the destination of the last link.
+ private static ConnectPoint destination(List<Link> links) {
+ checkNotNull(links, "List of path links cannot be null");
+ checkArgument(!links.isEmpty(), "List of path links cannot be empty");
+ return links.get(links.size() - 1).dst();
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(links);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof DefaultPath) {
+ final DefaultPath other = (DefaultPath) obj;
+ return Objects.equals(this.links, other.links);
+ }
+ return false;
+ }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/Path.java b/core/api/src/main/java/org/onlab/onos/net/Path.java
index 22a363a..acf8170 100644
--- a/core/api/src/main/java/org/onlab/onos/net/Path.java
+++ b/core/api/src/main/java/org/onlab/onos/net/Path.java
@@ -17,4 +17,11 @@
*/
List<Link> links();
+ /**
+ * Returns the path cost as a unit-less value.
+ *
+ * @return unit-less path cost
+ */
+ double cost();
+
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/ClusterId.java b/core/api/src/main/java/org/onlab/onos/net/topology/ClusterId.java
index af8f122..502eee1 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/ClusterId.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/ClusterId.java
@@ -27,6 +27,15 @@
return new ClusterId(id);
}
+ /**
+ * Returns the backing integer index.
+ *
+ * @return backing integer index
+ */
+ public int index() {
+ return id;
+ }
+
@Override
public int hashCode() {
return Objects.hash(id);
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/GraphDescription.java b/core/api/src/main/java/org/onlab/onos/net/topology/GraphDescription.java
new file mode 100644
index 0000000..2b846a0
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/GraphDescription.java
@@ -0,0 +1,34 @@
+package org.onlab.onos.net.topology;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.onos.net.Description;
+
+/**
+ * Describes attribute(s) of a network graph.
+ */
+public interface GraphDescription extends Description {
+
+ /**
+ * Returns the creation timestamp of the graph description. This is
+ * expressed in system nanos to allow proper sequencing.
+ *
+ * @return graph description creation timestamp
+ */
+ long timestamp();
+
+ /**
+ * Returns the set of topology graph vertexes.
+ *
+ * @return set of graph vertexes
+ */
+ ImmutableSet<TopologyVertex> vertexes();
+
+ /**
+ * Returns the set of topology graph edges.
+ *
+ * @return set of graph edges
+ */
+ ImmutableSet<TopologyEdge> edges();
+
+}
+
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/LinkWeight.java b/core/api/src/main/java/org/onlab/onos/net/topology/LinkWeight.java
index 89ef577..5e18dfb 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/LinkWeight.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/LinkWeight.java
@@ -6,5 +6,5 @@
* Entity capable of determining cost or weight of a specified topology
* graph edge.
*/
-public interface LinkWeight extends EdgeWeight<TopoVertex, TopoEdge> {
+public interface LinkWeight extends EdgeWeight<TopologyVertex, TopologyEdge> {
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyDescription.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyDescription.java
deleted file mode 100644
index dd0102d..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyDescription.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.onlab.onos.net.topology;
-
-import org.onlab.graph.Graph;
-import org.onlab.graph.GraphPathSearch;
-import org.onlab.onos.net.Description;
-import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.Link;
-
-import java.util.Set;
-
-/**
- * Describes attribute(s) of a network topology.
- */
-public interface TopologyDescription extends Description {
-
- /**
- * Returns the creation timestamp of the topology description. This is
- * expressed in system nanos to allow proper sequencing.
- *
- * @return topology description creation timestamp
- */
- long timestamp();
-
- /**
- * Returns the topology graph.
- *
- * @return network graph
- */
- Graph<TopoVertex, TopoEdge> graph();
-
- /**
- * Returns the results of the path search through the network graph. This
- * is assumed to contain results of seach fro the given device to all
- * other devices.
- *
- * @param srcDeviceId source device identifier
- * @return path search result for the given source node
- */
- GraphPathSearch.Result pathResults(DeviceId srcDeviceId);
-
- /**
- * Returns the set of topology SCC clusters.
- *
- * @return set of SCC clusters
- */
- Set<TopologyCluster> clusters();
-
- /**
- * Returns the set of devices contained by the specified topology cluster.
- *
- * @return set of devices that belong to the specified cluster
- */
- Set<DeviceId> clusterDevices(TopologyCluster cluster);
-
- /**
- * Returns the set of infrastructure links contained by the specified cluster.
- *
- * @return set of links that form the given cluster
- */
- Set<Link> clusterLinks(TopologyCluster cluster);
-
- /**
- * Returns the topology SCC cluster which contains the given device.
- *
- * @param deviceId device identifier
- * @return topology cluster that contains the specified device
- */
- TopologyCluster clusterFor(DeviceId deviceId);
-
-}
-
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopoEdge.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyEdge.java
similarity index 82%
rename from core/api/src/main/java/org/onlab/onos/net/topology/TopoEdge.java
rename to core/api/src/main/java/org/onlab/onos/net/topology/TopologyEdge.java
index ef94eca..d9cd6f4 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopoEdge.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyEdge.java
@@ -6,7 +6,7 @@
/**
* Represents an edge in the topology graph.
*/
-public interface TopoEdge extends Edge<TopoVertex> {
+public interface TopologyEdge extends Edge<TopologyVertex> {
/**
* Returns the associated infrastructure link.
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyGraph.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyGraph.java
new file mode 100644
index 0000000..70139cd
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyGraph.java
@@ -0,0 +1,10 @@
+package org.onlab.onos.net.topology;
+
+import org.onlab.graph.Graph;
+
+/**
+ * Represents an immutable topology graph.
+ */
+public interface TopologyGraph extends Graph<TopologyVertex, TopologyEdge> {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyProviderService.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyProviderService.java
index 0e03767..c81a871 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyProviderService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyProviderService.java
@@ -10,16 +10,13 @@
*/
public interface TopologyProviderService extends ProviderService<TopologyProvider> {
- // What can be conveyed in a topology that isn't by individual
- // providers?
-
/**
* Signals the core that some aspect of the topology has changed.
*
- * @param topoDescription information about topology
- * @param reasons events that triggered topology change
+ * @param graphDescription information about the network graph
+ * @param reasons events that triggered topology change
*/
- void topologyChanged(TopologyDescription topoDescription,
+ void topologyChanged(GraphDescription graphDescription,
List<Event> reasons);
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java
index 7c6be33..d8470e7 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java
@@ -1,6 +1,5 @@
package org.onlab.onos.net.topology;
-import org.onlab.graph.Graph;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Path;
@@ -21,6 +20,7 @@
/**
* Indicates whether the specified topology is the latest or not.
+ *
* @param topology topology descriptor
* @return true if the topology is the most recent; false otherwise
*/
@@ -40,7 +40,7 @@
* @param topology topology descriptor
* @return topology graph view
*/
- Graph<TopoVertex, TopoEdge> getGraph(Topology topology);
+ TopologyGraph getGraph(Topology topology);
/**
* Returns the set of all shortest paths, precomputed in terms of hop-count,
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopoVertex.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyVertex.java
similarity index 86%
rename from core/api/src/main/java/org/onlab/onos/net/topology/TopoVertex.java
rename to core/api/src/main/java/org/onlab/onos/net/topology/TopologyVertex.java
index d5a8b95..96a918f 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopoVertex.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyVertex.java
@@ -6,7 +6,7 @@
/**
* Represents a vertex in the topology graph.
*/
-public interface TopoVertex extends Vertex {
+public interface TopologyVertex extends Vertex {
/**
* Returns the associated infrastructure device identification.
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultGraphDescription.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultGraphDescription.java
new file mode 100644
index 0000000..59ef8df
--- /dev/null
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultGraphDescription.java
@@ -0,0 +1,90 @@
+package org.onlab.onos.net.trivial.topology.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Device;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.topology.GraphDescription;
+import org.onlab.onos.net.topology.TopologyEdge;
+import org.onlab.onos.net.topology.TopologyVertex;
+
+import java.util.Map;
+
+/**
+ * Default implementation of an immutable topology graph data carrier.
+ */
+class DefaultGraphDescription implements GraphDescription {
+
+ private final long nanos;
+ private final ImmutableSet<TopologyVertex> vertexes;
+ private final ImmutableSet<TopologyEdge> edges;
+
+ private final Map<DeviceId, TopologyVertex> vertexesById = Maps.newHashMap();
+
+
+ /**
+ * Creates a minimal topology graph description to allow core to construct
+ * and process the topology graph.
+ *
+ * @param nanos time in nanos of when the topology description was created
+ * @param devices collection of infrastructure devices
+ * @param links collection of infrastructure links
+ */
+ DefaultGraphDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
+ this.nanos = nanos;
+ this.vertexes = buildVertexes(devices);
+ this.edges = buildEdges(links);
+ vertexesById.clear();
+ }
+
+ @Override
+ public long timestamp() {
+ return nanos;
+ }
+
+ @Override
+ public ImmutableSet<TopologyVertex> vertexes() {
+ return vertexes;
+ }
+
+ @Override
+ public ImmutableSet<TopologyEdge> edges() {
+ return edges;
+ }
+
+ // Builds a set of topology vertexes from the specified list of devices
+ private ImmutableSet<TopologyVertex> buildVertexes(Iterable<Device> devices) {
+ ImmutableSet.Builder<TopologyVertex> vertexes = ImmutableSet.builder();
+ for (Device device : devices) {
+ TopologyVertex vertex = new DefaultTopologyVertex(device.id());
+ vertexes.add(vertex);
+ vertexesById.put(vertex.deviceId(), vertex);
+ }
+ return vertexes.build();
+ }
+
+ // Builds a set of topology vertexes from the specified list of links
+ private ImmutableSet<TopologyEdge> buildEdges(Iterable<Link> links) {
+ ImmutableSet.Builder<TopologyEdge> edges = ImmutableSet.builder();
+ for (Link link : links) {
+ edges.add(new DefaultTopologyEdge(vertexOf(link.src()),
+ vertexOf(link.dst()), link));
+ }
+ return edges.build();
+ }
+
+ // Fetches a vertex corresponding to the given connection point device.
+ private TopologyVertex vertexOf(ConnectPoint connectPoint) {
+ DeviceId id = connectPoint.deviceId();
+ TopologyVertex vertex = vertexesById.get(id);
+ if (vertex == null) {
+ // If vertex does not exist, create one and register it.
+ vertex = new DefaultTopologyVertex(id);
+ vertexesById.put(id, vertex);
+ }
+ return vertex;
+ }
+
+}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopology.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopology.java
index c20acd8..86b88b3 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopology.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopology.java
@@ -1,8 +1,38 @@
package org.onlab.onos.net.trivial.topology.impl;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import org.onlab.graph.DijkstraGraphSearch;
+import org.onlab.graph.GraphPathSearch;
+import org.onlab.graph.TarjanGraphSearch;
import org.onlab.onos.net.AbstractModel;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DefaultPath;
+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.DefaultTopologyCluster;
+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.TopologyEdge;
+import org.onlab.onos.net.topology.TopologyGraph;
+import org.onlab.onos.net.topology.TopologyVertex;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.collect.ImmutableSetMultimap.Builder;
+import static org.onlab.graph.GraphPathSearch.Result;
+import static org.onlab.graph.TarjanGraphSearch.SCCResult;
+import static org.onlab.onos.net.Link.Type.INDIRECT;
/**
* Default implementation of the topology descriptor. This carries the
@@ -10,30 +40,53 @@
*/
public class DefaultTopology extends AbstractModel implements Topology {
+ private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA =
+ new DijkstraGraphSearch<>();
+ private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN =
+ new TarjanGraphSearch<>();
+
+ private static final ProviderId PID = new ProviderId("org.onlab.onos.net");
+
private final long time;
- private final int clusterCount;
- private final int deviceCount;
- private final int linkCount;
- private final int pathCount;
+ private final TopologyGraph graph;
+
+ private final SCCResult<TopologyVertex, TopologyEdge> clusterResults;
+ private final ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> results;
+ private final ImmutableSetMultimap<PathKey, Path> paths;
+
+ private final ImmutableMap<ClusterId, TopologyCluster> clusters;
+ private final ImmutableSet<ConnectPoint> infrastructurePoints;
+ private final ImmutableSetMultimap<ClusterId, ConnectPoint> broadcastSets;
+
+ private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
+ private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
+ private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
+
/**
* Creates a topology descriptor attributed to the specified provider.
*
- * @param providerId identity of the provider
- * @param time creation time in system nanos
- * @param clusterCount number of clusters
- * @param deviceCount number of devices
- * @param linkCount number of links
- * @param pathCount number of pre-computed paths
+ * @param providerId identity of the provider
+ * @param description data describing the new topology
*/
- DefaultTopology(ProviderId providerId, long time, int clusterCount,
- int deviceCount, int linkCount, int pathCount) {
+ DefaultTopology(ProviderId providerId, GraphDescription description) {
super(providerId);
- this.time = time;
- this.clusterCount = clusterCount;
- this.deviceCount = deviceCount;
- this.linkCount = linkCount;
- this.pathCount = pathCount;
+ this.time = description.timestamp();
+
+ // Build the graph
+ this.graph = new DefaultTopologyGraph(description.vertexes(),
+ description.edges());
+
+ this.results = searchForShortestPaths();
+ this.paths = buildPaths();
+
+ this.clusterResults = searchForClusters();
+ this.clusters = buildTopologyClusters();
+
+ buildIndexes();
+
+ this.broadcastSets = buildBroadcastSets();
+ this.infrastructurePoints = findInfrastructurePoints();
}
@Override
@@ -43,22 +96,318 @@
@Override
public int clusterCount() {
- return clusterCount;
+ return clusters.size();
}
@Override
public int deviceCount() {
- return deviceCount;
+ return graph.getVertexes().size();
}
@Override
public int linkCount() {
- return linkCount;
+ return graph.getEdges().size();
}
@Override
public int pathCount() {
- return pathCount;
+ return paths.size();
}
+ /**
+ * Returns the backing topology graph.
+ *
+ * @return topology graph
+ */
+ TopologyGraph getGraph() {
+ return graph;
+ }
+
+ /**
+ * Returns the set of topology clusters.
+ *
+ * @return set of clusters
+ */
+ Set<TopologyCluster> getClusters() {
+ return ImmutableSet.copyOf(clusters.values());
+ }
+
+ /**
+ * Returns the set of cluster devices.
+ *
+ * @param cluster topology cluster
+ * @return cluster devices
+ */
+ Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
+ return devicesByCluster.get(cluster);
+ }
+
+ /**
+ * Returns the set of cluster links.
+ *
+ * @param cluster topology cluster
+ * @return cluster links
+ */
+ Set<Link> getClusterLinks(TopologyCluster cluster) {
+ return linksByCluster.get(cluster);
+ }
+
+ /**
+ * Indicates whether the given point is an infrastructure link end-point.
+ *
+ * @param connectPoint connection point
+ * @return true if infrastructure
+ */
+ boolean isInfrastructure(ConnectPoint connectPoint) {
+ return infrastructurePoints.contains(connectPoint);
+ }
+
+ /**
+ * Indicates whether the given point is part of a broadcast tree.
+ *
+ * @param connectPoint connection point
+ * @return true if in broadcast tree
+ */
+ boolean isInBroadcastTree(ConnectPoint connectPoint) {
+ // Any non-infrastructure, i.e. edge points are assumed to be OK
+ if (!isInfrastructure(connectPoint)) {
+ return true;
+ }
+
+ // Find the cluster to which the device belongs.
+ TopologyCluster cluster = clustersByDevice.get(connectPoint.deviceId());
+ if (cluster == null) {
+ throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId());
+ }
+
+ // If the broadcast tree is null or empty, or if the point explicitly
+ // belongs to the broadcast tree points, return true;
+ Set<ConnectPoint> points = broadcastSets.get(cluster.id());
+ return points == null || points.isEmpty() || points.contains(connectPoint);
+ }
+
+ /**
+ * Returns the set of pre-computed shortest paths between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @return set of shortest paths
+ */
+ Set<Path> getPaths(DeviceId src, DeviceId dst) {
+ return paths.get(new PathKey(src, dst));
+ }
+
+ /**
+ * Computes on-demand the set of shortest paths between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @return set of shortest paths
+ */
+ Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
+ GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
+ DIJKSTRA.search(graph, new DefaultTopologyVertex(src),
+ new DefaultTopologyVertex(dst), weight);
+ ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
+ for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
+ builder.add(networkPath(path));
+ }
+ return builder.build();
+ }
+
+
+ // Searches the graph for all shortest paths and returns the search results.
+ private ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> searchForShortestPaths() {
+ ImmutableMap.Builder<DeviceId, Result<TopologyVertex, TopologyEdge>> builder = ImmutableMap.builder();
+
+ // Search graph paths for each source to all destinations.
+ LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
+ for (TopologyVertex src : graph.getVertexes()) {
+ builder.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
+ }
+ return builder.build();
+ }
+
+ // Builds network paths from the graph path search results
+ private ImmutableSetMultimap<PathKey, Path> buildPaths() {
+ Builder<PathKey, Path> builder = ImmutableSetMultimap.builder();
+ for (DeviceId deviceId : results.keySet()) {
+ Result<TopologyVertex, TopologyEdge> result = results.get(deviceId);
+ for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
+ builder.put(new PathKey(path.src().deviceId(), path.dst().deviceId()),
+ networkPath(path));
+ }
+ }
+ return builder.build();
+ }
+
+ // Converts graph path to a network path with the same cost.
+ private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
+ List<Link> links = new ArrayList<>();
+ for (TopologyEdge edge : path.edges()) {
+ links.add(edge.link());
+ }
+ return new DefaultPath(PID, links, path.cost());
+ }
+
+
+ // Searches for SCC clusters in the network topology graph using Tarjan
+ // algorithm.
+ private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
+ return TARJAN.search(graph, new NoIndirectLinksWeight());
+ }
+
+ // Builds the topology clusters and returns the id-cluster bindings.
+ private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
+ ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
+ SCCResult<TopologyVertex, TopologyEdge> result =
+ TARJAN.search(graph, new NoIndirectLinksWeight());
+
+ // Extract both vertexes and edges from the results; the lists form
+ // pairs along the same index.
+ List<Set<TopologyVertex>> clusterVertexes = result.clusterVertexes();
+ List<Set<TopologyEdge>> clusterEdges = result.clusterEdges();
+
+ // Scan over the lists and create a cluster from the results.
+ for (int i = 0, n = result.clusterCount(); i < n; i++) {
+ Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
+ Set<TopologyEdge> edgeSet = clusterEdges.get(i);
+
+ ClusterId cid = ClusterId.clusterId(i);
+ DefaultTopologyCluster cluster =
+ new DefaultTopologyCluster(cid, vertexSet.size(), edgeSet.size(),
+ findRoot(vertexSet).deviceId());
+ clusterBuilder.put(cid, cluster);
+ }
+ return clusterBuilder.build();
+ }
+
+ // Finds the vertex whose device id is the lexicographical minimum in the
+ // specified set.
+ private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
+ TopologyVertex minVertex = null;
+ for (TopologyVertex vertex : vertexSet) {
+ if (minVertex == null ||
+ minVertex.deviceId().toString()
+ .compareTo(minVertex.deviceId().toString()) < 0) {
+ minVertex = vertex;
+ }
+ }
+ return minVertex;
+ }
+
+ // Processes a map of broadcast sets for each cluster.
+ private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
+ Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
+ for (TopologyCluster cluster : clusters.values()) {
+ addClusterBroadcastSet(cluster, builder);
+ }
+ return builder.build();
+ }
+
+ // Finds all broadcast points for the cluster. These are those connection
+ // points which lie along the shortest paths between the cluster root and
+ // all other devices within the cluster.
+ private void addClusterBroadcastSet(TopologyCluster cluster,
+ Builder<ClusterId, ConnectPoint> builder) {
+ // Use the graph root search results to build the broadcast set.
+ Result<TopologyVertex, TopologyEdge> result = results.get(cluster.root());
+ for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
+ TopologyVertex vertex = entry.getKey();
+
+ // Ignore any parents that lead outside the cluster.
+ if (clustersByDevice.get(vertex.deviceId()) != cluster) {
+ continue;
+ }
+
+ // Ignore any back-link sets that are empty.
+ Set<TopologyEdge> parents = entry.getValue();
+ if (parents.isEmpty()) {
+ continue;
+ }
+
+ // Use the first back-link source and destinations to add to the
+ // broadcast set.
+ Link link = parents.iterator().next().link();
+ builder.put(cluster.id(), link.src());
+ builder.put(cluster.id(), link.dst());
+ }
+ }
+
+ // Collects and returns an set of all infrastructure link end-points.
+ private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
+ ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
+ for (TopologyEdge edge : graph.getEdges()) {
+ builder.add(edge.link().src());
+ builder.add(edge.link().dst());
+ }
+ return builder.build();
+ }
+
+ // Builds cluster-devices, cluster-links and device-cluster indexes.
+ private void buildIndexes() {
+ // Prepare the index builders
+ ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
+ ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
+ ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder();
+
+ // Now scan through all the clusters
+ for (TopologyCluster cluster : clusters.values()) {
+ int i = cluster.id().index();
+
+ // Scan through all the cluster vertexes.
+ for (TopologyVertex vertex : clusterResults.clusterVertexes().get(i)) {
+ devicesBuilder.put(cluster, vertex.deviceId());
+ clusterBuilder.put(vertex.deviceId(), cluster);
+ }
+
+ // Scan through all the cluster edges.
+ for (TopologyEdge edge : clusterResults.clusterEdges().get(i)) {
+ linksBuilder.put(cluster, edge.link());
+ }
+ }
+
+ // Finalize all indexes.
+ clustersByDevice = clusterBuilder.build();
+ devicesByCluster = devicesBuilder.build();
+ linksByCluster = linksBuilder.build();
+ }
+
+ // Link weight for measuring link cost as hop count with indirect links
+ // being as expensive as traversing the entire graph to assume the worst.
+ private static class HopCountLinkWeight implements LinkWeight {
+ private final int indirectLinkCost;
+
+ HopCountLinkWeight(int indirectLinkCost) {
+ this.indirectLinkCost = indirectLinkCost;
+ }
+
+ @Override
+ public double weight(TopologyEdge edge) {
+ // To force preference to use direct paths first, make indirect
+ // links as expensive as the linear vertex traversal.
+ return edge.link().type() == INDIRECT ? indirectLinkCost : 1;
+ }
+ }
+
+ // Link weight for preventing traversal over indirect links.
+ private static class NoIndirectLinksWeight implements LinkWeight {
+ @Override
+ public double weight(TopologyEdge edge) {
+ return edge.link().type() == INDIRECT ? -1 : 1;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("time", time)
+ .add("clusters", clusterCount())
+ .add("devices", deviceCount())
+ .add("links", linkCount())
+ .add("pathCount", pathCount())
+ .toString();
+ }
}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoEdge.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyEdge.java
similarity index 64%
rename from core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoEdge.java
rename to core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyEdge.java
index d940754..e3a1a9e 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoEdge.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyEdge.java
@@ -1,8 +1,8 @@
-package org.onlab.onos.net.trivial.topology.provider.impl;
+package org.onlab.onos.net.trivial.topology.impl;
import org.onlab.onos.net.Link;
-import org.onlab.onos.net.topology.TopoEdge;
-import org.onlab.onos.net.topology.TopoVertex;
+import org.onlab.onos.net.topology.TopologyEdge;
+import org.onlab.onos.net.topology.TopologyVertex;
import java.util.Objects;
@@ -11,11 +11,11 @@
/**
* Implementation of the topology edge backed by a link.
*/
-class DefaultTopoEdge implements TopoEdge {
+class DefaultTopologyEdge implements TopologyEdge {
private final Link link;
- private final TopoVertex src;
- private final TopoVertex dst;
+ private final TopologyVertex src;
+ private final TopologyVertex dst;
/**
* Creates a new topology edge.
@@ -24,7 +24,7 @@
* @param dst destination vertex
* @param link infrastructure link
*/
- DefaultTopoEdge(TopoVertex src, TopoVertex dst, Link link) {
+ DefaultTopologyEdge(TopologyVertex src, TopologyVertex dst, Link link) {
this.src = src;
this.dst = dst;
this.link = link;
@@ -36,12 +36,12 @@
}
@Override
- public TopoVertex src() {
+ public TopologyVertex src() {
return src;
}
@Override
- public TopoVertex dst() {
+ public TopologyVertex dst() {
return dst;
}
@@ -52,8 +52,8 @@
@Override
public boolean equals(Object obj) {
- if (obj instanceof DefaultTopoEdge) {
- final DefaultTopoEdge other = (DefaultTopoEdge) obj;
+ if (obj instanceof DefaultTopologyEdge) {
+ final DefaultTopologyEdge other = (DefaultTopologyEdge) obj;
return Objects.equals(this.link, other.link);
}
return false;
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyGraph.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyGraph.java
new file mode 100644
index 0000000..22681b7
--- /dev/null
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyGraph.java
@@ -0,0 +1,28 @@
+package org.onlab.onos.net.trivial.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);
+ }
+
+}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/SimpleTopologyProvider.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyProvider.java
similarity index 89%
rename from core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/SimpleTopologyProvider.java
rename to core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyProvider.java
index 777a0e4..f49f7d3 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/SimpleTopologyProvider.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyProvider.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.net.trivial.topology.provider.impl;
+package org.onlab.onos.net.trivial.topology.impl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -16,7 +16,7 @@
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.net.topology.TopologyDescription;
+import org.onlab.onos.net.topology.GraphDescription;
import org.onlab.onos.net.topology.TopologyProvider;
import org.onlab.onos.net.topology.TopologyProviderRegistry;
import org.onlab.onos.net.topology.TopologyProviderService;
@@ -35,7 +35,7 @@
* Simple implementation of a network topology provider/computor.
*/
@Component(immediate = true)
-public class SimpleTopologyProvider extends AbstractProvider
+public class DefaultTopologyProvider extends AbstractProvider
implements TopologyProvider {
// TODO: make these configurable
@@ -70,7 +70,7 @@
/**
* Creates a provider with the supplier identifier.
*/
- public SimpleTopologyProvider() {
+ public DefaultTopologyProvider() {
super(new ProviderId("org.onlab.onos.provider.topology"));
}
@@ -90,6 +90,8 @@
@Deactivate
public synchronized void deactivate() {
+ isStarted = false;
+
deviceService.removeListener(deviceListener);
linkService.removeListener(linkListener);
providerRegistry.unregister(this);
@@ -98,7 +100,6 @@
executor.shutdownNow();
executor = null;
- isStarted = false;
log.info("Stopped");
}
@@ -108,18 +109,20 @@
*
* @param reasons events which triggered the topology change
*/
- private void triggerTopologyBuild(List<Event> reasons) {
- executor.execute(new TopologyBuilderTask(reasons));
+ private synchronized void triggerTopologyBuild(List<Event> reasons) {
+ if (executor != null) {
+ executor.execute(new TopologyBuilderTask(reasons));
+ }
}
// Builds the topology using the latest device and link information
// and citing the specified events as reasons for the change.
private void buildTopology(List<Event> reasons) {
if (isStarted) {
- TopologyDescription desc =
- new DefaultTopologyDescription(System.nanoTime(),
- deviceService.getDevices(),
- linkService.getLinks());
+ GraphDescription desc =
+ new DefaultGraphDescription(System.nanoTime(),
+ deviceService.getDevices(),
+ linkService.getLinks());
providerService.topologyChanged(desc, reasons);
}
}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoVertex.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyVertex.java
similarity index 69%
rename from core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoVertex.java
rename to core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyVertex.java
index afcaca6..043e364 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopoVertex.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/DefaultTopologyVertex.java
@@ -1,14 +1,14 @@
-package org.onlab.onos.net.trivial.topology.provider.impl;
+package org.onlab.onos.net.trivial.topology.impl;
import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.topology.TopoVertex;
+import org.onlab.onos.net.topology.TopologyVertex;
import java.util.Objects;
/**
* Implementation of the topology vertex backed by a device id.
*/
-class DefaultTopoVertex implements TopoVertex {
+class DefaultTopologyVertex implements TopologyVertex {
private final DeviceId deviceId;
@@ -17,7 +17,7 @@
*
* @param deviceId backing infrastructure device identifier
*/
- DefaultTopoVertex(DeviceId deviceId) {
+ DefaultTopologyVertex(DeviceId deviceId) {
this.deviceId = deviceId;
}
@@ -33,8 +33,8 @@
@Override
public boolean equals(Object obj) {
- if (obj instanceof DefaultTopoVertex) {
- final DefaultTopoVertex other = (DefaultTopoVertex) obj;
+ if (obj instanceof DefaultTopologyVertex) {
+ final DefaultTopologyVertex other = (DefaultTopologyVertex) obj;
return Objects.equals(this.deviceId, other.deviceId);
}
return false;
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/PathKey.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/PathKey.java
new file mode 100644
index 0000000..ff8b8f0
--- /dev/null
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/PathKey.java
@@ -0,0 +1,37 @@
+package org.onlab.onos.net.trivial.topology.impl;
+
+import org.onlab.onos.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Key for filing src/dst paths.
+ */
+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 (obj instanceof PathKey) {
+ final PathKey other = (PathKey) obj;
+ return Objects.equals(this.src, other.src) && Objects.equals(this.dst, other.dst);
+ }
+ return false;
+ }
+}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
index 70f001c..24bb256 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
@@ -6,7 +6,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.graph.Graph;
import org.onlab.onos.event.AbstractListenerRegistry;
import org.onlab.onos.event.Event;
import org.onlab.onos.event.EventDeliveryService;
@@ -15,13 +14,12 @@
import org.onlab.onos.net.Path;
import org.onlab.onos.net.provider.AbstractProviderRegistry;
import org.onlab.onos.net.provider.AbstractProviderService;
+import org.onlab.onos.net.topology.GraphDescription;
import org.onlab.onos.net.topology.LinkWeight;
-import org.onlab.onos.net.topology.TopoEdge;
-import org.onlab.onos.net.topology.TopoVertex;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyCluster;
-import org.onlab.onos.net.topology.TopologyDescription;
import org.onlab.onos.net.topology.TopologyEvent;
+import org.onlab.onos.net.topology.TopologyGraph;
import org.onlab.onos.net.topology.TopologyListener;
import org.onlab.onos.net.topology.TopologyProvider;
import org.onlab.onos.net.topology.TopologyProviderRegistry;
@@ -79,19 +77,28 @@
@Override
public boolean isLatest(Topology topology) {
checkNotNull(topology, TOPOLOGY_NULL);
- return store.isLatest(topology);
+ return store.isLatest(defaultTopology(topology));
+ }
+
+ // 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");
}
@Override
public Set<TopologyCluster> getClusters(Topology topology) {
checkNotNull(topology, TOPOLOGY_NULL);
- return store.getClusters(topology);
+ return store.getClusters(defaultTopology(topology));
}
@Override
- public Graph<TopoVertex, TopoEdge> getGraph(Topology topology) {
+ public TopologyGraph getGraph(Topology topology) {
checkNotNull(topology, TOPOLOGY_NULL);
- return store.getGraph(topology);
+ return store.getGraph(defaultTopology(topology));
}
@Override
@@ -99,7 +106,7 @@
checkNotNull(topology, TOPOLOGY_NULL);
checkNotNull(src, DEVICE_ID_NULL);
checkNotNull(dst, DEVICE_ID_NULL);
- return store.getPaths(topology, src, dst);
+ return store.getPaths(defaultTopology(topology), src, dst);
}
@Override
@@ -108,21 +115,21 @@
checkNotNull(src, DEVICE_ID_NULL);
checkNotNull(dst, DEVICE_ID_NULL);
checkNotNull(weight, "Link weight cannot be null");
- return store.getPaths(topology, src, dst, weight);
+ return store.getPaths(defaultTopology(topology), src, dst, weight);
}
@Override
public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
checkNotNull(topology, TOPOLOGY_NULL);
checkNotNull(connectPoint, CONNECTION_POINT_NULL);
- return store.isInfrastructure(topology, connectPoint);
+ return store.isInfrastructure(defaultTopology(topology), connectPoint);
}
@Override
public boolean isInBroadcastTree(Topology topology, ConnectPoint connectPoint) {
checkNotNull(topology, TOPOLOGY_NULL);
checkNotNull(connectPoint, CONNECTION_POINT_NULL);
- return store.isInBroadcastTree(topology, connectPoint);
+ return store.isInBroadcastTree(defaultTopology(topology), connectPoint);
}
@Override
@@ -150,15 +157,14 @@
}
@Override
- public void topologyChanged(TopologyDescription topoDescription,
+ public void topologyChanged(GraphDescription topoDescription,
List<Event> reasons) {
checkNotNull(topoDescription, "Topology description cannot be null");
- log.info("Topology changed due to: {}", // to be removed soon
- reasons == null ? "initial compute" : reasons);
- TopologyEvent event = store.updateTopology(topoDescription, reasons);
+ TopologyEvent event = store.updateTopology(provider().id(),
+ topoDescription, reasons);
if (event != null) {
- log.info("Topology changed due to: {}",
+ log.info("Topology {} changed due to: {}", event.subject(),
reasons == null ? "initial compute" : reasons);
eventDispatcher.post(event);
}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyStore.java
index 1b9766d..b167dbc 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyStore.java
@@ -1,17 +1,16 @@
package org.onlab.onos.net.trivial.topology.impl;
-import org.onlab.graph.Graph;
import org.onlab.onos.event.Event;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Path;
+import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.topology.GraphDescription;
import org.onlab.onos.net.topology.LinkWeight;
-import org.onlab.onos.net.topology.TopoEdge;
-import org.onlab.onos.net.topology.TopoVertex;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyCluster;
-import org.onlab.onos.net.topology.TopologyDescription;
import org.onlab.onos.net.topology.TopologyEvent;
+import org.onlab.onos.net.topology.TopologyGraph;
import java.util.List;
import java.util.Set;
@@ -50,8 +49,8 @@
* @param topology topology descriptor
* @return set of clusters
*/
- Set<TopologyCluster> getClusters(Topology topology) {
- return null;
+ Set<TopologyCluster> getClusters(DefaultTopology topology) {
+ return topology.getClusters();
}
/**
@@ -60,8 +59,8 @@
* @param topology topology descriptor
* @return graph view
*/
- Graph<TopoVertex, TopoEdge> getGraph(Topology topology) {
- return null;
+ TopologyGraph getGraph(DefaultTopology topology) {
+ return topology.getGraph();
}
/**
@@ -72,8 +71,8 @@
* @param dst destination device
* @return set of shortest paths
*/
- Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
- return null;
+ Set<Path> getPaths(DefaultTopology topology, DeviceId src, DeviceId dst) {
+ return topology.getPaths(src, dst);
}
/**
@@ -85,9 +84,9 @@
* @param weight link weight function
* @return set of shortest paths
*/
- Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
+ Set<Path> getPaths(DefaultTopology topology, DeviceId src, DeviceId dst,
LinkWeight weight) {
- return null;
+ return topology.getPaths(src, dst, weight);
}
/**
@@ -97,8 +96,8 @@
* @param connectPoint connection point
* @return true if infrastructure; false otherwise
*/
- boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
- return false;
+ boolean isInfrastructure(DefaultTopology topology, ConnectPoint connectPoint) {
+ return topology.isInfrastructure(connectPoint);
}
/**
@@ -108,20 +107,36 @@
* @param connectPoint connection point
* @return true if in broadcast tree; false otherwise
*/
- boolean isInBroadcastTree(Topology topology, ConnectPoint connectPoint) {
- return false;
+ boolean isInBroadcastTree(DefaultTopology topology, ConnectPoint connectPoint) {
+ return topology.isInBroadcastTree(connectPoint);
}
/**
* Generates a new topology snapshot from the specified description.
*
- * @param topoDescription topology description
- * @param reasons list of events that triggered the update
+ * @param providerId provider identification
+ * @param graphDescription topology graph description
+ * @param reasons list of events that triggered the update
* @return topology update event or null if the description is old
*/
- TopologyEvent updateTopology(TopologyDescription topoDescription,
+ TopologyEvent updateTopology(ProviderId providerId,
+ GraphDescription graphDescription,
List<Event> reasons) {
- return null;
+ // 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);
+ }
}
}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopologyDescription.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopologyDescription.java
deleted file mode 100644
index 408e6af..0000000
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/provider/impl/DefaultTopologyDescription.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package org.onlab.onos.net.trivial.topology.provider.impl;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.onlab.graph.AdjacencyListsGraph;
-import org.onlab.graph.DijkstraGraphSearch;
-import org.onlab.graph.Graph;
-import org.onlab.graph.GraphPathSearch;
-import org.onlab.graph.TarjanGraphSearch;
-import org.onlab.onos.net.ConnectPoint;
-import org.onlab.onos.net.Device;
-import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.Link;
-import org.onlab.onos.net.topology.ClusterId;
-import org.onlab.onos.net.topology.DefaultTopologyCluster;
-import org.onlab.onos.net.topology.LinkWeight;
-import org.onlab.onos.net.topology.TopoEdge;
-import org.onlab.onos.net.topology.TopoVertex;
-import org.onlab.onos.net.topology.TopologyCluster;
-import org.onlab.onos.net.topology.TopologyDescription;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.collect.ImmutableSetMultimap.Builder;
-import static org.onlab.graph.GraphPathSearch.Result;
-import static org.onlab.graph.TarjanGraphSearch.SCCResult;
-import static org.onlab.onos.net.Link.Type.INDIRECT;
-
-/**
- * Default implementation of an immutable topology data carrier.
- */
-class DefaultTopologyDescription implements TopologyDescription {
-
- private static final GraphPathSearch<TopoVertex, TopoEdge> DIJKSTRA =
- new DijkstraGraphSearch<>();
- private static final TarjanGraphSearch<TopoVertex, TopoEdge> TARJAN =
- new TarjanGraphSearch<>();
-
- private final long nanos;
- private final Map<DeviceId, TopoVertex> vertexesById = Maps.newHashMap();
- private final Graph<TopoVertex, TopoEdge> graph;
- private final Map<DeviceId, Result<TopoVertex, TopoEdge>> results;
- private final Map<ClusterId, TopologyCluster> clusters;
-
- // Secondary look-up indexes
- private ImmutableSetMultimap<ClusterId, DeviceId> devicesByCluster;
- private ImmutableSetMultimap<ClusterId, Link> linksByCluster;
- private Map<DeviceId, TopologyCluster> clustersByDevice = Maps.newHashMap();
-
- /**
- * Creates a topology description to carry topology vitals to the core.
- *
- * @param nanos time in nanos of when the topology description was created
- * @param devices collection of infrastructure devices
- * @param links collection of infrastructure links
- */
- DefaultTopologyDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
- this.nanos = nanos;
- this.graph = buildGraph(devices, links);
- this.results = computeDefaultPaths();
- this.clusters = computeClusters();
- }
-
- @Override
- public long timestamp() {
- return nanos;
- }
-
- @Override
- public Graph<TopoVertex, TopoEdge> graph() {
- return graph;
- }
-
- @Override
- public Result<TopoVertex, TopoEdge> pathResults(DeviceId srcDeviceId) {
- return results.get(srcDeviceId);
- }
-
- @Override
- public Set<TopologyCluster> clusters() {
- return ImmutableSet.copyOf(clusters.values());
- }
-
- @Override
- public Set<DeviceId> clusterDevices(TopologyCluster cluster) {
- return devicesByCluster.get(cluster.id());
- }
-
- @Override
- public Set<Link> clusterLinks(TopologyCluster cluster) {
- return linksByCluster.get(cluster.id());
- }
-
- @Override
- public TopologyCluster clusterFor(DeviceId deviceId) {
- return clustersByDevice.get(deviceId);
- }
-
-
- // Link weight for measuring link cost as hop count with indirect links
- // being as expensive as traversing the entire graph to assume the worst.
- private static class HopCountLinkWeight implements LinkWeight {
- private final int indirectLinkCost;
-
- HopCountLinkWeight(int indirectLinkCost) {
- this.indirectLinkCost = indirectLinkCost;
- }
-
- @Override
- public double weight(TopoEdge edge) {
- // To force preference to use direct paths first, make indirect
- // links as expensive as the linear vertex traversal.
- return edge.link().type() == INDIRECT ? indirectLinkCost : 1;
- }
- }
-
- // Link weight for preventing traversal over indirect links.
- private static class NoIndirectLinksWeight implements LinkWeight {
- @Override
- public double weight(TopoEdge edge) {
- return edge.link().type() == INDIRECT ? -1 : 1;
- }
- }
-
- // Constructs the topology graph using the supplied devices and links.
- private Graph<TopoVertex, TopoEdge> buildGraph(Iterable<Device> devices,
- Iterable<Link> links) {
- return new AdjacencyListsGraph<>(buildVertexes(devices),
- buildEdges(links));
- }
-
- // Builds a set of topology vertexes from the specified list of devices
- private Set<TopoVertex> buildVertexes(Iterable<Device> devices) {
- Set<TopoVertex> vertexes = Sets.newHashSet();
- for (Device device : devices) {
- TopoVertex vertex = new DefaultTopoVertex(device.id());
- vertexes.add(vertex);
- vertexesById.put(vertex.deviceId(), vertex);
- }
- return vertexes;
- }
-
- // Builds a set of topology vertexes from the specified list of links
- private Set<TopoEdge> buildEdges(Iterable<Link> links) {
- Set<TopoEdge> edges = Sets.newHashSet();
- for (Link link : links) {
- edges.add(new DefaultTopoEdge(vertexOf(link.src()),
- vertexOf(link.dst()), link));
- }
- return edges;
- }
-
- // Computes the default shortest paths for all source/dest pairs using
- // the multi-path Dijkstra and hop-count as path cost.
- private Map<DeviceId, Result<TopoVertex, TopoEdge>> computeDefaultPaths() {
- LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
- Map<DeviceId, Result<TopoVertex, TopoEdge>> results = Maps.newHashMap();
-
- // Search graph paths for each source to all destinations.
- for (TopoVertex src : vertexesById.values()) {
- results.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
- }
- return results;
- }
-
- // Computes topology SCC clusters using Tarjan algorithm.
- private Map<ClusterId, TopologyCluster> computeClusters() {
- Map<ClusterId, TopologyCluster> clusters = Maps.newHashMap();
- SCCResult<TopoVertex, TopoEdge> result = TARJAN.search(graph, new NoIndirectLinksWeight());
-
- // Extract both vertexes and edges from the results; the lists form
- // pairs along the same index.
- List<Set<TopoVertex>> clusterVertexes = result.clusterVertexes();
- List<Set<TopoEdge>> clusterEdges = result.clusterEdges();
-
- Builder<ClusterId, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
- Builder<ClusterId, Link> linksBuilder = ImmutableSetMultimap.builder();
-
- // Scan over the lists and create a cluster from the results.
- for (int i = 0, n = result.clusterCount(); i < n; i++) {
- Set<TopoVertex> vertexSet = clusterVertexes.get(i);
- Set<TopoEdge> edgeSet = clusterEdges.get(i);
-
- DefaultTopologyCluster cluster =
- new DefaultTopologyCluster(ClusterId.clusterId(i),
- vertexSet.size(), edgeSet.size(),
- findRoot(vertexSet).deviceId());
- findClusterDevices(vertexSet, cluster, devicesBuilder);
- findClusterLinks(edgeSet, cluster, linksBuilder);
- }
- return clusters;
- }
-
- // Scans through the set of cluster vertexes and puts their devices in a
- // multi-map associated with the cluster. It also binds the devices to
- // the cluster.
- private void findClusterDevices(Set<TopoVertex> vertexSet,
- DefaultTopologyCluster cluster,
- Builder<ClusterId, DeviceId> builder) {
- for (TopoVertex vertex : vertexSet) {
- DeviceId deviceId = vertex.deviceId();
- builder.put(cluster.id(), deviceId);
- clustersByDevice.put(deviceId, cluster);
- }
- }
-
- // Scans through the set of cluster edges and puts their links in a
- // multi-map associated with the cluster.
- private void findClusterLinks(Set<TopoEdge> edgeSet,
- DefaultTopologyCluster cluster,
- Builder<ClusterId, Link> builder) {
- for (TopoEdge edge : edgeSet) {
- builder.put(cluster.id(), edge.link());
- }
- }
-
- // Finds the vertex whose device id is the lexicographical minimum in the
- // specified set.
- private TopoVertex findRoot(Set<TopoVertex> vertexSet) {
- TopoVertex minVertex = null;
- for (TopoVertex vertex : vertexSet) {
- if (minVertex == null ||
- minVertex.deviceId().toString()
- .compareTo(minVertex.deviceId().toString()) < 0) {
- minVertex = vertex;
- }
- }
- return minVertex;
- }
-
- // Fetches a vertex corresponding to the given connection point device.
- private TopoVertex vertexOf(ConnectPoint connectPoint) {
- DeviceId id = connectPoint.deviceId();
- TopoVertex vertex = vertexesById.get(id);
- if (vertex == null) {
- // If vertex does not exist, create one and register it.
- vertex = new DefaultTopoVertex(id);
- vertexesById.put(id, vertex);
- }
- return vertex;
- }
-
-}
diff --git a/core/trivial/src/main/javadoc/org/onlab/onos/net/trivial/topology/provider/impl/package.html b/core/trivial/src/main/javadoc/org/onlab/onos/net/trivial/topology/provider/impl/package.html
deleted file mode 100644
index ee67aa8..0000000
--- a/core/trivial/src/main/javadoc/org/onlab/onos/net/trivial/topology/provider/impl/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-Built-in protocol-agnostic topology builder & provider.
-</body>
\ No newline at end of file