blob: 82c9895f77d09ec00c2e55de9be9467332f5ffab [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;
Brian O'Connord03d7dd2016-08-02 23:33:25 -070021import org.apache.felix.scr.annotations.Component;
Claudine Chiu45920dd2016-07-28 19:19:46 +000022import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DefaultDisjointPath;
26import org.onosproject.net.DefaultEdgeLink;
27import org.onosproject.net.DefaultPath;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.DisjointPath;
30import org.onosproject.net.EdgeLink;
31import org.onosproject.net.ElementId;
32import org.onosproject.net.Host;
33import org.onosproject.net.HostId;
34import org.onosproject.net.HostLocation;
35import org.onosproject.net.Link;
36import org.onosproject.net.Path;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.host.HostService;
39import org.onosproject.net.provider.ProviderId;
40
41import java.util.List;
42import java.util.Map;
43import java.util.Set;
44
45import static com.google.common.base.Preconditions.checkNotNull;
46
47/**
48 * Helper class for path service.
49 */
Brian O'Connord03d7dd2016-08-02 23:33:25 -070050@Component(componentAbstract = true)
Claudine Chiu45920dd2016-07-28 19:19:46 +000051public abstract class AbstractPathService {
52
53 private static final String ELEMENT_ID_NULL = "Element ID cannot be null";
54 private static final EdgeLink NOT_HOST = new NotHost();
55
56 private static final ProviderId PID = new ProviderId("core", "org.onosproject.core");
57 private static final PortNumber P0 = PortNumber.portNumber(0);
58
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected TopologyService topologyService;
61
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected HostService hostService;
64
65 public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
66 checkNotNull(src, ELEMENT_ID_NULL);
67 checkNotNull(dst, ELEMENT_ID_NULL);
68
69 // Get the source and destination edge locations
70 EdgeLink srcEdge = getEdgeLink(src, true);
71 EdgeLink dstEdge = getEdgeLink(dst, false);
72
73 // If either edge is null, bail with no paths.
74 if (srcEdge == null || dstEdge == null) {
75 return ImmutableSet.of();
76 }
77
78 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
79 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
80
81 // If the source and destination are on the same edge device, there
82 // is just one path, so build it and return it.
83 if (srcDevice.equals(dstDevice)) {
84 return edgeToEdgePaths(srcEdge, dstEdge);
85 }
86
87 // Otherwise get all paths between the source and destination edge
88 // devices.
89 Topology topology = topologyService.currentTopology();
90 Set<Path> paths = weight == null ?
91 topologyService.getPaths(topology, srcDevice, dstDevice) :
92 topologyService.getPaths(topology, srcDevice, dstDevice, weight);
93
94 return edgeToEdgePaths(srcEdge, dstEdge, paths);
95 }
96
97 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
98 checkNotNull(src, ELEMENT_ID_NULL);
99 checkNotNull(dst, ELEMENT_ID_NULL);
100
101 // Get the source and destination edge locations
102 EdgeLink srcEdge = getEdgeLink(src, true);
103 EdgeLink dstEdge = getEdgeLink(dst, false);
104
105 // If either edge is null, bail with no paths.
106 if (srcEdge == null || dstEdge == null) {
107 return ImmutableSet.of();
108 }
109
110 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
111 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
112
113 // If the source and destination are on the same edge device, there
114 // is just one path, so build it and return it.
115 if (srcDevice.equals(dstDevice)) {
116 return edgeToEdgePathsDisjoint(srcEdge, dstEdge);
117 }
118
119 // Otherwise get all paths between the source and destination edge
120 // devices.
121 Topology topology = topologyService.currentTopology();
122 Set<DisjointPath> paths = weight == null ?
123 topologyService.getDisjointPaths(topology, srcDevice, dstDevice) :
124 topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight);
125
126 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths);
127 }
128
129 public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
130 Map<Link, Object> riskProfile) {
131 checkNotNull(src, ELEMENT_ID_NULL);
132 checkNotNull(dst, ELEMENT_ID_NULL);
133
134 // Get the source and destination edge locations
135 EdgeLink srcEdge = getEdgeLink(src, true);
136 EdgeLink dstEdge = getEdgeLink(dst, false);
137
138 // If either edge is null, bail with no paths.
139 if (srcEdge == null || dstEdge == null) {
140 return ImmutableSet.of();
141 }
142
143 DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
144 DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
145
146 // If the source and destination are on the same edge device, there
147 // is just one path, so build it and return it.
148 if (srcDevice.equals(dstDevice)) {
149 return edgeToEdgePathsDisjoint(srcEdge, dstEdge);
150 }
151
152 // Otherwise get all paths between the source and destination edge
153 // devices.
154 Topology topology = topologyService.currentTopology();
155 Set<DisjointPath> paths = weight == null ?
156 topologyService.getDisjointPaths(topology, srcDevice, dstDevice, riskProfile) :
157 topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight, riskProfile);
158
159 return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths);
160 }
161
162 // Finds the host edge link if the element ID is a host id of an existing
163 // host. Otherwise, if the host does not exist, it returns null and if
164 // the element ID is not a host ID, returns NOT_HOST edge link.
165 private EdgeLink getEdgeLink(ElementId elementId, boolean isIngress) {
166 if (elementId instanceof HostId) {
167 // Resolve the host, return null.
168 Host host = hostService.getHost((HostId) elementId);
169 if (host == null) {
170 return null;
171 }
172 return new DefaultEdgeLink(PID, new ConnectPoint(elementId, P0),
173 host.location(), isIngress);
174 }
175 return NOT_HOST;
176 }
177
178 // Produces a set of edge-to-edge paths using the set of infrastructure
179 // paths and the given edge links.
180 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink) {
181 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
182 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, null));
183 return endToEndPaths;
184 }
185
186 // Produces a set of edge-to-edge paths using the set of infrastructure
187 // paths and the given edge links.
188 private Set<Path> edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, Set<Path> paths) {
189 Set<Path> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
190 for (Path path : paths) {
191 endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, path));
192 }
193 return endToEndPaths;
194 }
195
196 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink) {
197 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
198 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null));
199 return endToEndPaths;
200 }
201
202 private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink,
203 Set<DisjointPath> paths) {
204 Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
205 for (DisjointPath path : paths) {
206 endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path));
207 }
208 return endToEndPaths;
209 }
210
211 // Produces a direct edge-to-edge path.
212 private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path) {
213 List<Link> links = Lists.newArrayListWithCapacity(2);
214 double cost = 0;
215
216 // Add source and destination edge links only if they are real and
217 // add the infrastructure path only if it is not null.
218 if (srcLink != NOT_HOST) {
219 links.add(srcLink);
220 cost++;
221 }
222 if (path != null) {
223 links.addAll(path.links());
224 cost += path.cost();
225 }
226 if (dstLink != NOT_HOST) {
227 links.add(dstLink);
228 cost++;
229 }
230 return new DefaultPath(PID, links, cost);
231 }
232
233 // Produces a direct edge-to-edge path.
234 private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path) {
235 Path primary = null;
236 Path backup = null;
237 if (path != null) {
238 primary = path.primary();
239 backup = path.backup();
240 }
241 return new DefaultDisjointPath(PID, (DefaultPath) edgeToEdgePath(srcLink, dstLink, primary),
242 (DefaultPath) edgeToEdgePath(srcLink, dstLink, backup));
243 }
244
245
246 // Special value for edge link to represent that this is really not an
247 // edge link since the src or dst are really an infrastructure device.
248 private static class NotHost extends DefaultEdgeLink implements EdgeLink {
249 NotHost() {
250 super(PID, new ConnectPoint(HostId.NONE, P0),
251 new HostLocation(DeviceId.NONE, P0, 0L), false);
252 }
253 }
254}