blob: e5974499b6c5b90c76ac826bd37f44ee1b8fb1dc [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.topology.impl;
alshabib339a3d92014-09-26 17:54:32 -070017
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050018import static com.google.common.base.MoreObjects.toStringHelper;
19import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
20import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
21import static org.onosproject.net.Link.State.ACTIVE;
22import static org.onosproject.net.Link.State.INACTIVE;
23import static org.onosproject.net.Link.Type.INDIRECT;
24
25import java.util.ArrayList;
26import java.util.List;
27import java.util.Map;
28import java.util.Set;
29
alshabib339a3d92014-09-26 17:54:32 -070030import org.onlab.graph.DijkstraGraphSearch;
31import org.onlab.graph.GraphPathSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080032import org.onlab.graph.GraphPathSearch.Result;
alshabib339a3d92014-09-26 17:54:32 -070033import org.onlab.graph.TarjanGraphSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080034import org.onlab.graph.TarjanGraphSearch.SCCResult;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.AbstractModel;
36import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.DefaultPath;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Link;
40import org.onosproject.net.Path;
41import org.onosproject.net.provider.ProviderId;
42import org.onosproject.net.topology.ClusterId;
43import org.onosproject.net.topology.DefaultTopologyCluster;
44import org.onosproject.net.topology.DefaultTopologyVertex;
45import org.onosproject.net.topology.GraphDescription;
46import org.onosproject.net.topology.LinkWeight;
47import org.onosproject.net.topology.Topology;
48import org.onosproject.net.topology.TopologyCluster;
49import org.onosproject.net.topology.TopologyEdge;
50import org.onosproject.net.topology.TopologyGraph;
51import org.onosproject.net.topology.TopologyVertex;
alshabib339a3d92014-09-26 17:54:32 -070052
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050053import com.google.common.base.Supplier;
54import com.google.common.base.Suppliers;
55import com.google.common.collect.ImmutableMap;
56import com.google.common.collect.ImmutableSet;
57import com.google.common.collect.ImmutableSetMultimap;
58import com.google.common.collect.ImmutableSetMultimap.Builder;
alshabib339a3d92014-09-26 17:54:32 -070059
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080060// FIXME: Move to onos-core-common when ready
alshabib339a3d92014-09-26 17:54:32 -070061/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050062 * Default implementation of the topology descriptor. This carries the backing
63 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070064 */
65public class DefaultTopology extends AbstractModel implements Topology {
66
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050067 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
68 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
alshabib339a3d92014-09-26 17:54:32 -070069
alshabib339a3d92014-09-26 17:54:32 -070070 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050071 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080072 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070073 private final TopologyGraph graph;
74
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080075 private final LinkWeight weight;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080076 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080077 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
78 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
79 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
alshabib339a3d92014-09-26 17:54:32 -070080
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080081 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070082
83 /**
84 * Creates a topology descriptor attributed to the specified provider.
85 *
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050086 * @param providerId
87 * identity of the provider
88 * @param description
89 * data describing the new topology
alshabib339a3d92014-09-26 17:54:32 -070090 */
91 DefaultTopology(ProviderId providerId, GraphDescription description) {
92 super(providerId);
93 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050094 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -070095
96 // Build the graph
97 this.graph = new DefaultTopologyGraph(description.vertexes(),
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050098 description.edges());
alshabib339a3d92014-09-26 17:54:32 -070099
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800100 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
101 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700102
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800103 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
104
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800105 this.weight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800106 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500107 this.infrastructurePoints = Suppliers
108 .memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800109 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700110 }
111
112 @Override
113 public long time() {
114 return time;
115 }
116
117 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500118 public long creationTime() {
119 return creationTime;
120 }
121
122 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800123 public long computeCost() {
124 return computeCost;
125 }
126
127 @Override
alshabib339a3d92014-09-26 17:54:32 -0700128 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800129 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700130 }
131
132 @Override
133 public int deviceCount() {
134 return graph.getVertexes().size();
135 }
136
137 @Override
138 public int linkCount() {
139 return graph.getEdges().size();
140 }
141
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800142 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
143 return clusterIndexes.get().clustersByDevice;
144 }
145
146 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
147 return clusterIndexes.get().devicesByCluster;
148 }
149
150 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
151 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700152 }
153
154 /**
155 * Returns the backing topology graph.
156 *
157 * @return topology graph
158 */
159 TopologyGraph getGraph() {
160 return graph;
161 }
162
163 /**
164 * Returns the set of topology clusters.
165 *
166 * @return set of clusters
167 */
168 Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800169 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700170 }
171
172 /**
173 * Returns the specified topology cluster.
174 *
175 * @param clusterId cluster identifier
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500176 *
alshabib339a3d92014-09-26 17:54:32 -0700177 * @return topology cluster
178 */
179 TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800180 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700181 }
182
183 /**
184 * Returns the topology cluster that contains the given device.
185 *
186 * @param deviceId device identifier
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500187 *
alshabib339a3d92014-09-26 17:54:32 -0700188 * @return topology cluster
189 */
190 TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800191 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700192 }
193
194 /**
195 * Returns the set of cluster devices.
196 *
197 * @param cluster topology cluster
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500198 *
alshabib339a3d92014-09-26 17:54:32 -0700199 * @return cluster devices
200 */
201 Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800202 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700203 }
204
205 /**
206 * Returns the set of cluster links.
207 *
208 * @param cluster topology cluster
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500209 *
alshabib339a3d92014-09-26 17:54:32 -0700210 * @return cluster links
211 */
212 Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800213 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700214 }
215
216 /**
217 * Indicates whether the given point is an infrastructure link end-point.
218 *
219 * @param connectPoint connection point
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500220 *
alshabib339a3d92014-09-26 17:54:32 -0700221 * @return true if infrastructure
222 */
223 boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800224 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700225 }
226
227 /**
228 * Indicates whether the given point is part of a broadcast set.
229 *
230 * @param connectPoint connection point
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500231 *
alshabib339a3d92014-09-26 17:54:32 -0700232 * @return true if in broadcast set
233 */
234 boolean isBroadcastPoint(ConnectPoint connectPoint) {
235 // Any non-infrastructure, i.e. edge points are assumed to be OK.
236 if (!isInfrastructure(connectPoint)) {
237 return true;
238 }
239
240 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800241 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700242 if (cluster == null) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500243 throw new IllegalArgumentException("No cluster found for device "
244 + connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700245 }
246
247 // If the broadcast set is null or empty, or if the point explicitly
248 // belongs to it, return true;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800249 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500250 return (points == null) || points.isEmpty() || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700251 }
252
253 /**
254 * Returns the size of the cluster broadcast set.
255 *
256 * @param clusterId cluster identifier
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500257 *
alshabib339a3d92014-09-26 17:54:32 -0700258 * @return size of the cluster broadcast set
259 */
260 int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800261 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700262 }
263
264 /**
265 * Returns the set of pre-computed shortest paths between source and
266 * destination devices.
267 *
268 * @param src source device
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500269 *
alshabib339a3d92014-09-26 17:54:32 -0700270 * @param dst destination device
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500271 *
alshabib339a3d92014-09-26 17:54:32 -0700272 * @return set of shortest paths
273 */
274 Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800275 return getPaths(src, dst, null);
alshabib339a3d92014-09-26 17:54:32 -0700276 }
277
278 /**
279 * Computes on-demand the set of shortest paths between source and
280 * destination devices.
281 *
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500282 * @param src source device
283 *
284 * @param dst destination device
285 *
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800286 * @param weight link weight function
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500287 *
alshabib339a3d92014-09-26 17:54:32 -0700288 * @return set of shortest paths
289 */
290 Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800291 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
292 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
293 Set<TopologyVertex> vertices = graph.getVertexes();
294 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
295 // src or dst not part of the current graph
296 return ImmutableSet.of();
297 }
298
alshabib339a3d92014-09-26 17:54:32 -0700299 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800300 DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700301 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
302 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
303 builder.add(networkPath(path));
304 }
305 return builder.build();
306 }
307
alshabib339a3d92014-09-26 17:54:32 -0700308 // Converts graph path to a network path with the same cost.
309 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
310 List<Link> links = new ArrayList<>();
311 for (TopologyEdge edge : path.edges()) {
312 links.add(edge.link());
313 }
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800314 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700315 }
316
alshabib339a3d92014-09-26 17:54:32 -0700317 // Searches for SCC clusters in the network topology graph using Tarjan
318 // algorithm.
319 private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
320 return TARJAN.search(graph, new NoIndirectLinksWeight());
321 }
322
323 // Builds the topology clusters and returns the id-cluster bindings.
324 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
325 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800326 SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
alshabib339a3d92014-09-26 17:54:32 -0700327 // Extract both vertexes and edges from the results; the lists form
328 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800329 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
330 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700331
332 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800333 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700334 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
335 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
336
337 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500338 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
339 vertexSet.size(),
340 edgeSet.size(),
341 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700342 clusterBuilder.put(cid, cluster);
343 }
344 return clusterBuilder.build();
345 }
346
347 // Finds the vertex whose device id is the lexicographical minimum in the
348 // specified set.
349 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
350 TopologyVertex minVertex = null;
351 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500352 if ((minVertex == null) || (minVertex.deviceId()
353 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700354 minVertex = vertex;
355 }
356 }
357 return minVertex;
358 }
359
360 // Processes a map of broadcast sets for each cluster.
361 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500362 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap
363 .builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800364 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700365 addClusterBroadcastSet(cluster, builder);
366 }
367 return builder.build();
368 }
369
370 // Finds all broadcast points for the cluster. These are those connection
371 // points which lie along the shortest paths between the cluster root and
372 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500373 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700374 // Use the graph root search results to build the broadcast set.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500375 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700376 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
377 TopologyVertex vertex = entry.getKey();
378
379 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800380 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700381 continue;
382 }
383
384 // Ignore any back-link sets that are empty.
385 Set<TopologyEdge> parents = entry.getValue();
386 if (parents.isEmpty()) {
387 continue;
388 }
389
390 // Use the first back-link source and destinations to add to the
391 // broadcast set.
392 Link link = parents.iterator().next().link();
393 builder.put(cluster.id(), link.src());
394 builder.put(cluster.id(), link.dst());
395 }
396 }
397
398 // Collects and returns an set of all infrastructure link end-points.
399 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
400 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
401 for (TopologyEdge edge : graph.getEdges()) {
402 builder.add(edge.link().src());
403 builder.add(edge.link().dst());
404 }
405 return builder.build();
406 }
407
408 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800409 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700410 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500411 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
412 ImmutableMap.builder();
413 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
414 ImmutableSetMultimap.builder();
415 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
416 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700417
418 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800419 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700420 int i = cluster.id().index();
421
422 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800423 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700424 devicesBuilder.put(cluster, vertex.deviceId());
425 clusterBuilder.put(vertex.deviceId(), cluster);
426 }
427
428 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800429 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700430 linksBuilder.put(cluster, edge.link());
431 }
432 }
433
434 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800435 return new ClusterIndexes(clusterBuilder.build(),
436 devicesBuilder.build(),
437 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700438 }
439
440 // Link weight for measuring link cost as hop count with indirect links
441 // being as expensive as traversing the entire graph to assume the worst.
442 private static class HopCountLinkWeight implements LinkWeight {
443 private final int indirectLinkCost;
444
445 HopCountLinkWeight(int indirectLinkCost) {
446 this.indirectLinkCost = indirectLinkCost;
447 }
448
449 @Override
450 public double weight(TopologyEdge edge) {
451 // To force preference to use direct paths first, make indirect
452 // links as expensive as the linear vertex traversal.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500453 return edge.link().state() ==
454 ACTIVE ? (edge.link().type() ==
455 INDIRECT ? indirectLinkCost : 1) : -1;
alshabib339a3d92014-09-26 17:54:32 -0700456 }
457 }
458
459 // Link weight for preventing traversal over indirect links.
460 private static class NoIndirectLinksWeight implements LinkWeight {
461 @Override
462 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500463 return (edge.link().state() == INACTIVE)
464 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700465 }
466 }
467
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800468 static final class ClusterIndexes {
469 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
470 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
471 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
472
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500473 public ClusterIndexes(
474 ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
475 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
476 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800477 this.clustersByDevice = clustersByDevice;
478 this.devicesByCluster = devicesByCluster;
479 this.linksByCluster = linksByCluster;
480 }
481 }
482
alshabib339a3d92014-09-26 17:54:32 -0700483 @Override
484 public String toString() {
485 return toStringHelper(this)
486 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500487 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800488 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700489 .add("clusters", clusterCount())
490 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500491 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700492 }
493}