blob: 2c43fc77405b1df9c1b0c5e2b11a640eea7da002 [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;
42
43import static com.google.common.base.Preconditions.checkNotNull;
Andrey Komarov2398d962016-09-26 15:11:23 +030044import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
Claudine Chiu45920dd2016-07-28 19:19:46 +000045
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 =
62 adapt(new HopCountLinkWeight());
63
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
Claudine Chiu45920dd2016-07-28 19:19:46 +000069 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
Andrey Komarov2398d962016-09-26 15:11:23 +030070 return getPaths(src, dst, adapt(weight));
71 }
72
73 @Override
74 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +000075 checkNotNull(src, ELEMENT_ID_NULL);
76 checkNotNull(dst, ELEMENT_ID_NULL);
77
Andrey Komarov2398d962016-09-26 15:11:23 +030078 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
79
Claudine Chiu45920dd2016-07-28 19:19:46 +000080 // Get the source and destination edge locations
81 EdgeLink srcEdge = getEdgeLink(src, true);
82 EdgeLink dstEdge = getEdgeLink(dst, false);
83
84 // If either edge is null, bail with no paths.
85 if (srcEdge == null || dstEdge == null) {
86 return ImmutableSet.of();
87 }
88
89 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
90 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
91
92 // If the source and destination are on the same edge device, there
93 // is just one path, so build it and return it.
94 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +030095 return edgeToEdgePaths(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +000096 }
97
98 // Otherwise get all paths between the source and destination edge
99 // devices.
100 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300101 Set<Path> paths = topologyService.getPaths(topology, srcDevice,
102 dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000103
Andrey Komarov2398d962016-09-26 15:11:23 +0300104 return edgeToEdgePaths(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000105 }
106
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700107 @Override
Claudine Chiu45920dd2016-07-28 19:19:46 +0000108 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300109 return getDisjointPaths(src, dst, adapt(weight));
110 }
111
112 @Override
113 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000114 checkNotNull(src, ELEMENT_ID_NULL);
115 checkNotNull(dst, ELEMENT_ID_NULL);
116
Andrey Komarov2398d962016-09-26 15:11:23 +0300117 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
118
Claudine Chiu45920dd2016-07-28 19:19:46 +0000119 // Get the source and destination edge locations
120 EdgeLink srcEdge = getEdgeLink(src, true);
121 EdgeLink dstEdge = getEdgeLink(dst, false);
122
123 // If either edge is null, bail with no paths.
124 if (srcEdge == null || dstEdge == null) {
125 return ImmutableSet.of();
126 }
127
128 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
129 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
130
131 // If the source and destination are on the same edge device, there
132 // is just one path, so build it and return it.
133 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300134 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000135 }
136
137 // Otherwise get all paths between the source and destination edge
138 // devices.
139 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300140 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
141 srcDevice, dstDevice, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000142
Andrey Komarov2398d962016-09-26 15:11:23 +0300143 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000144 }
145
Yuta HIGUCHI90e12292016-08-02 18:02:53 -0700146 @Override
Claudine Chiu45920dd2016-07-28 19:19:46 +0000147 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
148 Map<Link, Object> riskProfile) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300149 return getDisjointPaths(src, dst, adapt(weight), riskProfile);
150 }
151
152 @Override
153 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
154 LinkWeigher weigher, Map<Link, Object> riskProfile) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000155 checkNotNull(src, ELEMENT_ID_NULL);
156 checkNotNull(dst, ELEMENT_ID_NULL);
157
Andrey Komarov2398d962016-09-26 15:11:23 +0300158 LinkWeigher internalWeigher = weigher != null ? weigher : DEFAULT_WEIGHER;
159
Claudine Chiu45920dd2016-07-28 19:19:46 +0000160 // Get the source and destination edge locations
161 EdgeLink srcEdge = getEdgeLink(src, true);
162 EdgeLink dstEdge = getEdgeLink(dst, false);
163
164 // If either edge is null, bail with no paths.
165 if (srcEdge == null || dstEdge == null) {
166 return ImmutableSet.of();
167 }
168
169 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
170 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
171
172 // If the source and destination are on the same edge device, there
173 // is just one path, so build it and return it.
174 if (srcDevice.equals(dstDevice)) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300175 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000176 }
177
178 // Otherwise get all paths between the source and destination edge
179 // devices.
180 Topology topology = topologyService.currentTopology();
Andrey Komarov2398d962016-09-26 15:11:23 +0300181 Set<DisjointPath> paths = topologyService.getDisjointPaths(topology,
182 srcDevice, dstDevice, internalWeigher, riskProfile);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000183
Andrey Komarov2398d962016-09-26 15:11:23 +0300184 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths, internalWeigher);
Claudine Chiu45920dd2016-07-28 19:19:46 +0000185 }
186
187 // Finds the host edge link if the element ID is a host id of an existing
188 // host. Otherwise, if the host does not exist, it returns null and if
189 // the element ID is not a host ID, returns NOT_HOST edge link.
190 private EdgeLink getEdgeLink(ElementId elementId, boolean isIngress) {
191 if (elementId instanceof HostId) {
192 // Resolve the host, return null.
193 Host host = hostService.getHost((HostId) elementId);
194 if (host == null) {
195 return null;
196 }
197 return new DefaultEdgeLink(PID, new ConnectPoint(elementId, P0),
198 host.location(), isIngress);
199 }
200 return NOT_HOST;
201 }
202
203 // Produces a set of edge-to-edge paths using the set of infrastructure
204 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300205 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000206 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300207 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000208 return endToEndPaths;
209 }
210
211 // Produces a set of edge-to-edge paths using the set of infrastructure
212 // paths and the given edge links.
Andrey Komarov2398d962016-09-26 15:11:23 +0300213 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, Set<Path> paths,
214 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000215 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
216 for (Path path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300217 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000218 }
219 return endToEndPaths;
220 }
221
Andrey Komarov2398d962016-09-26 15:11:23 +0300222 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000223 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
Andrey Komarov2398d962016-09-26 15:11:23 +0300224 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000225 return endToEndPaths;
226 }
227
228 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink,
Andrey Komarov2398d962016-09-26 15:11:23 +0300229 Set<DisjointPath> paths, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000230 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
231 for (DisjointPath path : paths) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300232 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000233 }
234 return endToEndPaths;
235 }
236
237 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300238 private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path, LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000239 List<Link> links = Lists.newArrayListWithCapacity(2);
Andrey Komarov2398d962016-09-26 15:11:23 +0300240 Weight cost = weigher.getInitialWeight();
Claudine Chiu45920dd2016-07-28 19:19:46 +0000241
242 // Add source and destination edge links only if they are real and
243 // add the infrastructure path only if it is not null.
244 if (srcLink != NOT_HOST) {
245 links.add(srcLink);
Andrey Komarov2398d962016-09-26 15:11:23 +0300246 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, srcLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000247 }
248 if (path != null) {
249 links.addAll(path.links());
Andrey Komarov2398d962016-09-26 15:11:23 +0300250 cost = cost.merge(path.weight());
Claudine Chiu45920dd2016-07-28 19:19:46 +0000251 }
252 if (dstLink != NOT_HOST) {
253 links.add(dstLink);
Andrey Komarov2398d962016-09-26 15:11:23 +0300254 cost = cost.merge(weigher.weight(new DefaultTopologyEdge(null, null, srcLink)));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000255 }
256 return new DefaultPath(PID, links, cost);
257 }
258
259 // Produces a direct edge-to-edge path.
Andrey Komarov2398d962016-09-26 15:11:23 +0300260 private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path,
261 LinkWeigher weigher) {
Claudine Chiu45920dd2016-07-28 19:19:46 +0000262 Path primary = null;
263 Path backup = null;
264 if (path != null) {
265 primary = path.primary();
266 backup = path.backup();
267 }
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530268 if (backup == null) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300269 return new DefaultDisjointPath(PID,
270 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher));
Jayasree Ghoshd3ff5402016-08-17 18:41:19 +0530271 }
Andrey Komarov2398d962016-09-26 15:11:23 +0300272 return new DefaultDisjointPath(PID,
273 (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary, weigher),
274 (DefaultPath) edgeToEdgePath(srcLink, dstLink, backup, weigher));
Claudine Chiu45920dd2016-07-28 19:19:46 +0000275 }
276
277
278 // Special value for edge link to represent that this is really not an
279 // edge link since the src or dst are really an infrastructure device.
280 private static class NotHost extends DefaultEdgeLink implements EdgeLink {
281 NotHost() {
282 super(PID, new ConnectPoint(HostId.NONE, P0),
283 new HostLocation(DeviceId.NONE, P0, 0L), false);
284 }
285 }
286}