blob: 8ed8513b593aeec5c0f2a665091bdc3f093ea486 [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;
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -070040import org.onosproject.net.Link.Type;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.Path;
42import org.onosproject.net.provider.ProviderId;
43import org.onosproject.net.topology.ClusterId;
44import org.onosproject.net.topology.DefaultTopologyCluster;
45import org.onosproject.net.topology.DefaultTopologyVertex;
46import org.onosproject.net.topology.GraphDescription;
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080047import org.onosproject.net.topology.HopCountLinkWeight;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.topology.LinkWeight;
49import org.onosproject.net.topology.Topology;
50import org.onosproject.net.topology.TopologyCluster;
51import org.onosproject.net.topology.TopologyEdge;
52import org.onosproject.net.topology.TopologyGraph;
53import org.onosproject.net.topology.TopologyVertex;
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080054import org.slf4j.Logger;
55import org.slf4j.LoggerFactory;
alshabib339a3d92014-09-26 17:54:32 -070056
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070057import java.util.HashMap;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070058import java.util.List;
59import java.util.Map;
60import java.util.Set;
Thomas Vachuska48e64e42015-09-22 15:32:55 -070061import java.util.stream.Collectors;
alshabib339a3d92014-09-26 17:54:32 -070062
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070063import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070064import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070065import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070066import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070067import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070068import static org.onosproject.net.Link.State.INACTIVE;
69import static org.onosproject.net.Link.Type.INDIRECT;
70
alshabib339a3d92014-09-26 17:54:32 -070071/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050072 * Default implementation of the topology descriptor. This carries the backing
73 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070074 */
75public class DefaultTopology extends AbstractModel implements Topology {
76
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080077 private static final Logger log = LoggerFactory.getLogger(DefaultTopology.class);
78
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050079 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
80 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080081 private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = new SuurballeGraphSearch<>();
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070082
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080083 private static LinkWeight defaultLinkWeight = null;
84 private static GraphPathSearch<TopologyVertex, TopologyEdge> defaultGraphPathSearch = null;
alshabib339a3d92014-09-26 17:54:32 -070085
alshabib339a3d92014-09-26 17:54:32 -070086 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050087 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080088 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070089 private final TopologyGraph graph;
90
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -080091 private final LinkWeight hopCountWeight;
92
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080093 private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080094 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
95 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
96 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070097 private final Function<ConnectPoint, Boolean> broadcastFunction;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080098 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070099
100 /**
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800101 * Sets the default link-weight to be used when computing paths. If null is
102 * specified, the builtin default link-weight measuring hop-counts will be
103 * used.
104 *
105 * @param linkWeight new default link-weight
106 */
107 public static void setDefaultLinkWeight(LinkWeight linkWeight) {
108 log.info("Setting new default link-weight function to {}", linkWeight);
109 defaultLinkWeight = linkWeight;
110 }
111
112 /**
113 * Sets the default lpath search algorighm to be used when computing paths.
114 * If null is specified, the builtin default Dijkstra will be used.
115 *
116 * @param graphPathSearch new default algorithm
117 */
118 public static void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) {
119 log.info("Setting new default graph path algorithm to {}", graphPathSearch);
120 defaultGraphPathSearch = graphPathSearch;
121 }
122
123
124 /**
alshabib339a3d92014-09-26 17:54:32 -0700125 * Creates a topology descriptor attributed to the specified provider.
126 *
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700127 * @param providerId identity of the provider
128 * @param description data describing the new topology
129 * @param broadcastFunction broadcast point function
alshabib339a3d92014-09-26 17:54:32 -0700130 */
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700131 public DefaultTopology(ProviderId providerId, GraphDescription description,
132 Function<ConnectPoint, Boolean> broadcastFunction) {
alshabib339a3d92014-09-26 17:54:32 -0700133 super(providerId);
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700134 this.broadcastFunction = broadcastFunction;
alshabib339a3d92014-09-26 17:54:32 -0700135 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500136 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -0700137
138 // Build the graph
139 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700140 description.edges());
alshabib339a3d92014-09-26 17:54:32 -0700141
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800142 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
143 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700144
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800145 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
146
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800147 this.hopCountWeight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800148 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700149 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800150 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700151 }
152
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700153 /**
154 * Creates a topology descriptor attributed to the specified provider.
155 *
156 * @param providerId identity of the provider
157 * @param description data describing the new topology
158 */
159 public DefaultTopology(ProviderId providerId, GraphDescription description) {
160 this(providerId, description, null);
161 }
162
alshabib339a3d92014-09-26 17:54:32 -0700163 @Override
164 public long time() {
165 return time;
166 }
167
168 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500169 public long creationTime() {
170 return creationTime;
171 }
172
173 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800174 public long computeCost() {
175 return computeCost;
176 }
177
178 @Override
alshabib339a3d92014-09-26 17:54:32 -0700179 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800180 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700181 }
182
183 @Override
184 public int deviceCount() {
185 return graph.getVertexes().size();
186 }
187
188 @Override
189 public int linkCount() {
190 return graph.getEdges().size();
191 }
192
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800193 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
194 return clusterIndexes.get().clustersByDevice;
195 }
196
197 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
198 return clusterIndexes.get().devicesByCluster;
199 }
200
201 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
202 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700203 }
204
205 /**
206 * Returns the backing topology graph.
207 *
208 * @return topology graph
209 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700210 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700211 return graph;
212 }
213
214 /**
215 * Returns the set of topology clusters.
216 *
217 * @return set of clusters
218 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700219 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800220 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700221 }
222
223 /**
224 * Returns the specified topology cluster.
225 *
226 * @param clusterId cluster identifier
227 * @return topology cluster
228 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700229 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800230 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700231 }
232
233 /**
234 * Returns the topology cluster that contains the given device.
235 *
236 * @param deviceId device identifier
237 * @return topology cluster
238 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700239 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800240 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700241 }
242
243 /**
244 * Returns the set of cluster devices.
245 *
246 * @param cluster topology cluster
247 * @return cluster devices
248 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700249 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800250 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700251 }
252
253 /**
254 * Returns the set of cluster links.
255 *
256 * @param cluster topology cluster
257 * @return cluster links
258 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700259 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800260 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700261 }
262
263 /**
264 * Indicates whether the given point is an infrastructure link end-point.
265 *
266 * @param connectPoint connection point
267 * @return true if infrastructure
268 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700269 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800270 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700271 }
272
273 /**
274 * Indicates whether the given point is part of a broadcast set.
275 *
276 * @param connectPoint connection point
277 * @return true if in broadcast set
278 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700279 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700280 if (broadcastFunction != null) {
281 return broadcastFunction.apply(connectPoint);
282 }
283
alshabib339a3d92014-09-26 17:54:32 -0700284 // Any non-infrastructure, i.e. edge points are assumed to be OK.
285 if (!isInfrastructure(connectPoint)) {
286 return true;
287 }
288
289 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800290 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700291 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700292
293 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700294 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800295 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700296 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700297 }
298
299 /**
300 * Returns the size of the cluster broadcast set.
301 *
302 * @param clusterId cluster identifier
303 * @return size of the cluster broadcast set
304 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700305 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800306 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700307 }
308
309 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700310 * Returns the set of the cluster broadcast points.
311 *
312 * @param clusterId cluster identifier
313 * @return set of cluster broadcast points
314 */
315 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
316 return broadcastSets.get().get(clusterId);
317 }
318
319 /**
alshabib339a3d92014-09-26 17:54:32 -0700320 * Returns the set of pre-computed shortest paths between source and
321 * destination devices.
322 *
323 * @param src source device
324 * @param dst destination device
325 * @return set of shortest paths
326 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700327 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Aaron Kruglikovf6aed992016-11-08 15:16:03 -0800328 return getPaths(src, dst, linkWeight(), ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700329 }
330
Aaron Kruglikovf6aed992016-11-08 15:16:03 -0800331
alshabib339a3d92014-09-26 17:54:32 -0700332 /**
333 * Computes on-demand the set of shortest paths between source and
334 * destination devices.
335 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700336 * @param src source device
337 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800338 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700339 * @return set of shortest paths
340 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700341 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Aaron Kruglikovf6aed992016-11-08 15:16:03 -0800342 return getPaths(src, dst, weight, ALL_PATHS);
343 }
344
345 /**
346 * Computes on-demand the set of shortest paths between source and
347 * destination devices, the set of returned paths will be no more than,
348 * maxPaths in size. The first {@code maxPaths} paths will be returned
349 * maintaining any ordering guarantees provided by the underlying
350 * (default or if no default is specified {@link DijkstraGraphSearch})
351 * search. If returning all paths of a given length would exceed
352 * {@code maxPaths} a subset of paths of that length will be returned,
353 * which paths will be returned depends on the currently specified
354 * {@code GraphPathSearch}. See {@link #setDefaultGraphPathSearch}.
355 *
356 * @param src source device
357 * @param dst destination device
358 * @param weight link weight function
359 * @param maxPaths maximum number of paths
360 * @return set of shortest paths
361 */
362 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight,
363 int maxPaths) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800364 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
365 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800366 Set<TopologyVertex> vertices = graph.getVertexes();
367 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
368 // src or dst not part of the current graph
369 return ImmutableSet.of();
370 }
371
alshabib339a3d92014-09-26 17:54:32 -0700372 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Aaron Kruglikovf6aed992016-11-08 15:16:03 -0800373 graphPathSearch().search(graph, srcV, dstV, weight, maxPaths);
alshabib339a3d92014-09-26 17:54:32 -0700374 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
375 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
376 builder.add(networkPath(path));
377 }
378 return builder.build();
379 }
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700380
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700381 /**
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700382 * /**
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700383 * Returns the set of pre-computed shortest disjoint path pairs between source and
384 * destination devices.
385 *
386 * @param src source device
387 * @param dst destination device
388 * @return set of shortest disjoint path pairs
389 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700390 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800391 return getDisjointPaths(src, dst, linkWeight());
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700392 }
393
394 /**
395 * Computes on-demand the set of shortest disjoint path pairs between source and
396 * destination devices.
397 *
398 * @param src source device
399 * @param dst destination device
400 * @param weight link weight function
401 * @return set of disjoint shortest path pairs
402 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700403 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800404 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
405 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700406 Set<TopologyVertex> vertices = graph.getVertexes();
407 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
408 // src or dst not part of the current graph
409 return ImmutableSet.of();
410 }
411
412 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
413 SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS);
414 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
415 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
helenyrwue3c43342016-08-11 10:33:12 -0700416 DisjointPath disjointPath =
417 networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path);
418 if (disjointPath.backup() != null) {
419 builder.add(disjointPath);
420 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700421 }
422 return builder.build();
423 }
424
425 /**
426 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
427 * destination devices.
428 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700429 * @param src source device
430 * @param dst destination device
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700431 * @param weight edge weight object
432 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700433 * @return set of shortest disjoint paths
434 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700435 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800436 Map<TopologyEdge, Object> riskProfile) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700437 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
438 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
439
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700440 Set<TopologyVertex> vertices = graph.getVertexes();
441 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
442 // src or dst not part of the current graph
443 return ImmutableSet.of();
444 }
445
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800446 SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg = new SrlgGraphSearch<>(riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700447 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
448 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
449 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
450 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
helenyrwue3c43342016-08-11 10:33:12 -0700451 DisjointPath disjointPath =
452 networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path);
453 if (disjointPath.backup() != null) {
454 builder.add(disjointPath);
455 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700456 }
457 return builder.build();
458 }
459
460 /**
461 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
462 * destination devices.
463 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700464 * @param src source device
465 * @param dst destination device
466 * @param weight edge weight object
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, LinkWeight weight,
471 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700472 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
473 for (Link l : riskProfile.keySet()) {
474 riskProfile2.put(new TopologyEdge() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700475 Link cur = l;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700476
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700477 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700478 public Link link() {
479 return cur;
480 }
481
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700482 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700483 public TopologyVertex src() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700484 return () -> src;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700485 }
486
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700487 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700488 public TopologyVertex dst() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700489 return () -> dst;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700490 }
491 }, riskProfile.get(l));
492 }
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700493 return disjointPaths(src, dst, weight, riskProfile2);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700494 }
495
496 /**
497 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
498 * destination devices.
499 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700500 * @param src source device
501 * @param dst destination device
502 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700503 * @return set of shortest disjoint paths
504 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700505 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800506 return getDisjointPaths(src, dst, linkWeight(), riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700507 }
alshabib339a3d92014-09-26 17:54:32 -0700508
alshabib339a3d92014-09-26 17:54:32 -0700509 // Converts graph path to a network path with the same cost.
510 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700511 List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800512 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700513 }
514
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700515 private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
Yuta HIGUCHIc3d69f52016-08-08 11:52:52 -0700516 if (!path.hasBackup()) {
517 // There was no secondary path available.
518 return new DefaultDisjointPath(CORE_PROVIDER_ID,
519 (DefaultPath) networkPath(path.primary()),
520 null);
521 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700522 return new DefaultDisjointPath(CORE_PROVIDER_ID,
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700523 (DefaultPath) networkPath(path.primary()),
524 (DefaultPath) networkPath(path.secondary()));
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700525 }
526
alshabib339a3d92014-09-26 17:54:32 -0700527 // Searches for SCC clusters in the network topology graph using Tarjan
528 // algorithm.
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800529 private SccResult<TopologyVertex, TopologyEdge> searchForClusters() {
alshabib339a3d92014-09-26 17:54:32 -0700530 return TARJAN.search(graph, new NoIndirectLinksWeight());
531 }
532
533 // Builds the topology clusters and returns the id-cluster bindings.
534 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
535 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800536 SccResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700537
alshabib339a3d92014-09-26 17:54:32 -0700538 // Extract both vertexes and edges from the results; the lists form
539 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800540 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
541 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700542
543 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800544 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700545 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
546 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
547
548 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500549 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
550 vertexSet.size(),
551 edgeSet.size(),
552 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700553 clusterBuilder.put(cid, cluster);
554 }
555 return clusterBuilder.build();
556 }
557
558 // Finds the vertex whose device id is the lexicographical minimum in the
559 // specified set.
560 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
561 TopologyVertex minVertex = null;
562 for (TopologyVertex vertex : vertexSet) {
Jon Halle7539632016-05-11 15:44:31 -0700563 if ((minVertex == null) || (vertex.deviceId()
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500564 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700565 minVertex = vertex;
566 }
567 }
568 return minVertex;
569 }
570
571 // Processes a map of broadcast sets for each cluster.
572 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800573 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800574 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700575 addClusterBroadcastSet(cluster, builder);
576 }
577 return builder.build();
578 }
579
580 // Finds all broadcast points for the cluster. These are those connection
581 // points which lie along the shortest paths between the cluster root and
582 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500583 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700584 // Use the graph root search results to build the broadcast set.
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800585 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700586 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
587 TopologyVertex vertex = entry.getKey();
588
589 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800590 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700591 continue;
592 }
593
594 // Ignore any back-link sets that are empty.
595 Set<TopologyEdge> parents = entry.getValue();
596 if (parents.isEmpty()) {
597 continue;
598 }
599
600 // Use the first back-link source and destinations to add to the
601 // broadcast set.
602 Link link = parents.iterator().next().link();
603 builder.put(cluster.id(), link.src());
604 builder.put(cluster.id(), link.dst());
605 }
606 }
607
608 // Collects and returns an set of all infrastructure link end-points.
609 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
610 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
611 for (TopologyEdge edge : graph.getEdges()) {
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700612 if (edge.link().type() == Type.EDGE) {
613 // exclude EDGE link from infrastructure link
614 // - Device <-> Host
615 // - Device <-> remote domain Device
616 continue;
617 }
alshabib339a3d92014-09-26 17:54:32 -0700618 builder.add(edge.link().src());
619 builder.add(edge.link().dst());
620 }
621 return builder.build();
622 }
623
624 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800625 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700626 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500627 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
628 ImmutableMap.builder();
629 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
630 ImmutableSetMultimap.builder();
631 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
632 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700633
634 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800635 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700636 int i = cluster.id().index();
637
638 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800639 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700640 devicesBuilder.put(cluster, vertex.deviceId());
641 clusterBuilder.put(vertex.deviceId(), cluster);
642 }
643
644 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800645 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700646 linksBuilder.put(cluster, edge.link());
647 }
648 }
649
650 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800651 return new ClusterIndexes(clusterBuilder.build(),
652 devicesBuilder.build(),
653 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700654 }
655
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800656 private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
657 return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA;
658 }
alshabib339a3d92014-09-26 17:54:32 -0700659
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800660 private LinkWeight linkWeight() {
661 return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight;
alshabib339a3d92014-09-26 17:54:32 -0700662 }
663
664 // Link weight for preventing traversal over indirect links.
665 private static class NoIndirectLinksWeight implements LinkWeight {
666 @Override
667 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500668 return (edge.link().state() == INACTIVE)
669 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700670 }
671 }
672
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800673 static final class ClusterIndexes {
674 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
675 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
676 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
677
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700678 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
679 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
680 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800681 this.clustersByDevice = clustersByDevice;
682 this.devicesByCluster = devicesByCluster;
683 this.linksByCluster = linksByCluster;
684 }
685 }
686
alshabib339a3d92014-09-26 17:54:32 -0700687 @Override
688 public String toString() {
689 return toStringHelper(this)
690 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500691 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800692 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700693 .add("clusters", clusterCount())
694 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500695 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700696 }
697}