blob: 8c4fbc84ec5dad39b8f98f16accc23a9d1077e49 [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()) {
393 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
394 }
395 return builder.build();
396 }
397
398 /**
399 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
400 * destination devices.
401 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700402 * @param src source device
403 * @param dst destination device
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700404 * @param weight edge weight object
405 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700406 * @return set of shortest disjoint paths
407 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700408 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800409 Map<TopologyEdge, Object> riskProfile) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700410 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
411 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
412
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700413 Set<TopologyVertex> vertices = graph.getVertexes();
414 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
415 // src or dst not part of the current graph
416 return ImmutableSet.of();
417 }
418
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800419 SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg = new SrlgGraphSearch<>(riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700420 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
421 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
422 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
423 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
424 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
425 }
426 return builder.build();
427 }
428
429 /**
430 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
431 * destination devices.
432 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700433 * @param src source device
434 * @param dst destination device
435 * @param weight edge weight object
436 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700437 * @return set of shortest disjoint paths
438 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700439 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
440 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700441 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
442 for (Link l : riskProfile.keySet()) {
443 riskProfile2.put(new TopologyEdge() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700444 Link cur = l;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700445
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700446 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700447 public Link link() {
448 return cur;
449 }
450
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700451 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700452 public TopologyVertex src() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700453 return () -> src;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700454 }
455
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700456 @Override
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700457 public TopologyVertex dst() {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700458 return () -> dst;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700459 }
460 }, riskProfile.get(l));
461 }
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700462 return disjointPaths(src, dst, weight, riskProfile2);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700463 }
464
465 /**
466 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
467 * destination devices.
468 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700469 * @param src source device
470 * @param dst destination device
471 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700472 * @return set of shortest disjoint paths
473 */
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700474 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800475 return getDisjointPaths(src, dst, linkWeight(), riskProfile);
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700476 }
alshabib339a3d92014-09-26 17:54:32 -0700477
alshabib339a3d92014-09-26 17:54:32 -0700478 // Converts graph path to a network path with the same cost.
479 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700480 List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800481 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700482 }
483
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700484 private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700485 return new DefaultDisjointPath(CORE_PROVIDER_ID,
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700486 (DefaultPath) networkPath(path.primary()),
487 (DefaultPath) networkPath(path.secondary()));
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700488 }
489
alshabib339a3d92014-09-26 17:54:32 -0700490 // Searches for SCC clusters in the network topology graph using Tarjan
491 // algorithm.
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800492 private SccResult<TopologyVertex, TopologyEdge> searchForClusters() {
alshabib339a3d92014-09-26 17:54:32 -0700493 return TARJAN.search(graph, new NoIndirectLinksWeight());
494 }
495
496 // Builds the topology clusters and returns the id-cluster bindings.
497 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
498 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800499 SccResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
Thomas Vachuska48e64e42015-09-22 15:32:55 -0700500
alshabib339a3d92014-09-26 17:54:32 -0700501 // Extract both vertexes and edges from the results; the lists form
502 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800503 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
504 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700505
506 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800507 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700508 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
509 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
510
511 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500512 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
513 vertexSet.size(),
514 edgeSet.size(),
515 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700516 clusterBuilder.put(cid, cluster);
517 }
518 return clusterBuilder.build();
519 }
520
521 // Finds the vertex whose device id is the lexicographical minimum in the
522 // specified set.
523 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
524 TopologyVertex minVertex = null;
525 for (TopologyVertex vertex : vertexSet) {
Jon Halle7539632016-05-11 15:44:31 -0700526 if ((minVertex == null) || (vertex.deviceId()
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500527 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700528 minVertex = vertex;
529 }
530 }
531 return minVertex;
532 }
533
534 // Processes a map of broadcast sets for each cluster.
535 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800536 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800537 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700538 addClusterBroadcastSet(cluster, builder);
539 }
540 return builder.build();
541 }
542
543 // Finds all broadcast points for the cluster. These are those connection
544 // points which lie along the shortest paths between the cluster root and
545 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500546 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700547 // Use the graph root search results to build the broadcast set.
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800548 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700549 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
550 TopologyVertex vertex = entry.getKey();
551
552 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800553 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700554 continue;
555 }
556
557 // Ignore any back-link sets that are empty.
558 Set<TopologyEdge> parents = entry.getValue();
559 if (parents.isEmpty()) {
560 continue;
561 }
562
563 // Use the first back-link source and destinations to add to the
564 // broadcast set.
565 Link link = parents.iterator().next().link();
566 builder.put(cluster.id(), link.src());
567 builder.put(cluster.id(), link.dst());
568 }
569 }
570
571 // Collects and returns an set of all infrastructure link end-points.
572 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
573 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
574 for (TopologyEdge edge : graph.getEdges()) {
Yuta HIGUCHIb440ef42016-07-15 09:09:09 -0700575 if (edge.link().type() == Type.EDGE) {
576 // exclude EDGE link from infrastructure link
577 // - Device <-> Host
578 // - Device <-> remote domain Device
579 continue;
580 }
alshabib339a3d92014-09-26 17:54:32 -0700581 builder.add(edge.link().src());
582 builder.add(edge.link().dst());
583 }
584 return builder.build();
585 }
586
587 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800588 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700589 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500590 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
591 ImmutableMap.builder();
592 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
593 ImmutableSetMultimap.builder();
594 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
595 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700596
597 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800598 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700599 int i = cluster.id().index();
600
601 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800602 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700603 devicesBuilder.put(cluster, vertex.deviceId());
604 clusterBuilder.put(vertex.deviceId(), cluster);
605 }
606
607 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800608 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700609 linksBuilder.put(cluster, edge.link());
610 }
611 }
612
613 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800614 return new ClusterIndexes(clusterBuilder.build(),
615 devicesBuilder.build(),
616 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700617 }
618
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800619 private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
620 return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA;
621 }
alshabib339a3d92014-09-26 17:54:32 -0700622
Thomas Vachuska41fe1ec2015-12-03 23:17:02 -0800623 private LinkWeight linkWeight() {
624 return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight;
alshabib339a3d92014-09-26 17:54:32 -0700625 }
626
627 // Link weight for preventing traversal over indirect links.
628 private static class NoIndirectLinksWeight implements LinkWeight {
629 @Override
630 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500631 return (edge.link().state() == INACTIVE)
632 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700633 }
634 }
635
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800636 static final class ClusterIndexes {
637 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
638 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
639 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
640
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700641 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
642 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
643 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800644 this.clustersByDevice = clustersByDevice;
645 this.devicesByCluster = devicesByCluster;
646 this.linksByCluster = linksByCluster;
647 }
648 }
649
alshabib339a3d92014-09-26 17:54:32 -0700650 @Override
651 public String toString() {
652 return toStringHelper(this)
653 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500654 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800655 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700656 .add("clusters", clusterCount())
657 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500658 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700659 }
660}