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