blob: cf9a5315a8135c073f28d052304d6cfdeabbf934 [file] [log] [blame]
Claudine Chiu45920dd2016-07-28 19:19:46 +00001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
45
46/**
47 * Helper class for path service.
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070048 * <p>
49 * Class inheriting this must manually initialize {@code topologyService}
50 * and {@code hostService} fields.
Claudine Chiu45920dd2016-07-28 19:19:46 +000051 */
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070052public abstract class AbstractPathService
53 implements PathService {
Claudine Chiu45920dd2016-07-28 19:19:46 +000054
55 private static final String ELEMENT_ID_NULL = "Element ID cannot be null";
56 private static final EdgeLink NOT_HOST = new NotHost();
57
58 private static final ProviderId PID = new ProviderId("core", "org.onosproject.core");
59 private static final PortNumber P0 = PortNumber.portNumber(0);
60
Andrey Komarov2398d962016-09-26 15:11:23 +030061 protected static final LinkWeigher DEFAULT_WEIGHER =
Ray Milkey7483e1b2018-02-07 15:43:01 -080062 new HopCountLinkWeigher();
Andrey Komarov2398d962016-09-26 15:11:23 +030063
Claudine Chiu45920dd2016-07-28 19:19:46 +000064 protected TopologyService topologyService;
65
Claudine Chiu45920dd2016-07-28 19:19:46 +000066 protected HostService hostService;
67
Yuta HIGUCHI90e12292016-08-02 18:02:53 -070068 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +030069 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +000070 checkNotNull(src, ELEMENT_ID_NULL);
71 checkNotNull(dst, ELEMENT_ID_NULL);
72
Andrey Komarov2398d962016-09-26 15:11:23 +030073 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
74
Claudine Chiu45920dd2016-07-28 19:19:46 +000075 // Get the source and destination edge locations
76 EdgeLink srcEdge = getEdgeLink(src, true);
77 EdgeLink dstEdge = getEdgeLink(dst, false);
78
79 // If either edge is null, bail with no paths.
80 if (srcEdge == null || dstEdge == null) {
81 return ImmutableSet.of();
82 }
83
84 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
85 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
86
87 // If the source and destination are on the same edge device, there
88 // is just one path, so build it and return it.
89 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +030090 return edgeToEdgePaths(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +000091 }
92
93 // Otherwise get all paths between the source and destination edge
94 // devices.
95 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +030096 Set<Path> paths = topologyService.getPaths(topology, srcDevice,
97 dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +000098
Andrey Komarov2398d962016-09-26 15:11:23 +030099 return edgeToEdgePaths(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000100 }
101
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700102 @Override
Yuta HIGUCHIa684b6e2017-05-18 22:29:22 -0700103 public Stream<Path> getKShortestPaths(ElementId src, ElementId dst,
104 LinkWeigher weigher) {
105 checkNotNull(src, ELEMENT_ID_NULL);
106 checkNotNull(dst, ELEMENT_ID_NULL);
107
108 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
109
110 // Get the source and destination edge locations
111 EdgeLink srcEdge = getEdgeLink(src, true);
112 EdgeLink dstEdge = getEdgeLink(dst, false);
113
114 // If either edge is null, bail with no paths.
115 if (srcEdge == null || dstEdge == null) {
116 return Stream.empty();
117 }
118
119 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
120 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
121
122 // If the source and destination are on the same edge device, there
123 // is just one path, so build it and return it.
124 if (srcDevice.equals(dstDevice)) {
125 return Stream.of(edgeToEdgePath(srcEdge, dstEdge, null, internalWeigher));
126 }
127
128 // Otherwise get all paths between the source and destination edge
129 // devices.
130 Topology topology = topologyService.currentTopology();
131
132 return topologyService.getKShortestPaths(topology, srcDevice, dstDevice, internalWeigher)
133 .map(path -> edgeToEdgePath(srcEdge, dstEdge, path, internalWeigher));
134 }
135
136 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300137 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000138 checkNotNull(src, ELEMENT_ID_NULL);
139 checkNotNull(dst, ELEMENT_ID_NULL);
140
Andrey Komarov2398d962016-09-26 15:11:23 +0300141 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
142
Claudine Chiu45920dd2016-07-28 19:19:46 +0000143 // Get the source and destination edge locations
144 EdgeLink srcEdge = getEdgeLink(src, true);
145 EdgeLink dstEdge = getEdgeLink(dst, false);
146
147 // If either edge is null, bail with no paths.
148 if (srcEdge == null || dstEdge == null) {
149 return ImmutableSet.of();
150 }
151
152 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
153 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
154
155 // If the source and destination are on the same edge device, there
156 // is just one path, so build it and return it.
157 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300158 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000159 }
160
161 // Otherwise get all paths between the source and destination edge
162 // devices.
163 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300164 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
165 srcDevice, dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000166
Andrey Komarov2398d962016-09-26 15:11:23 +0300167 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000168 }
169
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700170 @Override
Andrey Komarov2398d962016-09-26 15:11:23 +0300171 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
172 LinkWeigher weigher, Map<Link, Object> riskProfile) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000173 checkNotNull(src, ELEMENT_ID_NULL);
174 checkNotNull(dst, ELEMENT_ID_NULL);
175
Andrey Komarov2398d962016-09-26 15:11:23 +0300176 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
177
Claudine Chiu45920dd2016-07-28 19:19:46 +0000178 // Get the source and destination edge locations
179 EdgeLink srcEdge = getEdgeLink(src, true);
180 EdgeLink dstEdge = getEdgeLink(dst, false);
181
182 // If either edge is null, bail with no paths.
183 if (srcEdge == null || dstEdge == null) {
184 return ImmutableSet.of();
185 }
186
187 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
188 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
189
190 // If the source and destination are on the same edge device, there
191 // is just one path, so build it and return it.
192 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300193 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000194 }
195
196 // Otherwise get all paths between the source and destination edge
197 // devices.
198 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300199 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
200 srcDevice, dstDevice, internalWeigher, riskProfile);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000201
Andrey Komarov2398d962016-09-26 15:11:23 +0300202 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000203 }
204
205 // Finds the host edge link if the element ID is a host id of an existing
206 // host. Otherwise, if the host does not exist, it returns null and if
207 // the element ID is not a host ID, returns NOT_HOST edge link.
208 private EdgeLink getEdgeLink(ElementId elementId, boolean isIngress) {
209 if (elementId instanceof HostId) {
210 // Resolve the host, return null.
211 Host host = hostService.getHost((HostId) elementId);
212 if (host == null) {
213 return null;
214 }
215 return new DefaultEdgeLink(PID, new ConnectPoint(elementId, P0),
216 host.location(), isIngress);
217 }
218 return NOT_HOST;
219 }
220
221 // Produces a set of edge-to-edge paths using the set of infrastructure
222 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300223 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000224 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300225 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000226 return endToEndPaths;
227 }
228
229 // Produces a set of edge-to-edge paths using the set of infrastructure
230 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300231 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, Set<Path> paths,
232 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000233 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
234 for (Path path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300235 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000236 }
237 return endToEndPaths;
238 }
239
Andrey Komarov2398d962016-09-26 15:11:23 +0300240 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000241 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300242 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000243 return endToEndPaths;
244 }
245
246 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink,
Andrey Komarov2398d962016-09-26 15:11:23 +0300247 Set<DisjointPath> paths, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000248 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
249 for (DisjointPath path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300250 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000251 }
252 return endToEndPaths;
253 }
254
255 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300256 private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000257 List<Link> links = Lists.newArrayListWithCapacity(2);
Andrey Komarov2398d962016-09-26 15:11:23 +0300258 Weight cost = weigher.getInitialWeight();
Claudine Chiu45920dd2016-07-28 19:19:46 +0000259
260 // Add source and destination edge links only if they are real and
261 // add the infrastructure path only if it is not null.
262 if (srcLink != NOT_HOST) {
263 links.add(srcLink);
Andrey Komarov2398d962016-09-26 15:11:23 +0300264 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, srcLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000265 }
266 if (path != null) {
267 links.addAll(path.links());
Andrey Komarov2398d962016-09-26 15:11:23 +0300268 cost = cost.merge(path.weight());
Claudine Chiu45920dd2016-07-28 19:19:46 +0000269 }
270 if (dstLink != NOT_HOST) {
271 links.add(dstLink);
Thomas Vachuskab8116eb2017-08-09 15:39:39 -0700272 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, dstLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000273 }
274 return new DefaultPath(PID, links, cost);
275 }
276
277 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300278 private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path,
279 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000280 Path primary = null;
281 Path backup = null;
282 if (path != null) {
283 primary = path.primary();
284 backup = path.backup();
285 }
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530286 if (backup == null) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300287 return new DefaultDisjointPath(PID,
288 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher));
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530289 }
Andrey Komarov2398d962016-09-26 15:11:23 +0300290 return new DefaultDisjointPath(PID,
291 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher),
292 (DefaultPath) edgeToEdgePath(srcLink, dstLink, backup, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000293 }
294
295
296 // Special value for edge link to represent that this is really not an
297 // edge link since the src or dst are really an infrastructure device.
298 private static class NotHost extends DefaultEdgeLink implements EdgeLink {
299 NotHost() {
300 super(PID, new ConnectPoint(HostId.NONE, P0),
301 new HostLocation(DeviceId.NONE, P0, 0L), false);
302 }
303 }
304}