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