Path Computation Server
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / PathComputationImpl.java
1 /*
2  * Copyright (c) 2020 Orange. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.bgpcep.pcep.server.provider;
10
11 import com.google.common.base.Preconditions;
12 import java.math.BigDecimal;
13 import java.nio.ByteBuffer;
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.opendaylight.params.xml.ns.yang.graph.rev191125.DecimalBandwidth;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Delay;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.AlgorithmType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ComputationStatus;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ConstrainedPath;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.PathConstraints;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.PathConstraints.AddressFamily;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.get.constrained.path.input.ConstraintsBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv4Case;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv6Case;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObj;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.Requests;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2p;
42 import org.opendaylight.yangtools.yang.common.Uint32;
43 import org.opendaylight.yangtools.yang.common.Uint8;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class PathComputationImpl implements PathComputation {
48
49     private static final Logger LOG = LoggerFactory.getLogger(PathComputationImpl.class);
50
51     private final ConnectedGraph tedGraph;
52     private final PathComputationProvider algoProvider;
53
54     public PathComputationImpl(ConnectedGraph tedGraph, PathComputationProvider algoProvider) {
55         Preconditions.checkArgument(tedGraph != null);
56         this.tedGraph = tedGraph;
57         this.algoProvider = algoProvider;
58     }
59
60     @Override
61     public Message computePath(Requests req) {
62         LOG.info("Received Compute Path request");
63
64         /* Check that Request Parameter Object is present */
65         if (req == null || req.getRp() == null) {
66             LOG.error("Missing Request Parameter Objects. Abort!");
67             return MessagesUtil.createErrorMsg(PCEPErrors.RP_MISSING, Uint32.ZERO);
68         }
69
70         LOG.debug("Request for path computation {}", req);
71
72         /*
73          * Check that mandatory End Point Objects are present and Source /
74          * Destination are know in the TED Graph
75          */
76         P2p input = req.getSegmentComputation().getP2p();
77         if (input == null || input.getEndpointsObj() == null) {
78             LOG.error("Missing End Point Objects. Abort!");
79             Uint32 reqID = req.getRp().getRequestId().getValue();
80             return MessagesUtil.createErrorMsg(PCEPErrors.END_POINTS_MISSING, reqID);
81         }
82         VertexKey source = getSourceVertexKey(input.getEndpointsObj());
83         VertexKey destination = getDestinationVertexKey(input.getEndpointsObj());
84         if (source == null) {
85             return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_SOURCE);
86         }
87         if (destination == null) {
88             return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_DESTINATION);
89         }
90
91         /* Create new Constraints Object from the request */
92         PathConstraints cts = getConstraints(input, !PSTUtil.isDefaultPST(req.getRp().getTlvs().getPathSetupType()));
93
94         /* Determine Path Computation Algorithm according to Input choice */
95         AlgorithmType algoType;
96         if ((cts.getTeMetric() == null) && (cts.getDelay() == null)) {
97             algoType = AlgorithmType.Spf;
98         } else if (cts.getDelay() == null) {
99             algoType = AlgorithmType.Cspf;
100         } else {
101             algoType = AlgorithmType.Samcra;
102         }
103         PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType);
104         if (algo == null) {
105             return MessagesUtil.createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
106         }
107
108         /* Request Path Computation for given source, destination and constraints */
109         LOG.debug("Call Path Computation {} algorithm for path from {} to {} with contraints {}",
110                 algoType, source, destination, cts);
111         final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts);
112
113         LOG.info("Computed path: {}", cpath.getPathDescription());
114
115         /* Check if we got a valid Path and return appropriate message */
116         if (cpath.getStatus() == ComputationStatus.Completed) {
117             return MessagesUtil.createPcRepMessage(req.getRp(), req.getSegmentComputation().getP2p(), cpath);
118         } else {
119             return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.NO_PATH);
120         }
121     }
122
123     @Override
124     public Ero computeEro(EndpointsObj endpoints, Bandwidth bandwidth, ClassType classType, List<Metrics> metrics,
125             boolean segmentRouting) {
126         VertexKey source = getSourceVertexKey(endpoints);
127         VertexKey destination = getDestinationVertexKey(endpoints);
128         if (source == null) {
129             return null;
130         }
131         if (destination == null) {
132             return null;
133         }
134         /* Create new Constraints Object from the request */
135         PathConstraints cts = getConstraints(endpoints, bandwidth, classType, metrics, segmentRouting);
136
137         /* Determine Path Computation Algorithm according to parameters */
138         AlgorithmType algoType;
139         if ((cts.getTeMetric() == null) && (cts.getDelay() == null) && (cts.getBandwidth() == null)) {
140             algoType = AlgorithmType.Spf;
141         } else if (cts.getDelay() == null) {
142             algoType = AlgorithmType.Cspf;
143         } else {
144             algoType = AlgorithmType.Samcra;
145         }
146         PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType);
147         if (algo == null) {
148             return null;
149         }
150
151         /*
152          * Request Path Computation for given source, destination and
153          * constraints
154          */
155         final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts);
156
157         LOG.info("Computed ERO: {}", cpath.getPathDescription());
158
159         /* Check if we got a valid Path and return appropriate ERO */
160         if (cpath.getStatus() == ComputationStatus.Completed) {
161             return MessagesUtil.getEro(cpath.getPathDescription());
162         } else {
163             return null;
164         }
165     }
166
167     private VertexKey getSourceVertexKey(EndpointsObj endPoints) {
168         IpAddress address = null;
169
170         if (endPoints.getAddressFamily() instanceof Ipv4Case) {
171             address = new IpAddress(((Ipv4Case) endPoints.getAddressFamily()).getIpv4().getSourceIpv4Address());
172         }
173         if (endPoints.getAddressFamily() instanceof Ipv6Case) {
174             address = new IpAddress(((Ipv6Case) endPoints.getAddressFamily()).getIpv6().getSourceIpv6Address());
175         }
176         if (address == null) {
177             return null;
178         }
179
180         ConnectedVertex vertex = tedGraph.getConnectedVertex(address);
181         LOG.debug("Compute path from Source {}", vertex.toString());
182         return (vertex != null) ? vertex.getVertex().key() : null;
183     }
184
185     private VertexKey getDestinationVertexKey(EndpointsObj endPoints) {
186         IpAddress address = null;
187
188         if (endPoints.getAddressFamily() instanceof Ipv4Case) {
189             address = new IpAddress(((Ipv4Case) endPoints.getAddressFamily()).getIpv4().getDestinationIpv4Address());
190         }
191         if (endPoints.getAddressFamily() instanceof Ipv6Case) {
192             address = new IpAddress(((Ipv6Case) endPoints.getAddressFamily()).getIpv6().getDestinationIpv6Address());
193         }
194         if (address == null) {
195             return null;
196         }
197
198         ConnectedVertex vertex = tedGraph.getConnectedVertex(address);
199         LOG.debug("Compute path to Destination {}", vertex.toString());
200         return (vertex != null) ? vertex.getVertex().key() : null;
201     }
202
203     private PathConstraints getConstraints(P2p parameters, boolean segmentRouting) {
204         return getConstraints(parameters.getEndpointsObj(), parameters.getBandwidth(), parameters.getClassType(),
205                 parameters.getMetrics(), segmentRouting);
206     }
207
208     private PathConstraints getConstraints(EndpointsObj endpoints, Bandwidth bandwidth, ClassType classType,
209             List<Metrics> metrics, boolean segmentRouting) {
210         ConstraintsBuilder ctsBuilder = new ConstraintsBuilder();
211         Float convert;
212
213         /* Set Metrics if any */
214         if (metrics != null) {
215             for (Metrics metric : metrics) {
216                 convert = ByteBuffer.wrap(metric.getMetric().getValue().getValue()).getFloat();
217                 switch (metric.getMetric().getMetricType().intValue()) {
218                     case MessagesUtil.IGP_METRIC:
219                         ctsBuilder.setMetric(Uint32.valueOf(convert.longValue()));
220                         break;
221                     case MessagesUtil.TE_METRIC:
222                         ctsBuilder.setTeMetric(Uint32.valueOf(convert.longValue()));
223                         break;
224                     case MessagesUtil.PATH_DELAY:
225                         ctsBuilder.setDelay(new Delay(Uint32.valueOf(convert.longValue())));
226                         break;
227                     default:
228                         LOG.warn("Metric {} is not handle by Path Computation Constraints", metric);
229                         break;
230                 }
231             }
232         }
233
234         /* Set Bandwidth and Class Type */
235         if (bandwidth != null) {
236             convert = ByteBuffer.wrap(bandwidth.getBandwidth().getValue()).getFloat();
237             ctsBuilder.setBandwidth(new DecimalBandwidth(BigDecimal.valueOf(convert.longValue())));
238             if (classType != null) {
239                 ctsBuilder.setClassType(classType.getClassType().getValue());
240             } else {
241                 ctsBuilder.setClassType(Uint8.ZERO);
242             }
243         }
244
245         /* Set Address Family */
246         if (endpoints.getAddressFamily() instanceof Ipv4Case) {
247             if (segmentRouting) {
248                 ctsBuilder.setAddressFamily(AddressFamily.SrIpv4);
249             } else {
250                 ctsBuilder.setAddressFamily(AddressFamily.Ipv4);
251             }
252         } else {
253             if (segmentRouting) {
254                 ctsBuilder.setAddressFamily(AddressFamily.SrIpv6);
255             } else {
256                 ctsBuilder.setAddressFamily(AddressFamily.Ipv6);
257             }
258         }
259
260         return ctsBuilder.build();
261     }
262 }