blob: 35b9fcec05c8fbb3d8e48b005d8322415017398e [file] [log] [blame]
Claudine Chiu45920dd2016-07-28 19:19:46 +00001/*
Brian O'Connord03d7dd2016-08-02 23:33:25 -07002 * Copyright 2016-present Open Networking Laboratory
Claudine Chiu45920dd2016-07-28 19:19:46 +00003 *
Brian O'Connord03d7dd2016-08-02 23:33:25 -07004 * 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
Claudine Chiu45920dd2016-07-28 19:19:46 +00007 *
Brian O'Connord03d7dd2016-08-02 23:33:25 -07008 * 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.
Claudine Chiu45920dd2016-07-28 19:19:46 +000015 */
Claudine Chiu45920dd2016-07-28 19:19:46 +000016package org.onosproject.net.topology;
17
18import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Lists;
20import com.google.common.collect.Sets;
Andrey Komarov2398d962016-09-26 15:11:23 +030021import org.onlab.graph.Weight;
Claudine Chiu45920dd2016-07-28 19:19:46 +000022import org.onosproject.net.ConnectPoint;
23import org.onosproject.net.DefaultDisjointPath;
24import org.onosproject.net.DefaultEdgeLink;
25import org.onosproject.net.DefaultPath;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.DisjointPath;
28import org.onosproject.net.EdgeLink;
29import org.onosproject.net.ElementId;
30import org.onosproject.net.Host;
31import org.onosproject.net.HostId;
32import org.onosproject.net.HostLocation;
33import org.onosproject.net.Link;
34import org.onosproject.net.Path;
35import org.onosproject.net.PortNumber;
36import org.onosproject.net.host.HostService;
37import org.onosproject.net.provider.ProviderId;
38
39import java.util.List;
40import java.util.Map;
41import java.util.Set;
Yuta HIGUCHIa684b6e2017-05-18 22:29:22 -070042import java.util.stream.Stream;
Claudine Chiu45920dd2016-07-28 19:19:46 +000043
44import static com.google.common.base.Preconditions.checkNotNull;
Andrey Komarov2398d962016-09-26 15:11:23 +030045import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
Claudine Chiu45920dd2016-07-28 19:19:46 +000046
47/**
48 * Helper class for path service.
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070049 * <p>
50 * Class inheriting this must manually initialize {@code topologyService}
51 * and {@code hostService} fields.
Claudine Chiu45920dd2016-07-28 19:19:46 +000052 */
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070053public abstract class AbstractPathService
54 implements PathService {
Claudine Chiu45920dd2016-07-28 19:19:46 +000055
56 private static final String ELEMENT_ID_NULL = "Element ID cannot be null";
57 private static final EdgeLink NOT_HOST = new NotHost();
58
59 private static final ProviderId PID = new ProviderId("core", "org.onosproject.core");
60 private static final PortNumber P0 = PortNumber.portNumber(0);
61
Andrey Komarov2398d962016-09-26 15:11:23 +030062 protected static final LinkWeigher DEFAULT_WEIGHER =
63 adapt(new HopCountLinkWeight());
64
Claudine Chiu45920dd2016-07-28 19:19:46 +000065 protected TopologyService topologyService;
66
Claudine Chiu45920dd2016-07-28 19:19:46 +000067 protected HostService hostService;
68
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070069 @Override
Claudine Chiu45920dd2016-07-28 19:19:46 +000070 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
Andrey Komarov2398d962016-09-26 15:11:23 +030071 return getPaths(src, dst, adapt(weight));
72 }
73
74 @Override
75 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +000076 checkNotNull(src, ELEMENT_ID_NULL);
77 checkNotNull(dst, ELEMENT_ID_NULL);
78
Andrey Komarov2398d962016-09-26 15:11:23 +030079 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
80
Claudine Chiu45920dd2016-07-28 19:19:46 +000081 // Get the source and destination edge locations
82 EdgeLink srcEdge = getEdgeLink(src, true);
83 EdgeLink dstEdge = getEdgeLink(dst, false);
84
85 // If either edge is null, bail with no paths.
86 if (srcEdge == null || dstEdge == null) {
87 return ImmutableSet.of();
88 }
89
90 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
91 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
92
93 // If the source and destination are on the same edge device, there
94 // is just one path, so build it and return it.
95 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +030096 return edgeToEdgePaths(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +000097 }
98
99 // Otherwise get all paths between the source and destination edge
100 // devices.
101 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300102 Set<Path> paths = topologyService.getPaths(topology, srcDevice,
103 dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000104
Andrey Komarov2398d962016-09-26 15:11:23 +0300105 return edgeToEdgePaths(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000106 }
107
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700108 @Override
Yuta HIGUCHIa684b6e2017-05-18 22:29:22 -0700109 public Stream<Path> getKShortestPaths(ElementId src, ElementId dst,
110 LinkWeigher weigher) {
111 checkNotNull(src, ELEMENT_ID_NULL);
112 checkNotNull(dst, ELEMENT_ID_NULL);
113
114 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
115
116 // Get the source and destination edge locations
117 EdgeLink srcEdge = getEdgeLink(src, true);
118 EdgeLink dstEdge = getEdgeLink(dst, false);
119
120 // If either edge is null, bail with no paths.
121 if (srcEdge == null || dstEdge == null) {
122 return Stream.empty();
123 }
124
125 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
126 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
127
128 // If the source and destination are on the same edge device, there
129 // is just one path, so build it and return it.
130 if (srcDevice.equals(dstDevice)) {
131 return Stream.of(edgeToEdgePath(srcEdge, dstEdge, null, internalWeigher));
132 }
133
134 // Otherwise get all paths between the source and destination edge
135 // devices.
136 Topology topology = topologyService.currentTopology();
137
138 return topologyService.getKShortestPaths(topology, srcDevice, dstDevice, internalWeigher)
139 .map(path -> edgeToEdgePath(srcEdge, dstEdge, path, internalWeigher));
140 }
141
142 @Override
Claudine Chiu45920dd2016-07-28 19:19:46 +0000143 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300144 return getDisjointPaths(src, dst, adapt(weight));
145 }
146
147 @Override
148 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000149 checkNotNull(src, ELEMENT_ID_NULL);
150 checkNotNull(dst, ELEMENT_ID_NULL);
151
Andrey Komarov2398d962016-09-26 15:11:23 +0300152 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
153
Claudine Chiu45920dd2016-07-28 19:19:46 +0000154 // Get the source and destination edge locations
155 EdgeLink srcEdge = getEdgeLink(src, true);
156 EdgeLink dstEdge = getEdgeLink(dst, false);
157
158 // If either edge is null, bail with no paths.
159 if (srcEdge == null || dstEdge == null) {
160 return ImmutableSet.of();
161 }
162
163 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
164 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
165
166 // If the source and destination are on the same edge device, there
167 // is just one path, so build it and return it.
168 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300169 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000170 }
171
172 // Otherwise get all paths between the source and destination edge
173 // devices.
174 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300175 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
176 srcDevice, dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000177
Andrey Komarov2398d962016-09-26 15:11:23 +0300178 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000179 }
180
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700181 @Override
Claudine Chiu45920dd2016-07-28 19:19:46 +0000182 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
183 Map<Link, Object> riskProfile) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300184 return getDisjointPaths(src, dst, adapt(weight), riskProfile);
185 }
186
187 @Override
188 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
189 LinkWeigher weigher, Map<Link, Object> riskProfile) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000190 checkNotNull(src, ELEMENT_ID_NULL);
191 checkNotNull(dst, ELEMENT_ID_NULL);
192
Andrey Komarov2398d962016-09-26 15:11:23 +0300193 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
194
Claudine Chiu45920dd2016-07-28 19:19:46 +0000195 // Get the source and destination edge locations
196 EdgeLink srcEdge = getEdgeLink(src, true);
197 EdgeLink dstEdge = getEdgeLink(dst, false);
198
199 // If either edge is null, bail with no paths.
200 if (srcEdge == null || dstEdge == null) {
201 return ImmutableSet.of();
202 }
203
204 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
205 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
206
207 // If the source and destination are on the same edge device, there
208 // is just one path, so build it and return it.
209 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300210 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000211 }
212
213 // Otherwise get all paths between the source and destination edge
214 // devices.
215 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300216 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
217 srcDevice, dstDevice, internalWeigher, riskProfile);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000218
Andrey Komarov2398d962016-09-26 15:11:23 +0300219 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000220 }
221
222 // Finds the host edge link if the element ID is a host id of an existing
223 // host. Otherwise, if the host does not exist, it returns null and if
224 // the element ID is not a host ID, returns NOT_HOST edge link.
225 private EdgeLink getEdgeLink(ElementId elementId, boolean isIngress) {
226 if (elementId instanceof HostId) {
227 // Resolve the host, return null.
228 Host host = hostService.getHost((HostId) elementId);
229 if (host == null) {
230 return null;
231 }
232 return new DefaultEdgeLink(PID, new ConnectPoint(elementId, P0),
233 host.location(), isIngress);
234 }
235 return NOT_HOST;
236 }
237
238 // Produces a set of edge-to-edge paths using the set of infrastructure
239 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300240 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000241 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300242 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000243 return endToEndPaths;
244 }
245
246 // Produces a set of edge-to-edge paths using the set of infrastructure
247 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300248 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, Set<Path> paths,
249 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000250 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
251 for (Path path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300252 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000253 }
254 return endToEndPaths;
255 }
256
Andrey Komarov2398d962016-09-26 15:11:23 +0300257 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000258 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300259 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000260 return endToEndPaths;
261 }
262
263 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink,
Andrey Komarov2398d962016-09-26 15:11:23 +0300264 Set<DisjointPath> paths, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000265 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
266 for (DisjointPath path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300267 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000268 }
269 return endToEndPaths;
270 }
271
272 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300273 private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000274 List<Link> links = Lists.newArrayListWithCapacity(2);
Andrey Komarov2398d962016-09-26 15:11:23 +0300275 Weight cost = weigher.getInitialWeight();
Claudine Chiu45920dd2016-07-28 19:19:46 +0000276
277 // Add source and destination edge links only if they are real and
278 // add the infrastructure path only if it is not null.
279 if (srcLink != NOT_HOST) {
280 links.add(srcLink);
Andrey Komarov2398d962016-09-26 15:11:23 +0300281 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, srcLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000282 }
283 if (path != null) {
284 links.addAll(path.links());
Andrey Komarov2398d962016-09-26 15:11:23 +0300285 cost = cost.merge(path.weight());
Claudine Chiu45920dd2016-07-28 19:19:46 +0000286 }
287 if (dstLink != NOT_HOST) {
288 links.add(dstLink);
Andrey Komarov2398d962016-09-26 15:11:23 +0300289 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, srcLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000290 }
291 return new DefaultPath(PID, links, cost);
292 }
293
294 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300295 private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path,
296 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000297 Path primary = null;
298 Path backup = null;
299 if (path != null) {
300 primary = path.primary();
301 backup = path.backup();
302 }
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530303 if (backup == null) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300304 return new DefaultDisjointPath(PID,
305 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher));
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530306 }
Andrey Komarov2398d962016-09-26 15:11:23 +0300307 return new DefaultDisjointPath(PID,
308 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher),
309 (DefaultPath) edgeToEdgePath(srcLink, dstLink, backup, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000310 }
311
312
313 // Special value for edge link to represent that this is really not an
314 // edge link since the src or dst are really an infrastructure device.
315 private static class NotHost extends DefaultEdgeLink implements EdgeLink {
316 NotHost() {
317 super(PID, new ConnectPoint(HostId.NONE, P0),
318 new HostLocation(DeviceId.NONE, P0, 0L), false);
319 }
320 }
321}