blob: c438146daa52da49d049142dfa8875c1bc71bb57 [file] [log] [blame]
tomcfde0622014-09-09 11:02:42 -07001package org.onlab.onos.net.trivial.impl;
2
3import com.google.common.collect.ImmutableSet;
tomcbff9392014-09-10 00:45:23 -07004import com.google.common.collect.Maps;
5import com.google.common.collect.Sets;
6import org.onlab.graph.AdjacencyListsGraph;
7import org.onlab.graph.DijkstraGraphSearch;
tomcfde0622014-09-09 11:02:42 -07008import org.onlab.graph.Graph;
9import org.onlab.graph.GraphPathSearch;
tomcbff9392014-09-10 00:45:23 -070010import org.onlab.onos.net.ConnectPoint;
11import org.onlab.onos.net.Device;
tomcfde0622014-09-09 11:02:42 -070012import org.onlab.onos.net.DeviceId;
13import org.onlab.onos.net.Link;
14import org.onlab.onos.net.topology.ClusterId;
tomcbff9392014-09-10 00:45:23 -070015import org.onlab.onos.net.topology.LinkWeight;
tomcfde0622014-09-09 11:02:42 -070016import org.onlab.onos.net.topology.TopoEdge;
17import org.onlab.onos.net.topology.TopoVertex;
18import org.onlab.onos.net.topology.TopologyCluster;
19import org.onlab.onos.net.topology.TopologyDescription;
20
21import java.util.Map;
tomcbff9392014-09-10 00:45:23 -070022import java.util.Objects;
tomcfde0622014-09-09 11:02:42 -070023import java.util.Set;
24
tomcbff9392014-09-10 00:45:23 -070025import static com.google.common.base.MoreObjects.toStringHelper;
26import static org.onlab.graph.GraphPathSearch.Result;
27import static org.onlab.onos.net.Link.Type.INDIRECT;
28
tomcfde0622014-09-09 11:02:42 -070029/**
30 * Default implementation of an immutable topology data carrier.
31 */
tomcbff9392014-09-10 00:45:23 -070032class DefaultTopologyDescription implements TopologyDescription {
33
34 private static final GraphPathSearch<TopoVertex, TopoEdge> DIJKSTRA =
35 new DijkstraGraphSearch<>();
tomcfde0622014-09-09 11:02:42 -070036
37 private final long nanos;
tomcbff9392014-09-10 00:45:23 -070038 private final Map<DeviceId, TopoVertex> vertexesById = Maps.newHashMap();
tomcfde0622014-09-09 11:02:42 -070039 private final Graph<TopoVertex, TopoEdge> graph;
tomcbff9392014-09-10 00:45:23 -070040 private final Map<DeviceId, Result<TopoVertex, TopoEdge>> results;
tomcfde0622014-09-09 11:02:42 -070041 private final Map<ClusterId, TopologyCluster> clusters;
tomcbff9392014-09-10 00:45:23 -070042// private final Multimap<ClusterId, DeviceId> clusterDevices;
43// private final Multimap<ClusterId, Link> clusterLinks;
44// private final Map<DeviceId, TopologyCluster> deviceClusters;
tomcfde0622014-09-09 11:02:42 -070045
tomcbff9392014-09-10 00:45:23 -070046
47 DefaultTopologyDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
tomcfde0622014-09-09 11:02:42 -070048 this.nanos = nanos;
tomcbff9392014-09-10 00:45:23 -070049 this.graph = buildGraph(devices, links);
50 this.results = computeDefaultPaths();
51 this.clusters = computeClusters();
52// this.clusterDevices = clusterDevices;
53// this.clusterLinks = clusterLinks;
54// this.deviceClusters = deviceClusters;
55 }
56
57 // Constructs the topology graph using the supplied devices and links.
58 private Graph<TopoVertex, TopoEdge> buildGraph(Iterable<Device> devices,
59 Iterable<Link> links) {
60 Graph<TopoVertex, TopoEdge> graph =
61 new AdjacencyListsGraph<>(buildVertexes(devices),
62 buildEdges(links));
63 return graph;
64 }
65
66 // Builds a set of topology vertexes from the specified list of devices
67 private Set<TopoVertex> buildVertexes(Iterable<Device> devices) {
68 Set<TopoVertex> vertexes = Sets.newHashSet();
69 for (Device device : devices) {
70 TopoVertex vertex = new TVertex(device.id());
71 vertexesById.put(vertex.deviceId(), vertex);
72 vertexes.add(vertex);
73 }
74 return vertexes;
75 }
76
77 // Builds a set of topology vertexes from the specified list of links
78 private Set<TopoEdge> buildEdges(Iterable<Link> links) {
79 Set<TopoEdge> edges = Sets.newHashSet();
80 for (Link link : links) {
81 edges.add(new TEdge(vertexOf(link.src()), vertexOf(link.dst()), link));
82 }
83 return edges;
84 }
85
86 // Computes the default shortest paths for all source/dest pairs using
87 // the multi-path Dijkstra and hop-count as path cost.
88 private Map<DeviceId, Result<TopoVertex, TopoEdge>> computeDefaultPaths() {
89 LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
90 Map<DeviceId, Result<TopoVertex, TopoEdge>> results = Maps.newHashMap();
91
92 // Search graph paths for each source to all destinations.
93 for (TopoVertex src : vertexesById.values()) {
94 results.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
95 }
96 return results;
97 }
98
99 // Computes topology SCC clusters using Tarjan algorithm.
100 private Map<ClusterId, TopologyCluster> computeClusters() {
101 Map<ClusterId, TopologyCluster> clusters = Maps.newHashMap();
102 return clusters;
103 }
104
105 // Fetches a vertex corresponding to the given connection point device.
106 private TopoVertex vertexOf(ConnectPoint connectPoint) {
107 DeviceId id = connectPoint.deviceId();
108 TopoVertex vertex = vertexesById.get(id);
109 if (vertex == null) {
110 // If vertex does not exist, create one and register it.
111 vertex = new TVertex(id);
112 vertexesById.put(id, vertex);
113 }
114 return vertex;
tomcfde0622014-09-09 11:02:42 -0700115 }
116
117 @Override
118 public long timestamp() {
119 return nanos;
120 }
121
122 @Override
123 public Graph<TopoVertex, TopoEdge> graph() {
124 return graph;
125 }
126
127 @Override
tomcbff9392014-09-10 00:45:23 -0700128 public Result<TopoVertex, TopoEdge> pathResults(DeviceId srcDeviceId) {
tomcfde0622014-09-09 11:02:42 -0700129 return results.get(srcDeviceId);
130 }
131
132 @Override
133 public Set<TopologyCluster> clusters() {
134 return ImmutableSet.copyOf(clusters.values());
135 }
136
137 @Override
138 public Set<DeviceId> clusterDevices(TopologyCluster cluster) {
139 return null; // clusterDevices.get(cluster.id());
140 }
141
142 @Override
143 public Set<Link> clusterLinks(TopologyCluster cluster) {
144 return null; // clusterLinks.get(cluster.id());
145 }
146
147 @Override
148 public TopologyCluster clusterFor(DeviceId deviceId) {
tomcbff9392014-09-10 00:45:23 -0700149 return null; // deviceClusters.get(deviceId);
tomcfde0622014-09-09 11:02:42 -0700150 }
tomcbff9392014-09-10 00:45:23 -0700151
152 // Implementation of the topology vertex backed by a device id
153 private static class TVertex implements TopoVertex {
154
155 private final DeviceId deviceId;
156
157 public TVertex(DeviceId deviceId) {
158 this.deviceId = deviceId;
159 }
160
161 @Override
162 public DeviceId deviceId() {
163 return deviceId;
164 }
165
166 @Override
167 public int hashCode() {
168 return Objects.hash(deviceId);
169 }
170
171 @Override
172 public boolean equals(Object obj) {
173 if (obj instanceof TVertex) {
174 final TVertex other = (TVertex) obj;
175 return Objects.equals(this.deviceId, other.deviceId);
176 }
177 return false;
178 }
179
180 @Override
181 public String toString() {
182 return deviceId.toString();
183 }
184 }
185
186 // Implementation of the topology edge backed by a link
187 private class TEdge implements TopoEdge {
188 private final Link link;
189 private final TopoVertex src;
190 private final TopoVertex dst;
191
192 public TEdge(TopoVertex src, TopoVertex dst, Link link) {
193 this.src = src;
194 this.dst = dst;
195 this.link = link;
196 }
197
198 @Override
199 public Link link() {
200 return link;
201 }
202
203 @Override
204 public TopoVertex src() {
205 return src;
206 }
207
208 @Override
209 public TopoVertex dst() {
210 return dst;
211 }
212
213 @Override
214 public int hashCode() {
215 return Objects.hash(link);
216 }
217
218 @Override
219 public boolean equals(Object obj) {
220 if (obj instanceof TEdge) {
221 final TEdge other = (TEdge) obj;
222 return Objects.equals(this.link, other.link);
223 }
224 return false;
225 }
226
227 @Override
228 public String toString() {
229 return toStringHelper(this).add("src", src).add("dst", dst).toString();
230 }
231 }
232
233 // Link weight for measuring link cost as hop count with indirect links
234 // being as expensive as traversing the entire graph to assume the worst.
235 private class HopCountLinkWeight implements LinkWeight {
236 private final int indirectLinkCost;
237
238 public HopCountLinkWeight(int indirectLinkCost) {
239 this.indirectLinkCost = indirectLinkCost;
240 }
241
242 @Override
243 public double weight(TopoEdge edge) {
244 // To force preference to use direct paths first, make indirect
245 // links as expensive as the linear vertex traversal.
246 return edge.link().type() == INDIRECT ? indirectLinkCost : 1;
247 }
248 }
249
tomcfde0622014-09-09 11:02:42 -0700250}