blob: 37411a275cb4ca9fd115d131bf711f7296c382ae [file] [log] [blame]
tom8bf2e6b2014-09-10 20:53:54 -07001package org.onlab.onos.net.trivial.topology.provider.impl;
tomcfde0622014-09-09 11:02:42 -07002
tome52ce702014-09-11 00:12:54 -07003import com.google.common.collect.ImmutableMap;
tomcfde0622014-09-09 11:02:42 -07004import com.google.common.collect.ImmutableSet;
tom2d331412014-09-10 21:31:20 -07005import com.google.common.collect.ImmutableSetMultimap;
tomcbff9392014-09-10 00:45:23 -07006import com.google.common.collect.Maps;
7import com.google.common.collect.Sets;
8import org.onlab.graph.AdjacencyListsGraph;
9import org.onlab.graph.DijkstraGraphSearch;
tomcfde0622014-09-09 11:02:42 -070010import org.onlab.graph.Graph;
11import org.onlab.graph.GraphPathSearch;
tom8bf2e6b2014-09-10 20:53:54 -070012import org.onlab.graph.TarjanGraphSearch;
tomcbff9392014-09-10 00:45:23 -070013import org.onlab.onos.net.ConnectPoint;
14import org.onlab.onos.net.Device;
tomcfde0622014-09-09 11:02:42 -070015import org.onlab.onos.net.DeviceId;
16import org.onlab.onos.net.Link;
17import org.onlab.onos.net.topology.ClusterId;
tom8bf2e6b2014-09-10 20:53:54 -070018import org.onlab.onos.net.topology.DefaultTopologyCluster;
tomcbff9392014-09-10 00:45:23 -070019import org.onlab.onos.net.topology.LinkWeight;
tomcfde0622014-09-09 11:02:42 -070020import org.onlab.onos.net.topology.TopoEdge;
21import org.onlab.onos.net.topology.TopoVertex;
22import org.onlab.onos.net.topology.TopologyCluster;
23import org.onlab.onos.net.topology.TopologyDescription;
24
tom8bf2e6b2014-09-10 20:53:54 -070025import java.util.List;
tomcfde0622014-09-09 11:02:42 -070026import java.util.Map;
27import java.util.Set;
28
tom2d331412014-09-10 21:31:20 -070029import static com.google.common.collect.ImmutableSetMultimap.Builder;
tome52ce702014-09-11 00:12:54 -070030import static com.google.common.collect.ImmutableSetMultimap.builder;
tomcbff9392014-09-10 00:45:23 -070031import static org.onlab.graph.GraphPathSearch.Result;
tom8bf2e6b2014-09-10 20:53:54 -070032import static org.onlab.graph.TarjanGraphSearch.SCCResult;
tomcbff9392014-09-10 00:45:23 -070033import static org.onlab.onos.net.Link.Type.INDIRECT;
34
tomcfde0622014-09-09 11:02:42 -070035/**
36 * Default implementation of an immutable topology data carrier.
37 */
tomcbff9392014-09-10 00:45:23 -070038class DefaultTopologyDescription implements TopologyDescription {
39
40 private static final GraphPathSearch<TopoVertex, TopoEdge> DIJKSTRA =
41 new DijkstraGraphSearch<>();
tom8bf2e6b2014-09-10 20:53:54 -070042 private static final TarjanGraphSearch<TopoVertex, TopoEdge> TARJAN =
43 new TarjanGraphSearch<>();
tomcfde0622014-09-09 11:02:42 -070044
45 private final long nanos;
tomcbff9392014-09-10 00:45:23 -070046 private final Map<DeviceId, TopoVertex> vertexesById = Maps.newHashMap();
tomcfde0622014-09-09 11:02:42 -070047 private final Graph<TopoVertex, TopoEdge> graph;
tome52ce702014-09-11 00:12:54 -070048 private final ImmutableMap<DeviceId, Result<TopoVertex, TopoEdge>> results;
tomcfde0622014-09-09 11:02:42 -070049
tome52ce702014-09-11 00:12:54 -070050 // Cluster-related structures
51 private final ImmutableSet<TopologyCluster> clusters;
52 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
53 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
tomcbff9392014-09-10 00:45:23 -070054
tom8bf2e6b2014-09-10 20:53:54 -070055 /**
56 * Creates a topology description to carry topology vitals to the core.
57 *
58 * @param nanos time in nanos of when the topology description was created
tom2d331412014-09-10 21:31:20 -070059 * @param devices collection of infrastructure devices
60 * @param links collection of infrastructure links
tom8bf2e6b2014-09-10 20:53:54 -070061 */
tomcbff9392014-09-10 00:45:23 -070062 DefaultTopologyDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
tomcfde0622014-09-09 11:02:42 -070063 this.nanos = nanos;
tomcbff9392014-09-10 00:45:23 -070064 this.graph = buildGraph(devices, links);
65 this.results = computeDefaultPaths();
66 this.clusters = computeClusters();
tomcbff9392014-09-10 00:45:23 -070067 }
68
tom2d331412014-09-10 21:31:20 -070069 @Override
70 public long timestamp() {
71 return nanos;
72 }
73
74 @Override
75 public Graph<TopoVertex, TopoEdge> graph() {
76 return graph;
77 }
78
79 @Override
tome52ce702014-09-11 00:12:54 -070080 public ImmutableMap<DeviceId, Result<TopoVertex, TopoEdge>> pathsBySource() {
81 return results;
tom2d331412014-09-10 21:31:20 -070082 }
83
84 @Override
tome52ce702014-09-11 00:12:54 -070085 public ImmutableSet<TopologyCluster> clusters() {
86 return clusters;
tom2d331412014-09-10 21:31:20 -070087 }
88
89 @Override
tome52ce702014-09-11 00:12:54 -070090 public ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
91 return devicesByCluster;
tom2d331412014-09-10 21:31:20 -070092 }
93
94 @Override
tome52ce702014-09-11 00:12:54 -070095 public ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
96 return linksByCluster;
tom2d331412014-09-10 21:31:20 -070097 }
98
tom2d331412014-09-10 21:31:20 -070099 // Link weight for measuring link cost as hop count with indirect links
100 // being as expensive as traversing the entire graph to assume the worst.
101 private static class HopCountLinkWeight implements LinkWeight {
102 private final int indirectLinkCost;
103
104 HopCountLinkWeight(int indirectLinkCost) {
105 this.indirectLinkCost = indirectLinkCost;
106 }
107
108 @Override
109 public double weight(TopoEdge edge) {
110 // To force preference to use direct paths first, make indirect
111 // links as expensive as the linear vertex traversal.
112 return edge.link().type() == INDIRECT ? indirectLinkCost : 1;
113 }
114 }
115
116 // Link weight for preventing traversal over indirect links.
117 private static class NoIndirectLinksWeight implements LinkWeight {
118 @Override
119 public double weight(TopoEdge edge) {
120 return edge.link().type() == INDIRECT ? -1 : 1;
121 }
122 }
123
tomcbff9392014-09-10 00:45:23 -0700124 // Constructs the topology graph using the supplied devices and links.
125 private Graph<TopoVertex, TopoEdge> buildGraph(Iterable<Device> devices,
126 Iterable<Link> links) {
tom2d331412014-09-10 21:31:20 -0700127 return new AdjacencyListsGraph<>(buildVertexes(devices),
128 buildEdges(links));
tomcbff9392014-09-10 00:45:23 -0700129 }
130
131 // Builds a set of topology vertexes from the specified list of devices
132 private Set<TopoVertex> buildVertexes(Iterable<Device> devices) {
133 Set<TopoVertex> vertexes = Sets.newHashSet();
134 for (Device device : devices) {
tom2d331412014-09-10 21:31:20 -0700135 TopoVertex vertex = new DefaultTopoVertex(device.id());
tomcbff9392014-09-10 00:45:23 -0700136 vertexes.add(vertex);
tom2d331412014-09-10 21:31:20 -0700137 vertexesById.put(vertex.deviceId(), vertex);
tomcbff9392014-09-10 00:45:23 -0700138 }
139 return vertexes;
140 }
141
142 // Builds a set of topology vertexes from the specified list of links
143 private Set<TopoEdge> buildEdges(Iterable<Link> links) {
144 Set<TopoEdge> edges = Sets.newHashSet();
145 for (Link link : links) {
tom2d331412014-09-10 21:31:20 -0700146 edges.add(new DefaultTopoEdge(vertexOf(link.src()),
147 vertexOf(link.dst()), link));
tomcbff9392014-09-10 00:45:23 -0700148 }
149 return edges;
150 }
151
152 // Computes the default shortest paths for all source/dest pairs using
153 // the multi-path Dijkstra and hop-count as path cost.
tome52ce702014-09-11 00:12:54 -0700154 private ImmutableMap<DeviceId, Result<TopoVertex, TopoEdge>> computeDefaultPaths() {
tomcbff9392014-09-10 00:45:23 -0700155 LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
tome52ce702014-09-11 00:12:54 -0700156 ImmutableMap.Builder<DeviceId, Result<TopoVertex, TopoEdge>> results =
157 ImmutableMap.builder();
tomcbff9392014-09-10 00:45:23 -0700158
159 // Search graph paths for each source to all destinations.
160 for (TopoVertex src : vertexesById.values()) {
161 results.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
162 }
tome52ce702014-09-11 00:12:54 -0700163 return results.build();
tomcbff9392014-09-10 00:45:23 -0700164 }
165
166 // Computes topology SCC clusters using Tarjan algorithm.
tome52ce702014-09-11 00:12:54 -0700167 private ImmutableSet<TopologyCluster> computeClusters() {
168 ImmutableSet.Builder<TopologyCluster> clusterBuilder = ImmutableSet.builder();
169 SCCResult<TopoVertex, TopoEdge> result =
170 TARJAN.search(graph, new NoIndirectLinksWeight());
tom8bf2e6b2014-09-10 20:53:54 -0700171
172 // Extract both vertexes and edges from the results; the lists form
173 // pairs along the same index.
174 List<Set<TopoVertex>> clusterVertexes = result.clusterVertexes();
175 List<Set<TopoEdge>> clusterEdges = result.clusterEdges();
176
tome52ce702014-09-11 00:12:54 -0700177 Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
178 Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder();
tom2d331412014-09-10 21:31:20 -0700179
tom8bf2e6b2014-09-10 20:53:54 -0700180 // Scan over the lists and create a cluster from the results.
181 for (int i = 0, n = result.clusterCount(); i < n; i++) {
182 Set<TopoVertex> vertexSet = clusterVertexes.get(i);
183 Set<TopoEdge> edgeSet = clusterEdges.get(i);
184
185 DefaultTopologyCluster cluster =
186 new DefaultTopologyCluster(ClusterId.clusterId(i),
187 vertexSet.size(), edgeSet.size(),
188 findRoot(vertexSet).deviceId());
tome52ce702014-09-11 00:12:54 -0700189 clusterBuilder.add(cluster);
tom2d331412014-09-10 21:31:20 -0700190 findClusterDevices(vertexSet, cluster, devicesBuilder);
191 findClusterLinks(edgeSet, cluster, linksBuilder);
tom8bf2e6b2014-09-10 20:53:54 -0700192 }
tome52ce702014-09-11 00:12:54 -0700193 return clusterBuilder.build();
tomcbff9392014-09-10 00:45:23 -0700194 }
195
tom2d331412014-09-10 21:31:20 -0700196 // Scans through the set of cluster vertexes and puts their devices in a
197 // multi-map associated with the cluster. It also binds the devices to
198 // the cluster.
tom8bf2e6b2014-09-10 20:53:54 -0700199 private void findClusterDevices(Set<TopoVertex> vertexSet,
tom2d331412014-09-10 21:31:20 -0700200 DefaultTopologyCluster cluster,
tome52ce702014-09-11 00:12:54 -0700201 Builder<TopologyCluster, DeviceId> builder) {
tom2d331412014-09-10 21:31:20 -0700202 for (TopoVertex vertex : vertexSet) {
203 DeviceId deviceId = vertex.deviceId();
tome52ce702014-09-11 00:12:54 -0700204 builder.put(cluster, deviceId);
tom8bf2e6b2014-09-10 20:53:54 -0700205 }
206 }
207
tom2d331412014-09-10 21:31:20 -0700208 // Scans through the set of cluster edges and puts their links in a
209 // multi-map associated with the cluster.
tom8bf2e6b2014-09-10 20:53:54 -0700210 private void findClusterLinks(Set<TopoEdge> edgeSet,
tom2d331412014-09-10 21:31:20 -0700211 DefaultTopologyCluster cluster,
tome52ce702014-09-11 00:12:54 -0700212 Builder<TopologyCluster, Link> builder) {
tom2d331412014-09-10 21:31:20 -0700213 for (TopoEdge edge : edgeSet) {
tome52ce702014-09-11 00:12:54 -0700214 builder.put(cluster, edge.link());
tom8bf2e6b2014-09-10 20:53:54 -0700215 }
216 }
217
218 // Finds the vertex whose device id is the lexicographical minimum in the
219 // specified set.
220 private TopoVertex findRoot(Set<TopoVertex> vertexSet) {
221 TopoVertex minVertex = null;
222 for (TopoVertex vertex : vertexSet) {
223 if (minVertex == null ||
224 minVertex.deviceId().toString()
225 .compareTo(minVertex.deviceId().toString()) < 0) {
226 minVertex = vertex;
227 }
228 }
229 return minVertex;
230 }
231
tomcbff9392014-09-10 00:45:23 -0700232 // Fetches a vertex corresponding to the given connection point device.
233 private TopoVertex vertexOf(ConnectPoint connectPoint) {
234 DeviceId id = connectPoint.deviceId();
235 TopoVertex vertex = vertexesById.get(id);
236 if (vertex == null) {
237 // If vertex does not exist, create one and register it.
tom2d331412014-09-10 21:31:20 -0700238 vertex = new DefaultTopoVertex(id);
tomcbff9392014-09-10 00:45:23 -0700239 vertexesById.put(id, vertex);
240 }
241 return vertex;
tomcfde0622014-09-09 11:02:42 -0700242 }
243
tomcfde0622014-09-09 11:02:42 -0700244}