2 * Copyright (c) 2020 Orange. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.algo.impl;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.PriorityQueue;
14 import org.eclipse.jdt.annotation.Nullable;
15 import org.opendaylight.algo.PathComputationAlgorithm;
16 import org.opendaylight.graph.ConnectedEdge;
17 import org.opendaylight.graph.ConnectedGraph;
18 import org.opendaylight.graph.ConnectedVertex;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.EdgeAttributes;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidth;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ComputationStatus;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ConstrainedPath;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ConstrainedPathBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.PathConstraints;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.path.descriptions.PathDescription;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.path.descriptions.PathDescriptionBuilder;
30 import org.opendaylight.yangtools.yang.common.Uint32;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 public abstract class AbstractPathComputation implements PathComputationAlgorithm {
36 private static final Logger LOG = LoggerFactory.getLogger(AbstractPathComputation.class);
38 protected final ConnectedGraph graph;
40 /* Source and Destination of the path */
41 protected CspfPath pathSource = null;
42 protected CspfPath pathDestination = null;
44 /* Constraints that the path must respect */
45 protected PathConstraints constraints = null;
47 /* Priority Queue and HashMap to manage path computation */
48 protected PriorityQueue<CspfPath> priorityQueue;
49 protected HashMap<Long, CspfPath> processedPath;
51 protected AbstractPathComputation(ConnectedGraph graph) {
53 priorityQueue = new PriorityQueue<CspfPath>();
54 processedPath = new HashMap<Long, CspfPath>();
58 * Initialize the various parameters for Path Computation, in particular the
59 * Source and Destination CspfPath.
62 * Source Vertex Identifier in the Connected Graph
64 * Destination Vertex Identifier in the Connected Graph
66 * @return Constrained Path Builder with status set to 'OnGoing' if
67 * initialization success, 'Failed' otherwise
69 protected ConstrainedPathBuilder initializePathComputation(VertexKey src, VertexKey dst) {
70 ConstrainedPathBuilder cpathBuilder = new ConstrainedPathBuilder().setStatus(ComputationStatus.InProgress);
72 /* Check that source and destination vertexKey are not identical */
73 if (src.equals(dst)) {
74 LOG.warn("Source and Destination are equal: Abort!");
75 cpathBuilder.setStatus(ComputationStatus.Failed);
80 * Get the Connected Vertex from the Graph to initialize the source of
83 ConnectedVertex vertex = null;
84 vertex = graph.getConnectedVertex(src.getVertexId().longValue());
86 LOG.warn("Found no source for Vertex Key {}", src);
87 cpathBuilder.setStatus(ComputationStatus.Failed);
90 LOG.debug("Create Path Source with Vertex {}", vertex.toString());
91 pathSource = new CspfPath(vertex).setCost(0).setDelay(0);
92 cpathBuilder.setSource(vertex.getVertex().getVertexId());
95 * Get the Connected Vertex from the Graph to initialize the destination
98 vertex = graph.getConnectedVertex(dst.getVertexId().longValue());
100 LOG.warn("Found no destination for Vertex Key {}", src);
101 cpathBuilder.setStatus(ComputationStatus.Failed);
104 LOG.debug("Create Path Destination with Vertex {}", vertex.toString());
105 pathDestination = new CspfPath(vertex);
106 cpathBuilder.setDestination(vertex.getVertex().getVertexId());
108 /* Initialize the Priority Queue, HashMap */
109 priorityQueue.clear();
110 priorityQueue.add(pathSource);
111 processedPath.clear();
112 processedPath.put(pathSource.getVertexKey(), pathSource);
113 processedPath.put(pathDestination.getVertexKey(), pathDestination);
119 * Check if Edge need to be prune regarding all constraints including
122 * @return True if Edge must be prune, False if Edge must be keep
124 protected boolean pruneEdge(ConnectedEdge edge, CspfPath path) {
125 /* Check that Constraints are initialized */
126 if (constraints == null) {
127 LOG.warn("Constraints not set");
131 /* Edge could point to an unknown Vertex e.g. with inter-domain link */
132 if ((edge.getDestination() == null) || (edge.getDestination().getVertex() == null)) {
133 LOG.debug("No Destination");
137 /* Check that Edge have attributes */
138 EdgeAttributes attributes = edge.getEdge() != null ? edge.getEdge().getEdgeAttributes() : null;
139 if (attributes == null) {
140 LOG.debug("No attributes");
144 /* Check that Edge belongs to the requested address family */
145 switch (constraints.getAddressFamily()) {
147 if ((attributes.getRemoteAddress() == null)
148 || (attributes.getRemoteAddress().getIpv4Address() == null)) {
149 LOG.debug("No Ipv4 address");
154 if ((attributes.getRemoteAddress() == null)
155 || (attributes.getRemoteAddress().getIpv6Address() == null)) {
156 LOG.debug("No Ipv6 address");
161 if (getIpv4NodeSid(edge.getDestination()) == null) {
162 LOG.debug("No Node-SID for IPv4");
165 if (attributes.getAdjSid() == null) {
166 LOG.debug("No Adjacency-SID");
171 if (getIpv6NodeSid(edge.getDestination()) == null) {
172 LOG.debug("No Node-SID for IPv6");
175 if (attributes.getAdjSid() == null) {
176 LOG.debug("No SR Adjacency-SID");
184 /* Skip checking other Constraints for simple SPF algorithm */
185 if (this instanceof ShortestPathFirst) {
186 LOG.trace("Edge {} is valid for Simple Path Computation", edge.toString());
191 * If specified, check that total TE Metric up to this edge respects the
192 * initial constraints
194 if (constraints.getTeMetric() != null) {
195 if (attributes.getTeMetric() == null) {
198 int totalCost = attributes.getTeMetric().intValue() + path.getCost();
199 if (totalCost > constraints.getTeMetric().intValue()) {
200 LOG.debug("TeMetric {} exceed constraint {}", totalCost, constraints.getTeMetric().intValue());
207 * If specified, check that total Delay up to this edge respects the
208 * initial constraints
210 if (constraints.getDelay() != null) {
211 if (attributes.getDelay() == null) {
214 int totalDelay = attributes.getDelay().getValue().intValue() + path.getDelay();
215 if (totalDelay > constraints.getDelay().getValue().intValue()) {
216 LOG.debug("Delay {} exceed constraint {}", totalDelay,
217 constraints.getDelay().getValue().intValue());
223 /* Check that Edge respect Loss constraint */
224 if (constraints.getLoss() != null) {
225 if ((attributes.getLoss() == null)
226 || (attributes.getLoss().getValue().intValue() > constraints.getLoss().getValue().intValue())) {
231 /* Check that Edge meet Bandwidth constraint */
232 if (constraints.getBandwidth() != null) {
233 if ((attributes.getMaxLinkBandwidth() == null) || (attributes.getMaxResvLinkBandwidth() == null)
234 || (attributes.getUnreservedBandwidth() == null)
235 || (attributes.getUnreservedBandwidth().get(constraints.getClassType().intValue()) == null)) {
238 Long bandwidth = constraints.getBandwidth().getValue().longValue();
240 for (UnreservedBandwidth unResBw : attributes.getUnreservedBandwidth()) {
241 if (unResBw.getClassType().intValue() == constraints.getClassType().intValue()) {
242 unrsv = unResBw.getBandwidth().getValue().longValue();
246 if (unrsv < bandwidth || attributes.getMaxLinkBandwidth().getValue().longValue() < bandwidth
247 || attributes.getMaxResvLinkBandwidth().getValue().longValue() < bandwidth) {
248 LOG.debug("Bandwidth constraint is not met");
254 /* Check that Edge belongs to admin group */
255 if ((constraints.getAdminGroup() != null)
256 && !(constraints.getAdminGroup().equals(attributes.getAdminGroup()))) {
257 LOG.debug("Not in the requested admin-group");
262 * OK. All is fine. We can consider this Edge valid, so not to be prune
264 LOG.trace("Edge {} is valid for Constrained Path Computation", edge.toString());
269 * Return the MPLS Label corresponding to the Node SID for IPv4 when the
270 * Connected Vertex is Segment Routing aware.
272 * @return MPLS Label if Connected Vertex is Segment Routing aware, Null
275 protected @Nullable MplsLabel getIpv4NodeSid(ConnectedVertex cvertex) {
277 * Check that Vertex is Segment Routing aware
279 if ((cvertex.getVertex() == null) || (cvertex.getVertex().getSrgb() == null)) {
283 * Find in Prefix List Node SID attached to the IPv4 of the next Vertex
284 * and return the MPLS Label that corresponds to the index in the SRGB
286 if (cvertex.getPrefixes() == null) {
289 for (Prefix prefix : cvertex.getPrefixes()) {
290 if ((prefix.getPrefixSid() == null) || (prefix.isNodeSid() == null)) {
293 if (prefix.isNodeSid() && prefix.getPrefix().getIpv4Prefix() != null) {
294 return new MplsLabel(Uint32.valueOf(prefix.getPrefixSid().intValue()));
301 * Return the MPLS Label corresponding to the Node SID for IPv6 when the
302 * Connected Vertex is Segment Routing aware.
304 * @return MPLS Label if Connected Vertex is Segment Routing aware, Null
307 protected @Nullable MplsLabel getIpv6NodeSid(ConnectedVertex cvertex) {
309 * Check that Vertex is Segment Routing aware
311 if ((cvertex.getVertex() == null) || (cvertex.getVertex().getSrgb() == null)) {
315 * Find in Prefix List Node SID attached to the IPv6 of the next Vertex
316 * and return the MPLS Label that corresponds to the index in the SRGB
318 if (cvertex.getPrefixes() == null) {
321 for (Prefix prefix : cvertex.getPrefixes()) {
322 if ((prefix.getPrefixSid() == null) || (prefix.isNodeSid() == null)) {
325 if (prefix.isNodeSid() && prefix.getPrefix().getIpv6Prefix() != null) {
326 return new MplsLabel(Uint32.valueOf(prefix.getPrefixSid().intValue()));
333 * Convert List of Connected Edges into a Path Description as a List of
334 * IPv4, IPv6 or MPLS Label depending of the requested Address Family.
337 * List of Connected Edges
339 * @return Path Description
341 protected List<PathDescription> getPathDescription(List<ConnectedEdge> edges) {
342 ArrayList<PathDescription> list = new ArrayList<PathDescription>();
344 for (ConnectedEdge edge : edges) {
345 PathDescription pathDesc = null;
346 switch (constraints.getAddressFamily()) {
348 pathDesc = new PathDescriptionBuilder()
349 .setIpv4(edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv4Address()).build();
352 pathDesc = new PathDescriptionBuilder()
353 .setIpv6(edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv6Address()).build();
356 pathDesc = new PathDescriptionBuilder()
357 .setLocalIpv4(edge.getEdge().getEdgeAttributes().getLocalAddress().getIpv4Address())
358 .setRemoteIpv4(edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv4Address())
359 .setSid(edge.getEdge().getEdgeAttributes().getAdjSid())
363 pathDesc = new PathDescriptionBuilder()
364 .setLocalIpv6(edge.getEdge().getEdgeAttributes().getLocalAddress().getIpv6Address())
365 .setRemoteIpv6(edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv6Address())
366 .setSid(edge.getEdge().getEdgeAttributes().getAdjSid())
378 public abstract ConstrainedPath computeP2pPath(VertexKey source, VertexKey destination,
379 PathConstraints constraints);