Merge changes I8c049137,I8660893e
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / PceSendingPceRPCs.java
1 /*
2  * Copyright © 2017 AT&T and others.  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.transportpce.pce;
10
11 import org.opendaylight.transportpce.common.ResponseCodes;
12 import org.opendaylight.transportpce.common.mapping.PortMapping;
13 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
14 import org.opendaylight.transportpce.pce.constraints.OperatorConstraints;
15 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
16 import org.opendaylight.transportpce.pce.constraints.PceConstraintsCalc;
17 import org.opendaylight.transportpce.pce.gnpy.GnpyException;
18 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
19 import org.opendaylight.transportpce.pce.gnpy.GnpyUtilitiesImpl;
20 import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
21 import org.opendaylight.transportpce.pce.graph.PceGraph;
22 import org.opendaylight.transportpce.pce.networkanalyzer.PceCalculation;
23 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInput;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInputBuilder;
26 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PceConstraintMode;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.path.computation.reroute.request.input.Endpoints;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.service.path.rpc.result.PathDescriptionBuilder;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev221209.routing.constraints.HardConstraints;
30 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.AToZDirection;
31 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.ZToADirection;
32 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.PceMetric;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /*
37  * Class for Sending
38  * PCE requests :
39  * - path-computation-request
40  * - path-computation-reroute
41  * - cancel-resource-reserve.
42  * @author Martial Coulibaly ( martial.coulibaly@gfi.com ) on behalf of Orange
43  *
44  */
45 public class PceSendingPceRPCs {
46
47     /* Logging. */
48     private static final Logger LOG = LoggerFactory.getLogger(PceSendingPceRPCs.class);
49     /* define procedure success (or not ). */
50     private PceResult rc = new PceResult();
51
52     /*
53      * define type of request<br> <code>true</code> pathcomputation <br>
54      * <code>false</code> cancelresourcereserve .
55      */
56     private PathDescriptionBuilder pathDescription;
57     private PathComputationRequestInput input;
58     private NetworkTransactionService networkTransaction;
59     private PceConstraints pceHardConstraints = new PceConstraints();
60     private PceConstraints pceSoftConstraints = new PceConstraints();
61     private GnpyResult gnpyAtoZ;
62     private GnpyResult gnpyZtoA;
63     private Boolean success;
64     private String message;
65     private String responseCode;
66     private final GnpyConsumer gnpyConsumer;
67     private PortMapping portMapping;
68     // Define the termination points whose reservation status is not taken into account during the pruning process
69     private Endpoints endpoints;
70
71     public PceSendingPceRPCs(GnpyConsumer gnpyConsumer) {
72         setPathDescription(null);
73         this.input = null;
74         this.networkTransaction = null;
75         this.gnpyConsumer = gnpyConsumer;
76     }
77
78     public PceSendingPceRPCs(PathComputationRequestInput input, NetworkTransactionService networkTransaction,
79                              GnpyConsumer gnpyConsumer, PortMapping portMapping) {
80         this.gnpyConsumer = gnpyConsumer;
81         setPathDescription(null);
82         // TODO compliance check to check that input is not empty
83         this.input = input;
84         this.networkTransaction = networkTransaction;
85         this.portMapping = portMapping;
86         this.endpoints = null;
87     }
88
89     public PceSendingPceRPCs(PathComputationRequestInput input, NetworkTransactionService networkTransaction,
90                              GnpyConsumer gnpyConsumer, PortMapping portMapping,
91                              Endpoints endpoints) {
92         this.gnpyConsumer = gnpyConsumer;
93         setPathDescription(null);
94         this.input = input;
95         this.networkTransaction = networkTransaction;
96         this.portMapping = portMapping;
97         this.endpoints = endpoints;
98     }
99
100     public void cancelResourceReserve() {
101         success = false;
102         LOG.info("Wait for 10s til beginning the PCE cancelResourceReserve request");
103         try {
104             // sleep for 10s
105             Thread.sleep(10000);
106         } catch (InterruptedException e) {
107             LOG.error("in PCESendingPceRPC: ",e);
108         }
109         success = true;
110         LOG.info("cancelResourceReserve ...");
111     }
112
113     private void pathComputationWithConstraints(PceConstraints hardConstraints, PceConstraints softConstraints,
114             PceConstraintMode mode) {
115
116         PceCalculation nwAnalizer = new PceCalculation(input, networkTransaction, hardConstraints, softConstraints, rc,
117                 portMapping, endpoints);
118         nwAnalizer.retrievePceNetwork();
119         rc = nwAnalizer.getReturnStructure();
120         String serviceType = nwAnalizer.getServiceType();
121         if (!rc.getStatus()) {
122             LOG.error("In pathComputationWithConstraints, nwAnalizer: result = {}", rc);
123             return;
124         }
125         OperatorConstraints opConstraints = new OperatorConstraints(networkTransaction);
126         LOG.info("PceGraph ...");
127         PceGraph graph = new PceGraph(nwAnalizer.getaendPceNode(), nwAnalizer.getzendPceNode(),
128                 nwAnalizer.getAllPceNodes(), nwAnalizer.getAllPceLinks(), hardConstraints,
129                 rc, serviceType, networkTransaction, mode, opConstraints.getBitMapConstraint(input.getCustomerName()));
130         graph.calcPath();
131         rc = graph.getReturnStructure();
132         if (!rc.getStatus()) {
133             LOG.warn("In pathComputationWithConstraints : Graph return without Path ");
134             // TODO fix. This is quick workaround for algorithm problem
135             if ((rc.getLocalCause() == PceResult.LocalCause.TOO_HIGH_LATENCY)
136                 && (hardConstraints.getPceMetrics() == PceMetric.HopCount)
137                 && (hardConstraints.getMaxLatency() != -1)) {
138                 hardConstraints.setPceMetrics(PceMetric.PropagationDelay);
139                 graph = patchRerunGraph(graph);
140             }
141
142             if (rc.getLocalCause() == PceResult.LocalCause.HD_NODE_INCLUDE) {
143                 graph.setKpathsToBring(graph.getKpathsToBring() * 10);
144                 graph = patchRerunGraph(graph);
145             }
146
147             if (!rc.getStatus()) {
148                 LOG.error("In pathComputationWithConstraints, graph.calcPath: result = {}", rc);
149                 return;
150             }
151         }
152         LOG.info("PcePathDescription ...");
153         PcePathDescription description = new PcePathDescription(graph.getPathAtoZ(), nwAnalizer.getAllPceLinks(), rc);
154         description.buildDescriptions();
155         rc = description.getReturnStructure();
156         if (!rc.getStatus()) {
157             LOG.error("In pathComputationWithConstraints, description: result = {}", rc);
158         }
159     }
160
161     public void pathComputation() throws Exception {
162
163         PceConstraintsCalc constraints = new PceConstraintsCalc(input, networkTransaction);
164         pceHardConstraints = constraints.getPceHardConstraints();
165         pceSoftConstraints = constraints.getPceSoftConstraints();
166         pathComputationWithConstraints(pceHardConstraints, pceSoftConstraints, PceConstraintMode.Loose);
167         this.success = rc.getStatus();
168         this.message = rc.getMessage();
169         this.responseCode = rc.getResponseCode();
170
171         AToZDirection atoz = null;
172         ZToADirection ztoa = null;
173         if (rc.getStatus()) {
174             atoz = rc.getAtoZDirection();
175             ztoa = rc.getZtoADirection();
176         }
177
178         //Connect to Gnpy to check path feasibility and recompute another path in case of path non-feasibility
179         try {
180             if (gnpyConsumer.isAvailable()) {
181                 GnpyUtilitiesImpl gnpy = new GnpyUtilitiesImpl(networkTransaction, input,
182                         gnpyConsumer);
183                 if (rc.getStatus() && gnpyToCheckFeasiblity(atoz,ztoa,gnpy)) {
184                     setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
185                     return;
186                 }
187                 callGnpyToComputeNewPath(gnpy);
188             } else {
189                 setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
190             }
191         }
192         catch (GnpyException e) {
193             LOG.error("Exception raised by GNPy {}",e.getMessage());
194             setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
195         }
196     }
197
198     private boolean gnpyToCheckFeasiblity(AToZDirection atoz, ZToADirection ztoa, GnpyUtilitiesImpl gnpy)
199             throws GnpyException {
200
201         //Call GNPy for path verification
202         if (gnpy.verifyComputationByGnpy(atoz, ztoa, pceHardConstraints)) {
203             LOG.info("In pceSendingPceRPC: the path is feasible according to Gnpy");
204             gnpyAtoZ = gnpy.getGnpyAtoZ();
205             gnpyZtoA = gnpy.getGnpyZtoA();
206             return true;
207         }
208         return false;
209     }
210
211     private void callGnpyToComputeNewPath(GnpyUtilitiesImpl gnpy) throws GnpyException {
212
213         //Call GNPy in the case of non feasibility
214         LOG.info("In pceSendingPceRPC: the path is not feasible according to Gnpy");
215         HardConstraints gnpyPathAsHC = null;
216         gnpyPathAsHC = gnpy.askNewPathFromGnpy(pceHardConstraints);
217         if (gnpyPathAsHC == null) {
218             LOG.info("In pceSendingPceRPC: GNPy failed to find another path");
219             this.success = false;
220             this.message = "No path available by PCE and GNPy ";
221             this.responseCode = ResponseCodes.RESPONSE_FAILED;
222             gnpyAtoZ = gnpy.getGnpyAtoZ();
223             gnpyZtoA = gnpy.getGnpyZtoA();
224             return;
225         }
226
227         LOG.info("In pceSendingPceRPC: GNPy succeed to find another path");
228         // Compute the path
229         PathComputationRequestInput inputFromGnpy = new PathComputationRequestInputBuilder()
230             .setServiceName(input.getServiceName())
231             .setHardConstraints(gnpyPathAsHC)
232             .setSoftConstraints(input.getSoftConstraints())
233             .setPceRoutingMetric(PceMetric.HopCount)
234             .setServiceAEnd(input.getServiceAEnd())
235             .setServiceZEnd(input.getServiceZEnd())
236             .build();
237         PceConstraintsCalc constraintsGnpy = new PceConstraintsCalc(inputFromGnpy, networkTransaction);
238         PceConstraints gnpyHardConstraints = constraintsGnpy.getPceHardConstraints();
239         PceConstraints gnpySoftConstraints = constraintsGnpy.getPceSoftConstraints();
240         pathComputationWithConstraints(gnpyHardConstraints, gnpySoftConstraints, PceConstraintMode.Strict);
241         AToZDirection atoz = rc.getAtoZDirection();
242         ZToADirection ztoa = rc.getZtoADirection();
243         if (gnpyToCheckFeasiblity(atoz, ztoa,gnpy)) {
244             LOG.info("In pceSendingPceRPC: the new path computed by GNPy is valid");
245             this.success = true;
246             this.message = "Path is calculated by GNPy";
247             this.responseCode = ResponseCodes.RESPONSE_OK;
248             setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
249         } else {
250             LOG.info("In pceSendingPceRPC: the new path computed by GNPy is not valid");
251             this.success = false;
252             this.message = "No path available";
253             this.responseCode = ResponseCodes.RESPONSE_FAILED;
254             setPathDescription(new PathDescriptionBuilder().setAToZDirection(null).setZToADirection(null));
255         }
256     }
257
258     private PceGraph patchRerunGraph(PceGraph graph) {
259         LOG.info("In pathComputation patchRerunGraph : rerun Graph with metric = PROPAGATION-DELAY ");
260         graph.setConstrains(pceHardConstraints);
261         graph.calcPath();
262         return graph;
263     }
264
265     public PathDescriptionBuilder getPathDescription() {
266         return pathDescription;
267     }
268
269     private void setPathDescription(PathDescriptionBuilder pathDescription) {
270         this.pathDescription = pathDescription;
271     }
272
273     public Boolean getSuccess() {
274         return this.success;
275     }
276
277     public String getMessage() {
278         return this.message;
279     }
280
281     public String getResponseCode() {
282         return this.responseCode;
283     }
284
285     public GnpyResult getGnpyAtoZ() {
286         return gnpyAtoZ;
287     }
288
289     public GnpyResult getGnpyZtoA() {
290         return gnpyZtoA;
291     }
292 }