blob: 5321b425569c18828eb5ef13b6f157f6faa43eec [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) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800328 return getPaths(src, dst, linkWeight());
alshabib339a3d92014-09-26 17:54:32 -0700329 }
330
331 /**
332 * Computes on-demand the set of shortest paths between source and
333 * destination devices.
334 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700335 * @param src source device
336 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800337 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700338 * @return set of shortest paths
339 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700340 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800341 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
342 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800343 Set<TopologyVertex> vertices = graph.getVertexes();
344 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
345 // src or dst not part of the current graph
346 return ImmutableSet.of();
347 }
348
alshabib339a3d92014-09-26 17:54:32 -0700349 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800350 graphPathSearch().search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700351 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
352 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
353 builder.add(networkPath(path));
354 }
355 return builder.build();
356 }
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700357
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700358 /**
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700359 * /**
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700360 * Returns the set of pre-computed shortest disjoint path pairs between source and
361 * destination devices.
362 *
363 * @param src source device
364 * @param dst destination device
365 * @return set of shortest disjoint path pairs
366 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700367 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800368 return getDisjointPaths(src, dst, linkWeight());
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700369 }
370
371 /**
372 * Computes on-demand the set of shortest disjoint path pairs between source and
373 * destination devices.
374 *
375 * @param src source device
376 * @param dst destination device
377 * @param weight link weight function
378 * @return set of disjoint shortest path pairs
379 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700380 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800381 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
382 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700383 Set<TopologyVertex> vertices = graph.getVertexes();
384 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
385 // src or dst not part of the current graph
386 return ImmutableSet.of();
387 }
388
389 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
390 SUURBALLE.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()) {
helenyrwue3c43342016-08-11 10:33:12 -0700393 DisjointPath disjointPath =
394 networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path);
395 if (disjointPath.backup() != null) {
396 builder.add(disjointPath);
397 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700398 }
399 return builder.build();
400 }
401
402 /**
403 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
404 * destination devices.
405 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700406 * @param src source device
407 * @param dst destination device
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700408 * @param weight edge weight object
409 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700410 * @return set of shortest disjoint paths
411 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700412 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800413 Map<TopologyEdge, Object> riskProfile) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700414 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
415 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
416
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700417 Set<TopologyVertex> vertices = graph.getVertexes();
418 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
419 // src or dst not part of the current graph
420 return ImmutableSet.of();
421 }
422
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800423 SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg = new SrlgGraphSearch<>(riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700424 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
425 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
426 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
427 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
helenyrwue3c43342016-08-11 10:33:12 -0700428 DisjointPath disjointPath =
429 networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path);
430 if (disjointPath.backup() != null) {
431 builder.add(disjointPath);
432 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700433 }
434 return builder.build();
435 }
436
437 /**
438 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
439 * destination devices.
440 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700441 * @param src source device
442 * @param dst destination device
443 * @param weight edge weight object
444 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700445 * @return set of shortest disjoint paths
446 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700447 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
448 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700449 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
450 for (Link l : riskProfile.keySet()) {
451 riskProfile2.put(new TopologyEdge() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700452 Link cur = l;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700453
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700454 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700455 public Link link() {
456 return cur;
457 }
458
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700459 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700460 public TopologyVertex src() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700461 return () -> src;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700462 }
463
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700464 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700465 public TopologyVertex dst() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700466 return () -> dst;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700467 }
468 }, riskProfile.get(l));
469 }
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700470 return disjointPaths(src, dst, weight, riskProfile2);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700471 }
472
473 /**
474 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
475 * destination devices.
476 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700477 * @param src source device
478 * @param dst destination device
479 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700480 * @return set of shortest disjoint paths
481 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700482 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800483 return getDisjointPaths(src, dst, linkWeight(), riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700484 }
alshabib339a3d92014-09-26 17:54:32 -0700485
alshabib339a3d92014-09-26 17:54:32 -0700486 // Converts graph path to a network path with the same cost.
487 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700488 List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800489 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700490 }
491
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700492 private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
Yuta HIGUCHIc3d69f52016-08-08 11:52:52 -0700493 if (!path.hasBackup()) {
494 // There was no secondary path available.
495 return new DefaultDisjointPath(CORE_PROVIDER_ID,
496 (DefaultPath) networkPath(path.primary()),
497 null);
498 }
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700499 return new DefaultDisjointPath(CORE_PROVIDER_ID,
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700500 (DefaultPath) networkPath(path.primary()),
501 (DefaultPath) networkPath(path.secondary()));
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700502 }
503
alshabib339a3d92014-09-26 17:54:32 -0700504 // Searches for SCC clusters in the network topology graph using Tarjan
505 // algorithm.
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800506 private SccResult<TopologyVertex, TopologyEdge> searchForClusters() {
alshabib339a3d92014-09-26 17:54:32 -0700507 return TARJAN.search(graph, new NoIndirectLinksWeight());
508 }
509
510 // Builds the topology clusters and returns the id-cluster bindings.
511 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
512 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800513 SccResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700514
alshabib339a3d92014-09-26 17:54:32 -0700515 // Extract both vertexes and edges from the results; the lists form
516 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800517 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
518 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700519
520 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800521 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700522 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
523 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
524
525 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500526 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
527 vertexSet.size(),
528 edgeSet.size(),
529 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700530 clusterBuilder.put(cid, cluster);
531 }
532 return clusterBuilder.build();
533 }
534
535 // Finds the vertex whose device id is the lexicographical minimum in the
536 // specified set.
537 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
538 TopologyVertex minVertex = null;
539 for (TopologyVertex vertex : vertexSet) {
Jon Halle7539632016-05-11 15:44:31 -0700540 if ((minVertex == null) || (vertex.deviceId()
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500541 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700542 minVertex = vertex;
543 }
544 }
545 return minVertex;
546 }
547
548 // Processes a map of broadcast sets for each cluster.
549 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800550 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800551 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700552 addClusterBroadcastSet(cluster, builder);
553 }
554 return builder.build();
555 }
556
557 // Finds all broadcast points for the cluster. These are those connection
558 // points which lie along the shortest paths between the cluster root and
559 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500560 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700561 // Use the graph root search results to build the broadcast set.
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800562 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700563 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
564 TopologyVertex vertex = entry.getKey();
565
566 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800567 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700568 continue;
569 }
570
571 // Ignore any back-link sets that are empty.
572 Set<TopologyEdge> parents = entry.getValue();
573 if (parents.isEmpty()) {
574 continue;
575 }
576
577 // Use the first back-link source and destinations to add to the
578 // broadcast set.
579 Link link = parents.iterator().next().link();
580 builder.put(cluster.id(), link.src());
581 builder.put(cluster.id(), link.dst());
582 }
583 }
584
585 // Collects and returns an set of all infrastructure link end-points.
586 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
587 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
588 for (TopologyEdge edge : graph.getEdges()) {
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700589 if (edge.link().type() == Type.EDGE) {
590 // exclude EDGE link from infrastructure link
591 // - Device <-> Host
592 // - Device <-> remote domain Device
593 continue;
594 }
alshabib339a3d92014-09-26 17:54:32 -0700595 builder.add(edge.link().src());
596 builder.add(edge.link().dst());
597 }
598 return builder.build();
599 }
600
601 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800602 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700603 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500604 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
605 ImmutableMap.builder();
606 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
607 ImmutableSetMultimap.builder();
608 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
609 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700610
611 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800612 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700613 int i = cluster.id().index();
614
615 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800616 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700617 devicesBuilder.put(cluster, vertex.deviceId());
618 clusterBuilder.put(vertex.deviceId(), cluster);
619 }
620
621 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800622 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700623 linksBuilder.put(cluster, edge.link());
624 }
625 }
626
627 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800628 return new ClusterIndexes(clusterBuilder.build(),
629 devicesBuilder.build(),
630 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700631 }
632
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800633 private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
634 return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA;
635 }
alshabib339a3d92014-09-26 17:54:32 -0700636
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800637 private LinkWeight linkWeight() {
638 return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight;
alshabib339a3d92014-09-26 17:54:32 -0700639 }
640
641 // Link weight for preventing traversal over indirect links.
642 private static class NoIndirectLinksWeight implements LinkWeight {
643 @Override
644 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500645 return (edge.link().state() == INACTIVE)
646 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700647 }
648 }
649
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800650 static final class ClusterIndexes {
651 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
652 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
653 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
654
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700655 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
656 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
657 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800658 this.clustersByDevice = clustersByDevice;
659 this.devicesByCluster = devicesByCluster;
660 this.linksByCluster = linksByCluster;
661 }
662 }
663
alshabib339a3d92014-09-26 17:54:32 -0700664 @Override
665 public String toString() {
666 return toStringHelper(this)
667 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500668 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800669 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700670 .add("clusters", clusterCount())
671 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500672 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700673 }
674}