blob: 408e6af686ca3cd4980f5cc5741a4cef0e4be170 [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
3import com.google.common.collect.ImmutableSet;
tom2d331412014-09-10 21:31:20 -07004import com.google.common.collect.ImmutableSetMultimap;
tomcbff9392014-09-10 00:45:23 -07005import com.google.common.collect.Maps;
6import com.google.common.collect.Sets;
7import org.onlab.graph.AdjacencyListsGraph;
8import org.onlab.graph.DijkstraGraphSearch;
tomcfde0622014-09-09 11:02:42 -07009import org.onlab.graph.Graph;
10import org.onlab.graph.GraphPathSearch;
tom8bf2e6b2014-09-10 20:53:54 -070011import org.onlab.graph.TarjanGraphSearch;
tomcbff9392014-09-10 00:45:23 -070012import org.onlab.onos.net.ConnectPoint;
13import org.onlab.onos.net.Device;
tomcfde0622014-09-09 11:02:42 -070014import org.onlab.onos.net.DeviceId;
15import org.onlab.onos.net.Link;
16import org.onlab.onos.net.topology.ClusterId;
tom8bf2e6b2014-09-10 20:53:54 -070017import org.onlab.onos.net.topology.DefaultTopologyCluster;
tomcbff9392014-09-10 00:45:23 -070018import org.onlab.onos.net.topology.LinkWeight;
tomcfde0622014-09-09 11:02:42 -070019import org.onlab.onos.net.topology.TopoEdge;
20import org.onlab.onos.net.topology.TopoVertex;
21import org.onlab.onos.net.topology.TopologyCluster;
22import org.onlab.onos.net.topology.TopologyDescription;
23
tom8bf2e6b2014-09-10 20:53:54 -070024import java.util.List;
tomcfde0622014-09-09 11:02:42 -070025import java.util.Map;
26import java.util.Set;
27
tom2d331412014-09-10 21:31:20 -070028import static com.google.common.collect.ImmutableSetMultimap.Builder;
tomcbff9392014-09-10 00:45:23 -070029import static org.onlab.graph.GraphPathSearch.Result;
tom8bf2e6b2014-09-10 20:53:54 -070030import static org.onlab.graph.TarjanGraphSearch.SCCResult;
tomcbff9392014-09-10 00:45:23 -070031import static org.onlab.onos.net.Link.Type.INDIRECT;
32
tomcfde0622014-09-09 11:02:42 -070033/**
34 * Default implementation of an immutable topology data carrier.
35 */
tomcbff9392014-09-10 00:45:23 -070036class DefaultTopologyDescription implements TopologyDescription {
37
38 private static final GraphPathSearch<TopoVertex, TopoEdge> DIJKSTRA =
39 new DijkstraGraphSearch<>();
tom8bf2e6b2014-09-10 20:53:54 -070040 private static final TarjanGraphSearch<TopoVertex, TopoEdge> TARJAN =
41 new TarjanGraphSearch<>();
tomcfde0622014-09-09 11:02:42 -070042
43 private final long nanos;
tomcbff9392014-09-10 00:45:23 -070044 private final Map<DeviceId, TopoVertex> vertexesById = Maps.newHashMap();
tomcfde0622014-09-09 11:02:42 -070045 private final Graph<TopoVertex, TopoEdge> graph;
tomcbff9392014-09-10 00:45:23 -070046 private final Map<DeviceId, Result<TopoVertex, TopoEdge>> results;
tomcfde0622014-09-09 11:02:42 -070047 private final Map<ClusterId, TopologyCluster> clusters;
tomcfde0622014-09-09 11:02:42 -070048
tom8bf2e6b2014-09-10 20:53:54 -070049 // Secondary look-up indexes
tom2d331412014-09-10 21:31:20 -070050 private ImmutableSetMultimap<ClusterId, DeviceId> devicesByCluster;
51 private ImmutableSetMultimap<ClusterId, Link> linksByCluster;
52 private Map<DeviceId, TopologyCluster> clustersByDevice = Maps.newHashMap();
tomcbff9392014-09-10 00:45:23 -070053
tom8bf2e6b2014-09-10 20:53:54 -070054 /**
55 * Creates a topology description to carry topology vitals to the core.
56 *
57 * @param nanos time in nanos of when the topology description was created
tom2d331412014-09-10 21:31:20 -070058 * @param devices collection of infrastructure devices
59 * @param links collection of infrastructure links
tom8bf2e6b2014-09-10 20:53:54 -070060 */
tomcbff9392014-09-10 00:45:23 -070061 DefaultTopologyDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
tomcfde0622014-09-09 11:02:42 -070062 this.nanos = nanos;
tomcbff9392014-09-10 00:45:23 -070063 this.graph = buildGraph(devices, links);
64 this.results = computeDefaultPaths();
65 this.clusters = computeClusters();
tomcbff9392014-09-10 00:45:23 -070066 }
67
tom2d331412014-09-10 21:31:20 -070068 @Override
69 public long timestamp() {
70 return nanos;
71 }
72
73 @Override
74 public Graph<TopoVertex, TopoEdge> graph() {
75 return graph;
76 }
77
78 @Override
79 public Result<TopoVertex, TopoEdge> pathResults(DeviceId srcDeviceId) {
80 return results.get(srcDeviceId);
81 }
82
83 @Override
84 public Set<TopologyCluster> clusters() {
85 return ImmutableSet.copyOf(clusters.values());
86 }
87
88 @Override
89 public Set<DeviceId> clusterDevices(TopologyCluster cluster) {
90 return devicesByCluster.get(cluster.id());
91 }
92
93 @Override
94 public Set<Link> clusterLinks(TopologyCluster cluster) {
95 return linksByCluster.get(cluster.id());
96 }
97
98 @Override
99 public TopologyCluster clusterFor(DeviceId deviceId) {
100 return clustersByDevice.get(deviceId);
101 }
102
103
104 // Link weight for measuring link cost as hop count with indirect links
105 // being as expensive as traversing the entire graph to assume the worst.
106 private static class HopCountLinkWeight implements LinkWeight {
107 private final int indirectLinkCost;
108
109 HopCountLinkWeight(int indirectLinkCost) {
110 this.indirectLinkCost = indirectLinkCost;
111 }
112
113 @Override
114 public double weight(TopoEdge edge) {
115 // To force preference to use direct paths first, make indirect
116 // links as expensive as the linear vertex traversal.
117 return edge.link().type() == INDIRECT ? indirectLinkCost : 1;
118 }
119 }
120
121 // Link weight for preventing traversal over indirect links.
122 private static class NoIndirectLinksWeight implements LinkWeight {
123 @Override
124 public double weight(TopoEdge edge) {
125 return edge.link().type() == INDIRECT ? -1 : 1;
126 }
127 }
128
tomcbff9392014-09-10 00:45:23 -0700129 // Constructs the topology graph using the supplied devices and links.
130 private Graph<TopoVertex, TopoEdge> buildGraph(Iterable<Device> devices,
131 Iterable<Link> links) {
tom2d331412014-09-10 21:31:20 -0700132 return new AdjacencyListsGraph<>(buildVertexes(devices),
133 buildEdges(links));
tomcbff9392014-09-10 00:45:23 -0700134 }
135
136 // Builds a set of topology vertexes from the specified list of devices
137 private Set<TopoVertex> buildVertexes(Iterable<Device> devices) {
138 Set<TopoVertex> vertexes = Sets.newHashSet();
139 for (Device device : devices) {
tom2d331412014-09-10 21:31:20 -0700140 TopoVertex vertex = new DefaultTopoVertex(device.id());
tomcbff9392014-09-10 00:45:23 -0700141 vertexes.add(vertex);
tom2d331412014-09-10 21:31:20 -0700142 vertexesById.put(vertex.deviceId(), vertex);
tomcbff9392014-09-10 00:45:23 -0700143 }
144 return vertexes;
145 }
146
147 // Builds a set of topology vertexes from the specified list of links
148 private Set<TopoEdge> buildEdges(Iterable<Link> links) {
149 Set<TopoEdge> edges = Sets.newHashSet();
150 for (Link link : links) {
tom2d331412014-09-10 21:31:20 -0700151 edges.add(new DefaultTopoEdge(vertexOf(link.src()),
152 vertexOf(link.dst()), link));
tomcbff9392014-09-10 00:45:23 -0700153 }
154 return edges;
155 }
156
157 // Computes the default shortest paths for all source/dest pairs using
158 // the multi-path Dijkstra and hop-count as path cost.
159 private Map<DeviceId, Result<TopoVertex, TopoEdge>> computeDefaultPaths() {
160 LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
161 Map<DeviceId, Result<TopoVertex, TopoEdge>> results = Maps.newHashMap();
162
163 // Search graph paths for each source to all destinations.
164 for (TopoVertex src : vertexesById.values()) {
165 results.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
166 }
167 return results;
168 }
169
170 // Computes topology SCC clusters using Tarjan algorithm.
171 private Map<ClusterId, TopologyCluster> computeClusters() {
172 Map<ClusterId, TopologyCluster> clusters = Maps.newHashMap();
tom8bf2e6b2014-09-10 20:53:54 -0700173 SCCResult<TopoVertex, TopoEdge> result = TARJAN.search(graph, new NoIndirectLinksWeight());
174
175 // Extract both vertexes and edges from the results; the lists form
176 // pairs along the same index.
177 List<Set<TopoVertex>> clusterVertexes = result.clusterVertexes();
178 List<Set<TopoEdge>> clusterEdges = result.clusterEdges();
179
tom2d331412014-09-10 21:31:20 -0700180 Builder<ClusterId, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
181 Builder<ClusterId, Link> linksBuilder = ImmutableSetMultimap.builder();
182
tom8bf2e6b2014-09-10 20:53:54 -0700183 // Scan over the lists and create a cluster from the results.
184 for (int i = 0, n = result.clusterCount(); i < n; i++) {
185 Set<TopoVertex> vertexSet = clusterVertexes.get(i);
186 Set<TopoEdge> edgeSet = clusterEdges.get(i);
187
188 DefaultTopologyCluster cluster =
189 new DefaultTopologyCluster(ClusterId.clusterId(i),
190 vertexSet.size(), edgeSet.size(),
191 findRoot(vertexSet).deviceId());
tom2d331412014-09-10 21:31:20 -0700192 findClusterDevices(vertexSet, cluster, devicesBuilder);
193 findClusterLinks(edgeSet, cluster, linksBuilder);
tom8bf2e6b2014-09-10 20:53:54 -0700194 }
tomcbff9392014-09-10 00:45:23 -0700195 return clusters;
196 }
197
tom2d331412014-09-10 21:31:20 -0700198 // Scans through the set of cluster vertexes and puts their devices in a
199 // multi-map associated with the cluster. It also binds the devices to
200 // the cluster.
tom8bf2e6b2014-09-10 20:53:54 -0700201 private void findClusterDevices(Set<TopoVertex> vertexSet,
tom2d331412014-09-10 21:31:20 -0700202 DefaultTopologyCluster cluster,
203 Builder<ClusterId, DeviceId> builder) {
204 for (TopoVertex vertex : vertexSet) {
205 DeviceId deviceId = vertex.deviceId();
206 builder.put(cluster.id(), deviceId);
tom8bf2e6b2014-09-10 20:53:54 -0700207 clustersByDevice.put(deviceId, cluster);
208 }
209 }
210
tom2d331412014-09-10 21:31:20 -0700211 // Scans through the set of cluster edges and puts their links in a
212 // multi-map associated with the cluster.
tom8bf2e6b2014-09-10 20:53:54 -0700213 private void findClusterLinks(Set<TopoEdge> edgeSet,
tom2d331412014-09-10 21:31:20 -0700214 DefaultTopologyCluster cluster,
215 Builder<ClusterId, Link> builder) {
216 for (TopoEdge edge : edgeSet) {
217 builder.put(cluster.id(), edge.link());
tom8bf2e6b2014-09-10 20:53:54 -0700218 }
219 }
220
221 // Finds the vertex whose device id is the lexicographical minimum in the
222 // specified set.
223 private TopoVertex findRoot(Set<TopoVertex> vertexSet) {
224 TopoVertex minVertex = null;
225 for (TopoVertex vertex : vertexSet) {
226 if (minVertex == null ||
227 minVertex.deviceId().toString()
228 .compareTo(minVertex.deviceId().toString()) < 0) {
229 minVertex = vertex;
230 }
231 }
232 return minVertex;
233 }
234
tomcbff9392014-09-10 00:45:23 -0700235 // Fetches a vertex corresponding to the given connection point device.
236 private TopoVertex vertexOf(ConnectPoint connectPoint) {
237 DeviceId id = connectPoint.deviceId();
238 TopoVertex vertex = vertexesById.get(id);
239 if (vertex == null) {
240 // If vertex does not exist, create one and register it.
tom2d331412014-09-10 21:31:20 -0700241 vertex = new DefaultTopoVertex(id);
tomcbff9392014-09-10 00:45:23 -0700242 vertexesById.put(id, vertex);
243 }
244 return vertex;
tomcfde0622014-09-09 11:02:42 -0700245 }
246
tomcfde0622014-09-09 11:02:42 -0700247}