blob: 5b161ff08d31c497f0c76d7cd8023a84f8e22175 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present 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;
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080046import org.onosproject.net.topology.HopCountLinkWeight;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.topology.LinkWeight;
48import org.onosproject.net.topology.Topology;
49import org.onosproject.net.topology.TopologyCluster;
50import org.onosproject.net.topology.TopologyEdge;
51import org.onosproject.net.topology.TopologyGraph;
52import org.onosproject.net.topology.TopologyVertex;
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
alshabib339a3d92014-09-26 17:54:32 -070055
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070056import java.util.HashMap;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070057import java.util.List;
58import java.util.Map;
59import java.util.Set;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070060import java.util.stream.Collectors;
alshabib339a3d92014-09-26 17:54:32 -070061
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070062import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070063import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070064import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070065import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070066import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070067import static org.onosproject.net.Link.State.INACTIVE;
68import static org.onosproject.net.Link.Type.INDIRECT;
69
alshabib339a3d92014-09-26 17:54:32 -070070/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050071 * Default implementation of the topology descriptor. This carries the backing
72 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070073 */
74public class DefaultTopology extends AbstractModel implements Topology {
75
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080076 private static final Logger log = LoggerFactory.getLogger(DefaultTopology.class);
77
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050078 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
79 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080080 private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = new SuurballeGraphSearch<>();
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070081
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080082 private static LinkWeight defaultLinkWeight = null;
83 private static GraphPathSearch<TopologyVertex, TopologyEdge> defaultGraphPathSearch = null;
alshabib339a3d92014-09-26 17:54:32 -070084
alshabib339a3d92014-09-26 17:54:32 -070085 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050086 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080087 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070088 private final TopologyGraph graph;
89
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080090 private final LinkWeight hopCountWeight;
91
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080092 private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080093 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
94 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
95 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070096 private final Function<ConnectPoint, Boolean> broadcastFunction;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080097 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070098
99 /**
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800100 * Sets the default link-weight to be used when computing paths. If null is
101 * specified, the builtin default link-weight measuring hop-counts will be
102 * used.
103 *
104 * @param linkWeight new default link-weight
105 */
106 public static void setDefaultLinkWeight(LinkWeight linkWeight) {
107 log.info("Setting new default link-weight function to {}", linkWeight);
108 defaultLinkWeight = linkWeight;
109 }
110
111 /**
112 * Sets the default lpath search algorighm to be used when computing paths.
113 * If null is specified, the builtin default Dijkstra will be used.
114 *
115 * @param graphPathSearch new default algorithm
116 */
117 public static void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) {
118 log.info("Setting new default graph path algorithm to {}", graphPathSearch);
119 defaultGraphPathSearch = graphPathSearch;
120 }
121
122
123 /**
alshabib339a3d92014-09-26 17:54:32 -0700124 * Creates a topology descriptor attributed to the specified provider.
125 *
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700126 * @param providerId identity of the provider
127 * @param description data describing the new topology
128 * @param broadcastFunction broadcast point function
alshabib339a3d92014-09-26 17:54:32 -0700129 */
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700130 public DefaultTopology(ProviderId providerId, GraphDescription description,
131 Function<ConnectPoint, Boolean> broadcastFunction) {
alshabib339a3d92014-09-26 17:54:32 -0700132 super(providerId);
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700133 this.broadcastFunction = broadcastFunction;
alshabib339a3d92014-09-26 17:54:32 -0700134 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500135 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -0700136
137 // Build the graph
138 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700139 description.edges());
alshabib339a3d92014-09-26 17:54:32 -0700140
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800141 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
142 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700143
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800144 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
145
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800146 this.hopCountWeight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800147 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700148 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800149 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700150 }
151
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700152 /**
153 * Creates a topology descriptor attributed to the specified provider.
154 *
155 * @param providerId identity of the provider
156 * @param description data describing the new topology
157 */
158 public DefaultTopology(ProviderId providerId, GraphDescription description) {
159 this(providerId, description, null);
160 }
161
alshabib339a3d92014-09-26 17:54:32 -0700162 @Override
163 public long time() {
164 return time;
165 }
166
167 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500168 public long creationTime() {
169 return creationTime;
170 }
171
172 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800173 public long computeCost() {
174 return computeCost;
175 }
176
177 @Override
alshabib339a3d92014-09-26 17:54:32 -0700178 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800179 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700180 }
181
182 @Override
183 public int deviceCount() {
184 return graph.getVertexes().size();
185 }
186
187 @Override
188 public int linkCount() {
189 return graph.getEdges().size();
190 }
191
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800192 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
193 return clusterIndexes.get().clustersByDevice;
194 }
195
196 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
197 return clusterIndexes.get().devicesByCluster;
198 }
199
200 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
201 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700202 }
203
204 /**
205 * Returns the backing topology graph.
206 *
207 * @return topology graph
208 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700209 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700210 return graph;
211 }
212
213 /**
214 * Returns the set of topology clusters.
215 *
216 * @return set of clusters
217 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700218 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800219 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700220 }
221
222 /**
223 * Returns the specified topology cluster.
224 *
225 * @param clusterId cluster identifier
226 * @return topology cluster
227 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700228 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800229 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700230 }
231
232 /**
233 * Returns the topology cluster that contains the given device.
234 *
235 * @param deviceId device identifier
236 * @return topology cluster
237 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700238 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800239 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700240 }
241
242 /**
243 * Returns the set of cluster devices.
244 *
245 * @param cluster topology cluster
246 * @return cluster devices
247 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700248 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800249 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700250 }
251
252 /**
253 * Returns the set of cluster links.
254 *
255 * @param cluster topology cluster
256 * @return cluster links
257 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700258 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800259 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700260 }
261
262 /**
263 * Indicates whether the given point is an infrastructure link end-point.
264 *
265 * @param connectPoint connection point
266 * @return true if infrastructure
267 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700268 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800269 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700270 }
271
272 /**
273 * Indicates whether the given point is part of a broadcast set.
274 *
275 * @param connectPoint connection point
276 * @return true if in broadcast set
277 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700278 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700279 if (broadcastFunction != null) {
280 return broadcastFunction.apply(connectPoint);
281 }
282
alshabib339a3d92014-09-26 17:54:32 -0700283 // Any non-infrastructure, i.e. edge points are assumed to be OK.
284 if (!isInfrastructure(connectPoint)) {
285 return true;
286 }
287
288 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800289 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700290 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700291
292 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700293 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800294 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700295 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700296 }
297
298 /**
299 * Returns the size of the cluster broadcast set.
300 *
301 * @param clusterId cluster identifier
302 * @return size of the cluster broadcast set
303 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700304 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800305 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700306 }
307
308 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700309 * Returns the set of the cluster broadcast points.
310 *
311 * @param clusterId cluster identifier
312 * @return set of cluster broadcast points
313 */
314 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
315 return broadcastSets.get().get(clusterId);
316 }
317
318 /**
alshabib339a3d92014-09-26 17:54:32 -0700319 * Returns the set of pre-computed shortest paths between source and
320 * destination devices.
321 *
322 * @param src source device
323 * @param dst destination device
324 * @return set of shortest paths
325 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700326 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800327 return getPaths(src, dst, linkWeight());
alshabib339a3d92014-09-26 17:54:32 -0700328 }
329
330 /**
331 * Computes on-demand the set of shortest paths between source and
332 * destination devices.
333 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700334 * @param src source device
335 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800336 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700337 * @return set of shortest paths
338 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700339 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800340 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
341 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800342 Set<TopologyVertex> vertices = graph.getVertexes();
343 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
344 // src or dst not part of the current graph
345 return ImmutableSet.of();
346 }
347
alshabib339a3d92014-09-26 17:54:32 -0700348 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800349 graphPathSearch().search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700350 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
351 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
352 builder.add(networkPath(path));
353 }
354 return builder.build();
355 }
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700356
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700357 /**
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700358 * /**
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700359 * Returns the set of pre-computed shortest disjoint path pairs between source and
360 * destination devices.
361 *
362 * @param src source device
363 * @param dst destination device
364 * @return set of shortest disjoint path pairs
365 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700366 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800367 return getDisjointPaths(src, dst, linkWeight());
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700368 }
369
370 /**
371 * Computes on-demand the set of shortest disjoint path pairs between source and
372 * destination devices.
373 *
374 * @param src source device
375 * @param dst destination device
376 * @param weight link weight function
377 * @return set of disjoint shortest path pairs
378 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700379 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800380 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
381 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
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
388 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
389 SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS);
390 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
391 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
392 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
393 }
394 return builder.build();
395 }
396
397 /**
398 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
399 * destination devices.
400 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700401 * @param src source device
402 * @param dst destination device
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700403 * @param weight edge weight object
404 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700405 * @return set of shortest disjoint paths
406 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700407 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800408 Map<TopologyEdge, Object> riskProfile) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700409 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
410 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
411
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700412 Set<TopologyVertex> vertices = graph.getVertexes();
413 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
414 // src or dst not part of the current graph
415 return ImmutableSet.of();
416 }
417
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800418 SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg = new SrlgGraphSearch<>(riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700419 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
420 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
421 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
422 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
423 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
424 }
425 return builder.build();
426 }
427
428 /**
429 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
430 * destination devices.
431 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700432 * @param src source device
433 * @param dst destination device
434 * @param weight edge weight object
435 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700436 * @return set of shortest disjoint paths
437 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700438 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
439 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700440 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
441 for (Link l : riskProfile.keySet()) {
442 riskProfile2.put(new TopologyEdge() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700443 Link cur = l;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700444
445 public Link link() {
446 return cur;
447 }
448
449 public TopologyVertex src() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700450 return () -> src;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700451 }
452
453 public TopologyVertex dst() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700454 return () -> dst;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700455 }
456 }, riskProfile.get(l));
457 }
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700458 return disjointPaths(src, dst, weight, riskProfile2);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700459 }
460
461 /**
462 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
463 * destination devices.
464 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700465 * @param src source device
466 * @param dst destination device
467 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700468 * @return set of shortest disjoint paths
469 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700470 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800471 return getDisjointPaths(src, dst, linkWeight(), riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700472 }
alshabib339a3d92014-09-26 17:54:32 -0700473
alshabib339a3d92014-09-26 17:54:32 -0700474 // Converts graph path to a network path with the same cost.
475 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700476 List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800477 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700478 }
479
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700480 private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700481 return new DefaultDisjointPath(CORE_PROVIDER_ID,
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700482 (DefaultPath) networkPath(path.primary()),
483 (DefaultPath) networkPath(path.secondary()));
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700484 }
485
alshabib339a3d92014-09-26 17:54:32 -0700486 // Searches for SCC clusters in the network topology graph using Tarjan
487 // algorithm.
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800488 private SccResult<TopologyVertex, TopologyEdge> searchForClusters() {
alshabib339a3d92014-09-26 17:54:32 -0700489 return TARJAN.search(graph, new NoIndirectLinksWeight());
490 }
491
492 // Builds the topology clusters and returns the id-cluster bindings.
493 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
494 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800495 SccResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700496
alshabib339a3d92014-09-26 17:54:32 -0700497 // Extract both vertexes and edges from the results; the lists form
498 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800499 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
500 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700501
502 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800503 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700504 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
505 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
506
507 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500508 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
509 vertexSet.size(),
510 edgeSet.size(),
511 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700512 clusterBuilder.put(cid, cluster);
513 }
514 return clusterBuilder.build();
515 }
516
517 // Finds the vertex whose device id is the lexicographical minimum in the
518 // specified set.
519 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
520 TopologyVertex minVertex = null;
521 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500522 if ((minVertex == null) || (minVertex.deviceId()
523 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700524 minVertex = vertex;
525 }
526 }
527 return minVertex;
528 }
529
530 // Processes a map of broadcast sets for each cluster.
531 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800532 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800533 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700534 addClusterBroadcastSet(cluster, builder);
535 }
536 return builder.build();
537 }
538
539 // Finds all broadcast points for the cluster. These are those connection
540 // points which lie along the shortest paths between the cluster root and
541 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500542 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700543 // Use the graph root search results to build the broadcast set.
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800544 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700545 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
546 TopologyVertex vertex = entry.getKey();
547
548 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800549 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700550 continue;
551 }
552
553 // Ignore any back-link sets that are empty.
554 Set<TopologyEdge> parents = entry.getValue();
555 if (parents.isEmpty()) {
556 continue;
557 }
558
559 // Use the first back-link source and destinations to add to the
560 // broadcast set.
561 Link link = parents.iterator().next().link();
562 builder.put(cluster.id(), link.src());
563 builder.put(cluster.id(), link.dst());
564 }
565 }
566
567 // Collects and returns an set of all infrastructure link end-points.
568 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
569 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
570 for (TopologyEdge edge : graph.getEdges()) {
571 builder.add(edge.link().src());
572 builder.add(edge.link().dst());
573 }
574 return builder.build();
575 }
576
577 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800578 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700579 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500580 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
581 ImmutableMap.builder();
582 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
583 ImmutableSetMultimap.builder();
584 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
585 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700586
587 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800588 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700589 int i = cluster.id().index();
590
591 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800592 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700593 devicesBuilder.put(cluster, vertex.deviceId());
594 clusterBuilder.put(vertex.deviceId(), cluster);
595 }
596
597 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800598 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700599 linksBuilder.put(cluster, edge.link());
600 }
601 }
602
603 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800604 return new ClusterIndexes(clusterBuilder.build(),
605 devicesBuilder.build(),
606 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700607 }
608
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800609 private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
610 return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA;
611 }
alshabib339a3d92014-09-26 17:54:32 -0700612
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800613 private LinkWeight linkWeight() {
614 return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight;
alshabib339a3d92014-09-26 17:54:32 -0700615 }
616
617 // Link weight for preventing traversal over indirect links.
618 private static class NoIndirectLinksWeight implements LinkWeight {
619 @Override
620 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500621 return (edge.link().state() == INACTIVE)
622 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700623 }
624 }
625
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800626 static final class ClusterIndexes {
627 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
628 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
629 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
630
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700631 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
632 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
633 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800634 this.clustersByDevice = clustersByDevice;
635 this.devicesByCluster = devicesByCluster;
636 this.linksByCluster = linksByCluster;
637 }
638 }
639
alshabib339a3d92014-09-26 17:54:32 -0700640 @Override
641 public String toString() {
642 return toStringHelper(this)
643 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500644 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800645 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700646 .add("clusters", clusterCount())
647 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500648 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700649 }
650}