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.bgpcep.pcep.server.provider;
10 import static java.util.Objects.requireNonNull;
12 import java.nio.ByteBuffer;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.algo.PathComputationAlgorithm;
16 import org.opendaylight.algo.PathComputationProvider;
17 import org.opendaylight.bgpcep.pcep.server.PathComputation;
18 import org.opendaylight.graph.ConnectedGraph;
19 import org.opendaylight.graph.ConnectedVertex;
20 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
21 import org.opendaylight.protocol.pcep.spi.PSTUtil;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.DecimalBandwidth;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Delay;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.VertexKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.AddressFamily;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.AlgorithmType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ComputationStatus;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ConstrainedPath;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.PathConstraints;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.get.constrained.path.input.ConstraintsBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.constraints.ExcludeRoute;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.constraints.ExcludeRouteBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.constraints.IncludeRoute;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.constraints.IncludeRouteBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPath;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPathBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPath;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv4Case;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv6Case;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObj;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.exclude.route.object.Xro;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.include.route.object.Iro;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.Requests;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2p;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase;
54 import org.opendaylight.yangtools.yang.common.Decimal64;
55 import org.opendaylight.yangtools.yang.common.Uint32;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 public class PathComputationImpl implements PathComputation {
61 private static final Logger LOG = LoggerFactory.getLogger(PathComputationImpl.class);
63 private final ConnectedGraph tedGraph;
64 private final PathComputationProvider algoProvider;
66 public PathComputationImpl(final ConnectedGraph tedGraph, final PathComputationProvider algoProvider) {
67 this.tedGraph = requireNonNull(tedGraph);
68 this.algoProvider = requireNonNull(algoProvider);
72 public Message computePath(final Requests req) {
73 LOG.info("Received Compute Path request");
75 /* Check that Request Parameter Object is present */
76 if (req == null || req.getRp() == null) {
77 LOG.error("Missing Request Parameter Objects. Abort!");
78 return MessagesUtil.createErrorMsg(PCEPErrors.RP_MISSING, Uint32.ZERO);
81 LOG.debug("Request for path computation {}", req);
84 * Check that mandatory End Point Objects are present and Source /
85 * Destination are know in the TED Graph
87 P2p input = req.getSegmentComputation().getP2p();
88 if (input == null || input.getEndpointsObj() == null) {
89 LOG.error("Missing End Point Objects. Abort!");
90 Uint32 reqID = req.getRp().getRequestId().getValue();
91 return MessagesUtil.createErrorMsg(PCEPErrors.END_POINTS_MISSING, reqID);
93 VertexKey source = getSourceVertexKey(input.getEndpointsObj());
94 VertexKey destination = getDestinationVertexKey(input.getEndpointsObj());
96 return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_SOURCE);
98 if (destination == null) {
99 return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_DESTINATION);
102 /* Create new Constraints Object from the request */
103 PathConstraints cts = getConstraints(input, !PSTUtil.isDefaultPST(req.getRp().getTlvs().getPathSetupType()));
105 /* Determine Path Computation Algorithm according to Input choice */
106 AlgorithmType algoType;
107 if (cts.getDelay() != null) {
108 algoType = AlgorithmType.Samcra;
109 } else if (cts.getTeMetric() != null) {
110 algoType = AlgorithmType.Cspf;
112 algoType = AlgorithmType.Spf;
114 PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType);
116 return MessagesUtil.createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
119 /* Request Path Computation for given source, destination and constraints */
120 LOG.debug("Call Path Computation {} algorithm for path from {} to {} with contraints {}",
121 algoType, source, destination, cts);
122 final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts);
124 LOG.info("Computed path: {}", cpath.getPathDescription());
126 /* Check if we got a valid Path and return appropriate message */
127 if (cpath.getStatus() == ComputationStatus.Completed) {
128 return MessagesUtil.createPcRepMessage(req.getRp(), req.getSegmentComputation().getP2p(), cpath);
130 return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.NO_PATH);
134 public ComputedPath computeTePath(final IntendedPath intend) {
135 final ComputedPathBuilder cpb = new ComputedPathBuilder();
136 ConnectedVertex source = tedGraph.getConnectedVertex(intend.getSource());
137 ConnectedVertex destination = tedGraph.getConnectedVertex(intend.getDestination());
139 if (source == null) {
140 return cpb.setComputationStatus(ComputationStatus.NoSource).build();
142 if (destination == null) {
143 return cpb.setComputationStatus(ComputationStatus.NoDestination).build();
146 /* Determine Path Computation Algorithm according to parameters */
147 AlgorithmType algoType;
148 if (intend.getConstraints().getDelay() != null) {
149 algoType = AlgorithmType.Samcra;
150 } else if (intend.getConstraints().getTeMetric() != null) {
151 algoType = AlgorithmType.Cspf;
153 algoType = AlgorithmType.Spf;
155 PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType);
157 return cpb.setComputationStatus(ComputationStatus.Failed).build();
160 /* Request Path Computation for given source, destination and constraints */
161 final ConstrainedPath cpath = algo.computeP2pPath(source.getVertex().key(), destination.getVertex().key(),
162 intend.getConstraints());
164 LOG.info("Computed path: {}", cpath.getPathDescription());
166 /* Check if we got a valid Path and return appropriate Path Description */
167 if (cpath.getStatus() == ComputationStatus.Completed) {
168 cpb.setPathDescription(cpath.getPathDescription()).setComputationStatus(ComputationStatus.Completed);
169 if (intend.getConstraints().getDelay() != null) {
170 cpb.setComputedMetric(cpath.getDelay().getValue());
171 } else if (intend.getConstraints().getTeMetric() != null) {
172 cpb.setComputedMetric(cpath.getTeMetric());
174 cpb.setComputedMetric(cpath.getMetric());
178 return cpb.setComputationStatus(ComputationStatus.NoPath).build();
183 public Ero computeEro(final EndpointsObj endpoints, final Bandwidth bandwidth, final ClassType classType,
184 final List<Metrics> metrics, final Xro xro, final Iro iro, final boolean segmentRouting) {
185 /* Get source and destination Vertex and verify there are valid */
186 VertexKey source = getSourceVertexKey(endpoints);
187 if (source == null) {
190 VertexKey destination = getDestinationVertexKey(endpoints);
191 if (destination == null) {
194 /* Create new Constraints Object from the request */
195 PathConstraints cts = getConstraints(endpoints, bandwidth, classType, metrics, xro, iro, segmentRouting);
197 /* Determine Path Computation Algorithm according to parameters */
198 AlgorithmType algoType;
199 if (cts.getDelay() != null) {
200 algoType = AlgorithmType.Samcra;
201 } else if (cts.getTeMetric() != null) {
202 algoType = AlgorithmType.Cspf;
204 algoType = AlgorithmType.Spf;
206 PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType);
212 * Request Path Computation for given source, destination and
215 final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts);
217 LOG.info("Computed path: {}", cpath.getPathDescription());
219 /* Check if we got a valid Path and return appropriate ERO */
220 if (cpath.getStatus() == ComputationStatus.Completed) {
221 return MessagesUtil.getEro(cpath.getPathDescription());
227 private VertexKey getSourceVertexKey(final EndpointsObj endPoints) {
228 IpAddress address = null;
230 if (endPoints.getAddressFamily() instanceof Ipv4Case) {
231 address = new IpAddress(((Ipv4Case) endPoints.getAddressFamily()).getIpv4().getSourceIpv4Address());
233 if (endPoints.getAddressFamily() instanceof Ipv6Case) {
234 address = new IpAddress(((Ipv6Case) endPoints.getAddressFamily()).getIpv6().getSourceIpv6Address());
236 if (address == null) {
240 ConnectedVertex vertex = tedGraph.getConnectedVertex(address);
241 LOG.debug("Compute path from Source {}", vertex != null ? vertex : "Unknown");
242 return vertex != null ? vertex.getVertex().key() : null;
245 private VertexKey getDestinationVertexKey(final EndpointsObj endPoints) {
246 IpAddress address = null;
248 if (endPoints.getAddressFamily() instanceof Ipv4Case ipv4) {
249 address = new IpAddress(ipv4.getIpv4().getDestinationIpv4Address());
251 if (endPoints.getAddressFamily() instanceof Ipv6Case ipv6) {
252 address = new IpAddress(ipv6.getIpv6().getDestinationIpv6Address());
254 if (address == null) {
258 ConnectedVertex vertex = tedGraph.getConnectedVertex(address);
259 LOG.debug("Compute path to Destination {}", vertex != null ? vertex : "Unknown");
260 return vertex != null ? vertex.getVertex().key() : null;
263 /* Convert Exclude Route Object (list of IP prefix) into Exclude Route (list of IP address) */
264 private static List<ExcludeRoute> getExcludeRoute(final Xro xro, final AddressFamily af) {
268 final var subobjects = xro.getSubobject();
269 if (subobjects == null || subobjects.isEmpty()) {
273 final var erl = new ArrayList<ExcludeRoute>();
274 for (var element : subobjects) {
275 final var sbt = element.getSubobjectType();
276 if (sbt instanceof IpPrefixCase ipc) {
278 case Ipv4, SrIpv4 -> {
279 erl.add(new ExcludeRouteBuilder()
280 .setIpv4(new Ipv4Address(
281 ipc.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue().split("/")[0]))
284 case Ipv6, SrIpv6 -> {
285 erl.add(new ExcludeRouteBuilder()
286 .setIpv6(new Ipv6Address(
287 ipc.getIpPrefix().getIpPrefix().getIpv6Prefix().getValue().split("/")[0]))
299 /* Convert Include Route Object (list of IP prefix) into Exclude Route (list of IP address) */
300 private static List<IncludeRoute> getIncludeRoute(final Iro iro, final AddressFamily af) {
305 final var subobjects = iro.getSubobject();
306 if (subobjects == null || subobjects.isEmpty()) {
309 final var irl = new ArrayList<IncludeRoute>();
310 for (var element : subobjects) {
311 final var sbt = element.getSubobjectType();
312 if (sbt instanceof IpPrefixCase ipc) {
314 case Ipv4, SrIpv4 -> {
315 irl.add(new IncludeRouteBuilder()
316 .setIpv4(new Ipv4Address(
317 ipc.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue().split("/")[0]))
320 case Ipv6, SrIpv6 -> {
321 irl.add(new IncludeRouteBuilder()
322 .setIpv6(new Ipv6Address(
323 ipc.getIpPrefix().getIpPrefix().getIpv6Prefix().getValue().split("/")[0]))
335 private static PathConstraints getConstraints(final P2p parameters, final boolean segmentRouting) {
336 return getConstraints(parameters.getEndpointsObj(), parameters.getBandwidth(), parameters.getClassType(),
337 parameters.getMetrics(), parameters.getXro(), parameters.getIro(), segmentRouting);
340 private static PathConstraints getConstraints(final EndpointsObj endpoints, final Bandwidth bandwidth,
341 final ClassType classType, final List<Metrics> metrics, final Xro xro, final Iro iro,
342 final boolean segmentRouting) {
343 ConstraintsBuilder ctsBuilder = new ConstraintsBuilder();
345 /* Set Metrics if any */
346 if (metrics != null) {
347 for (Metrics metric : metrics) {
348 Float convert = ByteBuffer.wrap(metric.getMetric().getValue().getValue()).getFloat();
349 final long value = convert.longValue();
350 /* Skip Metric with value equal to 0 */
355 switch (metric.getMetric().getMetricType().intValue()) {
356 case MessagesUtil.IGP_METRIC:
357 ctsBuilder.setMetric(Uint32.valueOf(value));
359 case MessagesUtil.TE_METRIC:
360 ctsBuilder.setTeMetric(Uint32.valueOf(value));
362 case MessagesUtil.PATH_DELAY:
363 ctsBuilder.setDelay(new Delay(Uint32.valueOf(value)));
366 LOG.warn("Metric {} is not handle by Path Computation Constraints", metric);
372 /* Set Bandwidth and Class Type */
373 if (bandwidth != null) {
374 Float convert = ByteBuffer.wrap(bandwidth.getBandwidth().getValue()).getFloat();
375 final long value = convert.longValue();
376 /* Skip Bandwidth with value equal to 0 */
378 // FIXME: correct rounding/truncation!
379 ctsBuilder.setBandwidth(new DecimalBandwidth(Decimal64.valueOf(2, value)));
380 if (classType != null) {
381 ctsBuilder.setClassType(classType.getClassType().getValue());
386 AddressFamily af = endpoints.getAddressFamily() instanceof Ipv4Case
387 ? segmentRouting ? AddressFamily.SrIpv4 : AddressFamily.Ipv4
388 : segmentRouting ? AddressFamily.SrIpv6 : AddressFamily.Ipv6;
390 /* Set Address Family, Exclude Route and Include Route if any */
392 .setAddressFamily(af)
393 .setExcludeRoute(getExcludeRoute(xro, af))
394 .setIncludeRoute(getIncludeRoute(iro, af))