blob: f2f86eaa0a5b51b33a0bf66ef8b924b93cb35121 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070016package org.onosproject.common;
alshabib339a3d92014-09-26 17:54:32 -070017
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070018import com.google.common.base.Function;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070019import com.google.common.base.Supplier;
20import com.google.common.base.Suppliers;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.ImmutableSetMultimap;
24import com.google.common.collect.ImmutableSetMultimap.Builder;
alshabib339a3d92014-09-26 17:54:32 -070025import org.onlab.graph.DijkstraGraphSearch;
26import org.onlab.graph.GraphPathSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080027import org.onlab.graph.GraphPathSearch.Result;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070028import org.onlab.graph.SRLGGraphSearch;
29import org.onlab.graph.SuurballeGraphSearch;
alshabib339a3d92014-09-26 17:54:32 -070030import org.onlab.graph.TarjanGraphSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080031import org.onlab.graph.TarjanGraphSearch.SCCResult;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.AbstractModel;
33import org.onosproject.net.ConnectPoint;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070034import org.onosproject.net.DefaultDisjointPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.DefaultPath;
36import org.onosproject.net.DeviceId;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070037import org.onosproject.net.DisjointPath;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.Link;
39import org.onosproject.net.Path;
40import org.onosproject.net.provider.ProviderId;
41import org.onosproject.net.topology.ClusterId;
42import org.onosproject.net.topology.DefaultTopologyCluster;
43import org.onosproject.net.topology.DefaultTopologyVertex;
44import org.onosproject.net.topology.GraphDescription;
45import org.onosproject.net.topology.LinkWeight;
46import org.onosproject.net.topology.Topology;
47import org.onosproject.net.topology.TopologyCluster;
48import org.onosproject.net.topology.TopologyEdge;
49import org.onosproject.net.topology.TopologyGraph;
50import org.onosproject.net.topology.TopologyVertex;
alshabib339a3d92014-09-26 17:54:32 -070051
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070052import java.util.ArrayList;
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070053import java.util.HashMap;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070054import java.util.List;
55import java.util.Map;
56import java.util.Set;
alshabib339a3d92014-09-26 17:54:32 -070057
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070058import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070059import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070060import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070061import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070062import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
63import static org.onosproject.net.Link.State.ACTIVE;
64import static org.onosproject.net.Link.State.INACTIVE;
65import static org.onosproject.net.Link.Type.INDIRECT;
66
alshabib339a3d92014-09-26 17:54:32 -070067/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050068 * Default implementation of the topology descriptor. This carries the backing
69 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070070 */
71public class DefaultTopology extends AbstractModel implements Topology {
72
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050073 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
74 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -070075 private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE =
76 new SuurballeGraphSearch<>();
77
alshabib339a3d92014-09-26 17:54:32 -070078
alshabib339a3d92014-09-26 17:54:32 -070079 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050080 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080081 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070082 private final TopologyGraph graph;
83
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080084 private final LinkWeight weight;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080085 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080086 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
87 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
88 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070089 private final Function<ConnectPoint, Boolean> broadcastFunction;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080090 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070091
92 /**
93 * Creates a topology descriptor attributed to the specified provider.
94 *
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070095 * @param providerId identity of the provider
96 * @param description data describing the new topology
97 * @param broadcastFunction broadcast point function
alshabib339a3d92014-09-26 17:54:32 -070098 */
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070099 public DefaultTopology(ProviderId providerId, GraphDescription description,
100 Function<ConnectPoint, Boolean> broadcastFunction) {
alshabib339a3d92014-09-26 17:54:32 -0700101 super(providerId);
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700102 this.broadcastFunction = broadcastFunction;
alshabib339a3d92014-09-26 17:54:32 -0700103 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500104 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -0700105
106 // Build the graph
107 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700108 description.edges());
alshabib339a3d92014-09-26 17:54:32 -0700109
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800110 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
111 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700112
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800113 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
114
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800115 this.weight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800116 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700117 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800118 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700119 }
120
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700121 /**
122 * Creates a topology descriptor attributed to the specified provider.
123 *
124 * @param providerId identity of the provider
125 * @param description data describing the new topology
126 */
127 public DefaultTopology(ProviderId providerId, GraphDescription description) {
128 this(providerId, description, null);
129 }
130
alshabib339a3d92014-09-26 17:54:32 -0700131 @Override
132 public long time() {
133 return time;
134 }
135
136 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500137 public long creationTime() {
138 return creationTime;
139 }
140
141 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800142 public long computeCost() {
143 return computeCost;
144 }
145
146 @Override
alshabib339a3d92014-09-26 17:54:32 -0700147 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800148 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700149 }
150
151 @Override
152 public int deviceCount() {
153 return graph.getVertexes().size();
154 }
155
156 @Override
157 public int linkCount() {
158 return graph.getEdges().size();
159 }
160
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800161 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
162 return clusterIndexes.get().clustersByDevice;
163 }
164
165 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
166 return clusterIndexes.get().devicesByCluster;
167 }
168
169 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
170 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700171 }
172
173 /**
174 * Returns the backing topology graph.
175 *
176 * @return topology graph
177 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700178 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700179 return graph;
180 }
181
182 /**
183 * Returns the set of topology clusters.
184 *
185 * @return set of clusters
186 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700187 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800188 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700189 }
190
191 /**
192 * Returns the specified topology cluster.
193 *
194 * @param clusterId cluster identifier
195 * @return topology cluster
196 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700197 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800198 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700199 }
200
201 /**
202 * Returns the topology cluster that contains the given device.
203 *
204 * @param deviceId device identifier
205 * @return topology cluster
206 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700207 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800208 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700209 }
210
211 /**
212 * Returns the set of cluster devices.
213 *
214 * @param cluster topology cluster
215 * @return cluster devices
216 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700217 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800218 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700219 }
220
221 /**
222 * Returns the set of cluster links.
223 *
224 * @param cluster topology cluster
225 * @return cluster links
226 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700227 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800228 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700229 }
230
231 /**
232 * Indicates whether the given point is an infrastructure link end-point.
233 *
234 * @param connectPoint connection point
235 * @return true if infrastructure
236 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700237 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800238 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700239 }
240
241 /**
242 * Indicates whether the given point is part of a broadcast set.
243 *
244 * @param connectPoint connection point
245 * @return true if in broadcast set
246 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700247 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700248 if (broadcastFunction != null) {
249 return broadcastFunction.apply(connectPoint);
250 }
251
alshabib339a3d92014-09-26 17:54:32 -0700252 // Any non-infrastructure, i.e. edge points are assumed to be OK.
253 if (!isInfrastructure(connectPoint)) {
254 return true;
255 }
256
257 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800258 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700259 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700260
261 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700262 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800263 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700264 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700265 }
266
267 /**
268 * Returns the size of the cluster broadcast set.
269 *
270 * @param clusterId cluster identifier
271 * @return size of the cluster broadcast set
272 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700273 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800274 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700275 }
276
277 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700278 * Returns the set of the cluster broadcast points.
279 *
280 * @param clusterId cluster identifier
281 * @return set of cluster broadcast points
282 */
283 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
284 return broadcastSets.get().get(clusterId);
285 }
286
287 /**
alshabib339a3d92014-09-26 17:54:32 -0700288 * Returns the set of pre-computed shortest paths between source and
289 * destination devices.
290 *
291 * @param src source device
292 * @param dst destination device
293 * @return set of shortest paths
294 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700295 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800296 return getPaths(src, dst, null);
alshabib339a3d92014-09-26 17:54:32 -0700297 }
298
299 /**
300 * Computes on-demand the set of shortest paths between source and
301 * destination devices.
302 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700303 * @param src source device
304 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800305 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700306 * @return set of shortest paths
307 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700308 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800309 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
310 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
311 Set<TopologyVertex> vertices = graph.getVertexes();
312 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
313 // src or dst not part of the current graph
314 return ImmutableSet.of();
315 }
316
alshabib339a3d92014-09-26 17:54:32 -0700317 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800318 DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700319 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
320 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
321 builder.add(networkPath(path));
322 }
323 return builder.build();
324 }
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700325
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700326 /**
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700327 * /**
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700328 * Returns the set of pre-computed shortest disjoint path pairs between source and
329 * destination devices.
330 *
331 * @param src source device
332 * @param dst destination device
333 * @return set of shortest disjoint path pairs
334 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700335 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700336 return getDisjointPaths(src, dst, null);
337 }
338
339 /**
340 * Computes on-demand the set of shortest disjoint path pairs between source and
341 * destination devices.
342 *
343 * @param src source device
344 * @param dst destination device
345 * @param weight link weight function
346 * @return set of disjoint shortest path pairs
347 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700348 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700349 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
350 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
351 Set<TopologyVertex> vertices = graph.getVertexes();
352 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
353 // src or dst not part of the current graph
354 return ImmutableSet.of();
355 }
356
357 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
358 SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS);
359 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
360 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
361 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
362 }
363 return builder.build();
364 }
365
366 /**
367 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
368 * destination devices.
369 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700370 * @param src source device
371 * @param dst destination device
372 * @param riskProfile map representing risk groups for each edge
373 * @return set of shortest disjoint paths
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700374 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700375 public Set<DisjointPath> getSRLGDisjointPathsD(DeviceId src, DeviceId dst, Map<TopologyEdge, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700376 return getSRLGDisjointPathsD(src, dst, null, riskProfile);
377 }
378
379 /**
380 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
381 * destination devices.
382 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700383 * @param src source device
384 * @param dst destination device
385 * @param weight edge weight object
386 * @param riskProfile map representing risk groups for each edge
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700387 * @return set of shortest disjoint paths
388 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700389 public Set<DisjointPath> getSRLGDisjointPathsD(DeviceId src, DeviceId dst, LinkWeight weight, Map<TopologyEdge,
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700390 Object> riskProfile) {
391 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
392 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
393 Set<TopologyVertex> vertices = graph.getVertexes();
394 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
395 // src or dst not part of the current graph
396 return ImmutableSet.of();
397 }
398
399 SRLGGraphSearch<TopologyVertex, TopologyEdge> srlg = new SRLGGraphSearch<>(riskProfile);
400 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
401 srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
402 ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
403 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
404 builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
405 }
406 return builder.build();
407 }
408
409 /**
410 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
411 * destination devices.
412 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700413 * @param src source device
414 * @param dst destination device
415 * @param weight edge weight object
416 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700417 * @return set of shortest disjoint paths
418 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700419 public Set<DisjointPath> getSRLGDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
420 Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700421 Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
422 for (Link l : riskProfile.keySet()) {
423 riskProfile2.put(new TopologyEdge() {
424 final Link cur = l;
425
426 public Link link() {
427 return cur;
428 }
429
430 public TopologyVertex src() {
431 return new TopologyVertex() {
432 public DeviceId deviceId() {
433 return src;
434 }
435 };
436 }
437
438 public TopologyVertex dst() {
439 return new TopologyVertex() {
440 public DeviceId deviceId() {
441 return dst;
442 }
443 };
444 }
445 }, riskProfile.get(l));
446 }
447 return getSRLGDisjointPathsD(src, dst, weight, riskProfile2);
448 }
449
450 /**
451 * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
452 * destination devices.
453 *
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700454 * @param src source device
455 * @param dst destination device
456 * @param riskProfile map representing risk groups for each link
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700457 * @return set of shortest disjoint paths
458 */
Nikhil Cheerla2ec191f2015-07-09 12:34:54 -0700459 public Set<DisjointPath> getSRLGDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700460 return getSRLGDisjointPaths(src, dst, null, riskProfile);
461 }
alshabib339a3d92014-09-26 17:54:32 -0700462
alshabib339a3d92014-09-26 17:54:32 -0700463 // Converts graph path to a network path with the same cost.
464 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
465 List<Link> links = new ArrayList<>();
466 for (TopologyEdge edge : path.edges()) {
467 links.add(edge.link());
468 }
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800469 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700470 }
471
Nikhil Cheerla1cf0f9a2015-07-09 12:26:48 -0700472 private DisjointPath networkDisjointPath(org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge> path) {
473 return new DefaultDisjointPath(CORE_PROVIDER_ID,
474 (DefaultPath) networkPath(path.path1), (DefaultPath) networkPath(path.path2));
475 }
476
alshabib339a3d92014-09-26 17:54:32 -0700477 // Searches for SCC clusters in the network topology graph using Tarjan
478 // algorithm.
479 private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
480 return TARJAN.search(graph, new NoIndirectLinksWeight());
481 }
482
483 // Builds the topology clusters and returns the id-cluster bindings.
484 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
485 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800486 SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
alshabib339a3d92014-09-26 17:54:32 -0700487 // Extract both vertexes and edges from the results; the lists form
488 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800489 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
490 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700491
492 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800493 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700494 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
495 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
496
497 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500498 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
499 vertexSet.size(),
500 edgeSet.size(),
501 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700502 clusterBuilder.put(cid, cluster);
503 }
504 return clusterBuilder.build();
505 }
506
507 // Finds the vertex whose device id is the lexicographical minimum in the
508 // specified set.
509 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
510 TopologyVertex minVertex = null;
511 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500512 if ((minVertex == null) || (minVertex.deviceId()
513 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700514 minVertex = vertex;
515 }
516 }
517 return minVertex;
518 }
519
520 // Processes a map of broadcast sets for each cluster.
521 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500522 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap
523 .builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800524 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700525 addClusterBroadcastSet(cluster, builder);
526 }
527 return builder.build();
528 }
529
530 // Finds all broadcast points for the cluster. These are those connection
531 // points which lie along the shortest paths between the cluster root and
532 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500533 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700534 // Use the graph root search results to build the broadcast set.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500535 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700536 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
537 TopologyVertex vertex = entry.getKey();
538
539 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800540 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700541 continue;
542 }
543
544 // Ignore any back-link sets that are empty.
545 Set<TopologyEdge> parents = entry.getValue();
546 if (parents.isEmpty()) {
547 continue;
548 }
549
550 // Use the first back-link source and destinations to add to the
551 // broadcast set.
552 Link link = parents.iterator().next().link();
553 builder.put(cluster.id(), link.src());
554 builder.put(cluster.id(), link.dst());
555 }
556 }
557
558 // Collects and returns an set of all infrastructure link end-points.
559 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
560 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
561 for (TopologyEdge edge : graph.getEdges()) {
562 builder.add(edge.link().src());
563 builder.add(edge.link().dst());
564 }
565 return builder.build();
566 }
567
568 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800569 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700570 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500571 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
572 ImmutableMap.builder();
573 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
574 ImmutableSetMultimap.builder();
575 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
576 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700577
578 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800579 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700580 int i = cluster.id().index();
581
582 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800583 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700584 devicesBuilder.put(cluster, vertex.deviceId());
585 clusterBuilder.put(vertex.deviceId(), cluster);
586 }
587
588 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800589 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700590 linksBuilder.put(cluster, edge.link());
591 }
592 }
593
594 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800595 return new ClusterIndexes(clusterBuilder.build(),
596 devicesBuilder.build(),
597 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700598 }
599
600 // Link weight for measuring link cost as hop count with indirect links
601 // being as expensive as traversing the entire graph to assume the worst.
602 private static class HopCountLinkWeight implements LinkWeight {
603 private final int indirectLinkCost;
604
605 HopCountLinkWeight(int indirectLinkCost) {
606 this.indirectLinkCost = indirectLinkCost;
607 }
608
609 @Override
610 public double weight(TopologyEdge edge) {
611 // To force preference to use direct paths first, make indirect
612 // links as expensive as the linear vertex traversal.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500613 return edge.link().state() ==
614 ACTIVE ? (edge.link().type() ==
615 INDIRECT ? indirectLinkCost : 1) : -1;
alshabib339a3d92014-09-26 17:54:32 -0700616 }
617 }
618
619 // Link weight for preventing traversal over indirect links.
620 private static class NoIndirectLinksWeight implements LinkWeight {
621 @Override
622 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500623 return (edge.link().state() == INACTIVE)
624 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700625 }
626 }
627
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800628 static final class ClusterIndexes {
629 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
630 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
631 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
632
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700633 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
634 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
635 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800636 this.clustersByDevice = clustersByDevice;
637 this.devicesByCluster = devicesByCluster;
638 this.linksByCluster = linksByCluster;
639 }
640 }
641
alshabib339a3d92014-09-26 17:54:32 -0700642 @Override
643 public String toString() {
644 return toStringHelper(this)
645 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500646 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800647 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700648 .add("clusters", clusterCount())
649 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500650 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700651 }
652}