blob: 84cde424aa89677d5f95221a01522626b0d0cb1c [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070016package org.onosproject.common;
alshabib339a3d92014-09-26 17:54:32 -070017
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070018import com.google.common.base.Function;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070019import com.google.common.base.Supplier;
20import com.google.common.base.Suppliers;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.ImmutableSetMultimap;
24import com.google.common.collect.ImmutableSetMultimap.Builder;
alshabib339a3d92014-09-26 17:54:32 -070025import org.onlab.graph.DijkstraGraphSearch;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070026import org.onlab.graph.DisjointPathPair;
alshabib339a3d92014-09-26 17:54:32 -070027import org.onlab.graph.GraphPathSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080028import org.onlab.graph.GraphPathSearch.Result;
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080029import org.onlab.graph.SrlgGraphSearch;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070030import org.onlab.graph.SuurballeGraphSearch;
alshabib339a3d92014-09-26 17:54:32 -070031import org.onlab.graph.TarjanGraphSearch;
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080032import org.onlab.graph.TarjanGraphSearch.SccResult;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.AbstractModel;
34import org.onosproject.net.ConnectPoint;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070035import org.onosproject.net.DefaultDisjointPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.DefaultPath;
37import org.onosproject.net.DeviceId;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070038import org.onosproject.net.DisjointPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import 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
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070053import java.util.HashMap;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070054import java.util.List;
55import java.util.Map;
56import java.util.Set;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070057import java.util.stream.Collectors;
alshabib339a3d92014-09-26 17:54:32 -070058
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070059import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070060import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070061import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070062import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070063import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
64import static org.onosproject.net.Link.State.ACTIVE;
65import static org.onosproject.net.Link.State.INACTIVE;
66import static org.onosproject.net.Link.Type.INDIRECT;
67
alshabib339a3d92014-09-26 17:54:32 -070068/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050069 * Default implementation of the topology descriptor. This carries the backing
70 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070071 */
72public class DefaultTopology extends AbstractModel implements Topology {
73
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050074 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
75 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070076 private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE =
77 new SuurballeGraphSearch<>();
78
alshabib339a3d92014-09-26 17:54:32 -070079
alshabib339a3d92014-09-26 17:54:32 -070080 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050081 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080082 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070083 private final TopologyGraph graph;
84
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080085 private final LinkWeight weight;
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080086 private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080087 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
88 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
89 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070090 private final Function<ConnectPoint, Boolean> broadcastFunction;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080091 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070092
93 /**
94 * Creates a topology descriptor attributed to the specified provider.
95 *
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070096 * @param providerId identity of the provider
97 * @param description data describing the new topology
98 * @param broadcastFunction broadcast point function
alshabib339a3d92014-09-26 17:54:32 -070099 */
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700100 public DefaultTopology(ProviderId providerId, GraphDescription description,
101 Function<ConnectPoint, Boolean> broadcastFunction) {
alshabib339a3d92014-09-26 17:54:32 -0700102 super(providerId);
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700103 this.broadcastFunction = broadcastFunction;
alshabib339a3d92014-09-26 17:54:32 -0700104 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500105 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -0700106
107 // Build the graph
108 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700109 description.edges());
alshabib339a3d92014-09-26 17:54:32 -0700110
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800111 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
112 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700113
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800114 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
115
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800116 this.weight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800117 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700118 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800119 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700120 }
121
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700122 /**
123 * Creates a topology descriptor attributed to the specified provider.
124 *
125 * @param providerId identity of the provider
126 * @param description data describing the new topology
127 */
128 public DefaultTopology(ProviderId providerId, GraphDescription description) {
129 this(providerId, description, null);
130 }
131
alshabib339a3d92014-09-26 17:54:32 -0700132 @Override
133 public long time() {
134 return time;
135 }
136
137 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500138 public long creationTime() {
139 return creationTime;
140 }
141
142 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800143 public long computeCost() {
144 return computeCost;
145 }
146
147 @Override
alshabib339a3d92014-09-26 17:54:32 -0700148 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800149 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700150 }
151
152 @Override
153 public int deviceCount() {
154 return graph.getVertexes().size();
155 }
156
157 @Override
158 public int linkCount() {
159 return graph.getEdges().size();
160 }
161
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800162 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
163 return clusterIndexes.get().clustersByDevice;
164 }
165
166 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
167 return clusterIndexes.get().devicesByCluster;
168 }
169
170 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
171 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700172 }
173
174 /**
175 * Returns the backing topology graph.
176 *
177 * @return topology graph
178 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700179 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700180 return graph;
181 }
182
183 /**
184 * Returns the set of topology clusters.
185 *
186 * @return set of clusters
187 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700188 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800189 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700190 }
191
192 /**
193 * Returns the specified topology cluster.
194 *
195 * @param clusterId cluster identifier
196 * @return topology cluster
197 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700198 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800199 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700200 }
201
202 /**
203 * Returns the topology cluster that contains the given device.
204 *
205 * @param deviceId device identifier
206 * @return topology cluster
207 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700208 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800209 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700210 }
211
212 /**
213 * Returns the set of cluster devices.
214 *
215 * @param cluster topology cluster
216 * @return cluster devices
217 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700218 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800219 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700220 }
221
222 /**
223 * Returns the set of cluster links.
224 *
225 * @param cluster topology cluster
226 * @return cluster links
227 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700228 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800229 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700230 }
231
232 /**
233 * Indicates whether the given point is an infrastructure link end-point.
234 *
235 * @param connectPoint connection point
236 * @return true if infrastructure
237 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700238 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800239 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700240 }
241
242 /**
243 * Indicates whether the given point is part of a broadcast set.
244 *
245 * @param connectPoint connection point
246 * @return true if in broadcast set
247 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700248 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700249 if (broadcastFunction != null) {
250 return broadcastFunction.apply(connectPoint);
251 }
252
alshabib339a3d92014-09-26 17:54:32 -0700253 // Any non-infrastructure, i.e. edge points are assumed to be OK.
254 if (!isInfrastructure(connectPoint)) {
255 return true;
256 }
257
258 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800259 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700260 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700261
262 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700263 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800264 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700265 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700266 }
267
268 /**
269 * Returns the size of the cluster broadcast set.
270 *
271 * @param clusterId cluster identifier
272 * @return size of the cluster broadcast set
273 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700274 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800275 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700276 }
277
278 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700279 * Returns the set of the cluster broadcast points.
280 *
281 * @param clusterId cluster identifier
282 * @return set of cluster broadcast points
283 */
284 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
285 return broadcastSets.get().get(clusterId);
286 }
287
288 /**
alshabib339a3d92014-09-26 17:54:32 -0700289 * Returns the set of pre-computed shortest paths between source and
290 * destination devices.
291 *
292 * @param src source device
293 * @param dst destination device
294 * @return set of shortest paths
295 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700296 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800297 return getPaths(src, dst, null);
alshabib339a3d92014-09-26 17:54:32 -0700298 }
299
300 /**
301 * Computes on-demand the set of shortest paths between source and
302 * destination devices.
303 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700304 * @param src source device
305 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800306 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700307 * @return set of shortest paths
308 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700309 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800310 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
311 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
312 Set<TopologyVertex> vertices = graph.getVertexes();
313 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
314 // src or dst not part of the current graph
315 return ImmutableSet.of();
316 }
317
alshabib339a3d92014-09-26 17:54:32 -0700318 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800319 DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700320 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
321 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
322 builder.add(networkPath(path));
323 }
324 return builder.build();
325 }
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700326
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700327 /**
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700328 * /**
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700329 * Returns the set of pre-computed shortest disjoint path pairs between source and
330 * destination devices.
331 *
332 * @param src source device
333 * @param dst destination device
334 * @return set of shortest disjoint path pairs
335 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700336 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700337 return getDisjointPaths(src, dst, (LinkWeight) null);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700338 }
339
340 /**
341 * Computes on-demand the set of shortest disjoint path pairs between source and
342 * destination devices.
343 *
344 * @param src source device
345 * @param dst destination device
346 * @param weight link weight function
347 * @return set of disjoint shortest path pairs
348 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700349 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700350 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
351 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
352 Set<TopologyVertex> vertices = graph.getVertexes();
353 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
354 // src or dst not part of the current graph
355 return ImmutableSet.of();
356 }
357
358 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
359 SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS);
360 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
361 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
362 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
363 }
364 return builder.build();
365 }
366
367 /**
368 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
369 * destination devices.
370 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700371 * @param src source device
372 * @param dst destination device
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700373 * @param weight edge weight object
374 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700375 * @return set of shortest disjoint paths
376 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700377 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
378 Map<TopologyEdge, Object> riskProfile) {
379 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
380 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
381
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700382 Set<TopologyVertex> vertices = graph.getVertexes();
383 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
384 // src or dst not part of the current graph
385 return ImmutableSet.of();
386 }
387
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800388 SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg = new SrlgGraphSearch<>(riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700389 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
390 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
391 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
392 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
393 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
394 }
395 return builder.build();
396 }
397
398 /**
399 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
400 * destination devices.
401 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700402 * @param src source device
403 * @param dst destination device
404 * @param weight edge weight object
405 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700406 * @return set of shortest disjoint paths
407 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700408 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
409 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700410 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
411 for (Link l : riskProfile.keySet()) {
412 riskProfile2.put(new TopologyEdge() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700413 Link cur = l;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700414
415 public Link link() {
416 return cur;
417 }
418
419 public TopologyVertex src() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700420 return () -> src;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700421 }
422
423 public TopologyVertex dst() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700424 return () -> dst;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700425 }
426 }, riskProfile.get(l));
427 }
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700428 return disjointPaths(src, dst, weight, riskProfile2);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700429 }
430
431 /**
432 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
433 * destination devices.
434 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700435 * @param src source device
436 * @param dst destination device
437 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700438 * @return set of shortest disjoint paths
439 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700440 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
441 return getDisjointPaths(src, dst, null, riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700442 }
alshabib339a3d92014-09-26 17:54:32 -0700443
alshabib339a3d92014-09-26 17:54:32 -0700444 // Converts graph path to a network path with the same cost.
445 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700446 List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800447 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700448 }
449
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700450 private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700451 return new DefaultDisjointPath(CORE_PROVIDER_ID,
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700452 (DefaultPath) networkPath(path.primary()),
453 (DefaultPath) networkPath(path.secondary()));
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700454 }
455
alshabib339a3d92014-09-26 17:54:32 -0700456 // Searches for SCC clusters in the network topology graph using Tarjan
457 // algorithm.
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800458 private SccResult<TopologyVertex, TopologyEdge> searchForClusters() {
alshabib339a3d92014-09-26 17:54:32 -0700459 return TARJAN.search(graph, new NoIndirectLinksWeight());
460 }
461
462 // Builds the topology clusters and returns the id-cluster bindings.
463 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
464 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800465 SccResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700466
alshabib339a3d92014-09-26 17:54:32 -0700467 // Extract both vertexes and edges from the results; the lists form
468 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800469 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
470 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700471
472 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800473 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700474 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
475 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
476
477 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500478 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
479 vertexSet.size(),
480 edgeSet.size(),
481 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700482 clusterBuilder.put(cid, cluster);
483 }
484 return clusterBuilder.build();
485 }
486
487 // Finds the vertex whose device id is the lexicographical minimum in the
488 // specified set.
489 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
490 TopologyVertex minVertex = null;
491 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500492 if ((minVertex == null) || (minVertex.deviceId()
493 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700494 minVertex = vertex;
495 }
496 }
497 return minVertex;
498 }
499
500 // Processes a map of broadcast sets for each cluster.
501 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500502 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap
503 .builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800504 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700505 addClusterBroadcastSet(cluster, builder);
506 }
507 return builder.build();
508 }
509
510 // Finds all broadcast points for the cluster. These are those connection
511 // points which lie along the shortest paths between the cluster root and
512 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500513 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700514 // Use the graph root search results to build the broadcast set.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500515 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700516 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
517 TopologyVertex vertex = entry.getKey();
518
519 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800520 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700521 continue;
522 }
523
524 // Ignore any back-link sets that are empty.
525 Set<TopologyEdge> parents = entry.getValue();
526 if (parents.isEmpty()) {
527 continue;
528 }
529
530 // Use the first back-link source and destinations to add to the
531 // broadcast set.
532 Link link = parents.iterator().next().link();
533 builder.put(cluster.id(), link.src());
534 builder.put(cluster.id(), link.dst());
535 }
536 }
537
538 // Collects and returns an set of all infrastructure link end-points.
539 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
540 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
541 for (TopologyEdge edge : graph.getEdges()) {
542 builder.add(edge.link().src());
543 builder.add(edge.link().dst());
544 }
545 return builder.build();
546 }
547
548 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800549 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700550 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500551 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
552 ImmutableMap.builder();
553 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
554 ImmutableSetMultimap.builder();
555 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
556 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700557
558 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800559 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700560 int i = cluster.id().index();
561
562 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800563 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700564 devicesBuilder.put(cluster, vertex.deviceId());
565 clusterBuilder.put(vertex.deviceId(), cluster);
566 }
567
568 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800569 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700570 linksBuilder.put(cluster, edge.link());
571 }
572 }
573
574 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800575 return new ClusterIndexes(clusterBuilder.build(),
576 devicesBuilder.build(),
577 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700578 }
579
580 // Link weight for measuring link cost as hop count with indirect links
581 // being as expensive as traversing the entire graph to assume the worst.
582 private static class HopCountLinkWeight implements LinkWeight {
583 private final int indirectLinkCost;
584
585 HopCountLinkWeight(int indirectLinkCost) {
586 this.indirectLinkCost = indirectLinkCost;
587 }
588
589 @Override
590 public double weight(TopologyEdge edge) {
591 // To force preference to use direct paths first, make indirect
592 // links as expensive as the linear vertex traversal.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500593 return edge.link().state() ==
594 ACTIVE ? (edge.link().type() ==
595 INDIRECT ? indirectLinkCost : 1) : -1;
alshabib339a3d92014-09-26 17:54:32 -0700596 }
597 }
598
599 // Link weight for preventing traversal over indirect links.
600 private static class NoIndirectLinksWeight implements LinkWeight {
601 @Override
602 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500603 return (edge.link().state() == INACTIVE)
604 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700605 }
606 }
607
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800608 static final class ClusterIndexes {
609 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
610 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
611 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
612
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700613 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
614 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
615 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800616 this.clustersByDevice = clustersByDevice;
617 this.devicesByCluster = devicesByCluster;
618 this.linksByCluster = linksByCluster;
619 }
620 }
621
alshabib339a3d92014-09-26 17:54:32 -0700622 @Override
623 public String toString() {
624 return toStringHelper(this)
625 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500626 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800627 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700628 .add("clusters", clusterCount())
629 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500630 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700631 }
632}