package org.opendaylight.transportpce.pce;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.transportpce.pce.PceResult.LocalCause;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.service.path.rpc.result.PathDescriptionBuilder;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.AToZDirection;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ZToADirection;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.RoutingConstraintsSp.PceMetric;
+import org.opendaylight.transportpce.common.ResponseCodes;
+import org.opendaylight.transportpce.common.mapping.PortMapping;
+import org.opendaylight.transportpce.common.network.NetworkTransactionService;
+import org.opendaylight.transportpce.pce.constraints.OperatorConstraints;
+import org.opendaylight.transportpce.pce.constraints.PceConstraints;
+import org.opendaylight.transportpce.pce.constraints.PceConstraintsCalc;
+import org.opendaylight.transportpce.pce.gnpy.GnpyException;
+import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
+import org.opendaylight.transportpce.pce.gnpy.GnpyUtilitiesImpl;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
+import org.opendaylight.transportpce.pce.graph.PceGraph;
+import org.opendaylight.transportpce.pce.networkanalyzer.PceCalculation;
+import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PathComputationRequestInputBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.PceConstraintMode;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.path.computation.reroute.request.input.Endpoints;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev240205.service.path.rpc.result.PathDescriptionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev221209.routing.constraints.HardConstraints;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.AToZDirection;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.path.description.ZToADirection;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.PceMetric;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Class for Sending
* PCE requests :
* - path-computation-request
+ * - path-computation-reroute
* - cancel-resource-reserve.
* @author Martial Coulibaly ( martial.coulibaly@gfi.com ) on behalf of Orange
*
* <code>false</code> cancelresourcereserve .
*/
private PathDescriptionBuilder pathDescription;
-
private PathComputationRequestInput input;
- private DataBroker dataBroker;
-
+ private NetworkTransactionService networkTransaction;
private PceConstraints pceHardConstraints = new PceConstraints();
private PceConstraints pceSoftConstraints = new PceConstraints();
+ private GnpyResult gnpyAtoZ;
+ private GnpyResult gnpyZtoA;
+ private Boolean success;
+ private String message;
+ private String responseCode;
+ private final GnpyConsumer gnpyConsumer;
+ private PortMapping portMapping;
+ // Define the termination points whose reservation status is not taken into account during the pruning process
+ private Endpoints endpoints;
- public PceSendingPceRPCs() {
+ public PceSendingPceRPCs(GnpyConsumer gnpyConsumer) {
setPathDescription(null);
-
this.input = null;
- this.dataBroker = null;
+ this.networkTransaction = null;
+ this.gnpyConsumer = gnpyConsumer;
}
- public PceSendingPceRPCs(PathComputationRequestInput input, DataBroker dataBroker) {
+ public PceSendingPceRPCs(PathComputationRequestInput input, NetworkTransactionService networkTransaction,
+ GnpyConsumer gnpyConsumer, PortMapping portMapping) {
+ this.gnpyConsumer = gnpyConsumer;
setPathDescription(null);
-
// TODO compliance check to check that input is not empty
this.input = input;
- this.dataBroker = dataBroker;
+ this.networkTransaction = networkTransaction;
+ this.portMapping = portMapping;
+ this.endpoints = null;
+ }
+
+ public PceSendingPceRPCs(PathComputationRequestInput input, NetworkTransactionService networkTransaction,
+ GnpyConsumer gnpyConsumer, PortMapping portMapping,
+ Endpoints endpoints) {
+ this.gnpyConsumer = gnpyConsumer;
+ setPathDescription(null);
+ this.input = input;
+ this.networkTransaction = networkTransaction;
+ this.portMapping = portMapping;
+ this.endpoints = endpoints;
}
public void cancelResourceReserve() {
+ success = false;
LOG.info("Wait for 10s til beginning the PCE cancelResourceReserve request");
try {
- Thread.sleep(10000); // sleep for 10s
+ // sleep for 10s
+ Thread.sleep(10000);
} catch (InterruptedException e) {
- LOG.error(e.toString());
+ LOG.error("in PCESendingPceRPC: ",e);
}
+ success = true;
LOG.info("cancelResourceReserve ...");
}
- public void pathComputation() {
- LOG.info("PathComputation ...");
-
- PceConstraintsCalc constraints = new PceConstraintsCalc(input, dataBroker);
- pceHardConstraints = constraints.getPceHardConstraints();
- pceSoftConstraints = constraints.getPceSoftConstraints();
-
+ private void pathComputationWithConstraints(PceConstraints hardConstraints, PceConstraints softConstraints,
+ PceConstraintMode mode) {
- LOG.info("nwAnalizer ...");
- PceCalculation nwAnalizer = new PceCalculation(input, dataBroker,
- pceHardConstraints, pceSoftConstraints, rc);
- nwAnalizer.calcPath();
+ PceCalculation nwAnalizer = new PceCalculation(input, networkTransaction, hardConstraints, softConstraints, rc,
+ portMapping, endpoints);
+ nwAnalizer.retrievePceNetwork();
rc = nwAnalizer.getReturnStructure();
+ String serviceType = nwAnalizer.getServiceType();
if (!rc.getStatus()) {
- LOG.error("In pathComputation nwAnalizer: result = {}", rc.toString());
+ LOG.error("In pathComputationWithConstraints, nwAnalizer: result = {}", rc);
return;
}
-
+ OperatorConstraints opConstraints = new OperatorConstraints(networkTransaction);
LOG.info("PceGraph ...");
- LOG.warn("PathComputation: aPceNode '{}' - zPceNode '{}'", nwAnalizer.getaPceNode(), nwAnalizer.getzPceNode());
- PceGraph graph = new PceGraph(
- nwAnalizer.getaPceNode(),
- nwAnalizer.getzPceNode(),
- nwAnalizer.getAllPceNodes(),
- pceHardConstraints, pceSoftConstraints, rc);
+ PceGraph graph = new PceGraph(nwAnalizer.getaendPceNode(), nwAnalizer.getzendPceNode(),
+ nwAnalizer.getAllPceNodes(), nwAnalizer.getAllPceLinks(), hardConstraints,
+ rc, serviceType, networkTransaction, mode, opConstraints.getBitMapConstraint(input.getCustomerName()));
graph.calcPath();
rc = graph.getReturnStructure();
if (!rc.getStatus()) {
-
- LOG.warn("In pathComputation : Graph return without Path ");
-
+ LOG.warn("In pathComputationWithConstraints : Graph return without Path ");
// TODO fix. This is quick workaround for algorithm problem
- if ((rc.getLocalCause() == LocalCause.TOO_HIGH_LATENCY)
- && (pceHardConstraints.getPceMetrics() == PceMetric.HopCount)
- && (pceHardConstraints.getMaxLatency() != -1)) {
+ if ((rc.getLocalCause() == PceResult.LocalCause.TOO_HIGH_LATENCY)
+ && (hardConstraints.getPceMetrics() == PceMetric.HopCount)
+ && (hardConstraints.getMaxLatency() != -1)) {
+ hardConstraints.setPceMetrics(PceMetric.PropagationDelay);
+ graph = patchRerunGraph(graph);
+ }
- pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay);
+ if (rc.getLocalCause() == PceResult.LocalCause.HD_NODE_INCLUDE) {
+ graph.setKpathsToBring(graph.getKpathsToBring() * 10);
graph = patchRerunGraph(graph);
}
if (!rc.getStatus()) {
- LOG.error("In pathComputation graph.calcPath: result = {}", rc.toString());
+ LOG.error("In pathComputationWithConstraints, graph.calcPath: result = {}", rc);
return;
}
}
-
LOG.info("PcePathDescription ...");
- PcePathDescription description = new PcePathDescription(
- graph.getPathAtoZ(),
- nwAnalizer.getAllPceLinks(), rc);
+ PcePathDescription description = new PcePathDescription(graph.getPathAtoZ(), nwAnalizer.getAllPceLinks(), rc);
description.buildDescriptions();
rc = description.getReturnStructure();
if (!rc.getStatus()) {
- LOG.error("In pathComputation description: result = {}", rc.toString());
+ LOG.error("In pathComputationWithConstraints, description: result = {}", rc);
+ }
+ }
+
+ public void pathComputation() throws Exception {
+
+ PceConstraintsCalc constraints = new PceConstraintsCalc(input, networkTransaction);
+ pceHardConstraints = constraints.getPceHardConstraints();
+ pceSoftConstraints = constraints.getPceSoftConstraints();
+ pathComputationWithConstraints(pceHardConstraints, pceSoftConstraints, PceConstraintMode.Loose);
+ this.success = rc.getStatus();
+ this.message = rc.getMessage();
+ this.responseCode = rc.getResponseCode();
+
+ AToZDirection atoz = null;
+ ZToADirection ztoa = null;
+ if (rc.getStatus()) {
+ atoz = rc.getAtoZDirection();
+ ztoa = rc.getZtoADirection();
+ }
+
+ //Connect to Gnpy to check path feasibility and recompute another path in case of path non-feasibility
+ try {
+ if (gnpyConsumer.isAvailable()) {
+ GnpyUtilitiesImpl gnpy = new GnpyUtilitiesImpl(networkTransaction, input,
+ gnpyConsumer);
+ if (rc.getStatus() && gnpyToCheckFeasiblity(atoz,ztoa,gnpy)) {
+ setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
+ return;
+ }
+ callGnpyToComputeNewPath(gnpy);
+ } else {
+ setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
+ }
+ }
+ catch (GnpyException e) {
+ LOG.error("Exception raised by GNPy {}",e.getMessage());
+ setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
+ }
+ }
+
+ private boolean gnpyToCheckFeasiblity(AToZDirection atoz, ZToADirection ztoa, GnpyUtilitiesImpl gnpy)
+ throws GnpyException {
+
+ //Call GNPy for path verification
+ if (gnpy.verifyComputationByGnpy(atoz, ztoa, pceHardConstraints)) {
+ LOG.info("In pceSendingPceRPC: the path is feasible according to Gnpy");
+ gnpyAtoZ = gnpy.getGnpyAtoZ();
+ gnpyZtoA = gnpy.getGnpyZtoA();
+ return true;
+ }
+ return false;
+ }
+
+ private void callGnpyToComputeNewPath(GnpyUtilitiesImpl gnpy) throws GnpyException {
+
+ //Call GNPy in the case of non feasibility
+ LOG.info("In pceSendingPceRPC: the path is not feasible according to Gnpy");
+ HardConstraints gnpyPathAsHC = null;
+ gnpyPathAsHC = gnpy.askNewPathFromGnpy(pceHardConstraints);
+ if (gnpyPathAsHC == null) {
+ LOG.info("In pceSendingPceRPC: GNPy failed to find another path");
+ this.success = false;
+ this.message = "No path available by PCE and GNPy ";
+ this.responseCode = ResponseCodes.RESPONSE_FAILED;
+ gnpyAtoZ = gnpy.getGnpyAtoZ();
+ gnpyZtoA = gnpy.getGnpyZtoA();
return;
}
- LOG.info("setPathDescription ...");
+ LOG.info("In pceSendingPceRPC: GNPy succeed to find another path");
+ // Compute the path
+ PathComputationRequestInput inputFromGnpy = new PathComputationRequestInputBuilder()
+ .setServiceName(input.getServiceName())
+ .setHardConstraints(gnpyPathAsHC)
+ .setSoftConstraints(input.getSoftConstraints())
+ .setPceRoutingMetric(PceMetric.HopCount)
+ .setServiceAEnd(input.getServiceAEnd())
+ .setServiceZEnd(input.getServiceZEnd())
+ .build();
+ PceConstraintsCalc constraintsGnpy = new PceConstraintsCalc(inputFromGnpy, networkTransaction);
+ PceConstraints gnpyHardConstraints = constraintsGnpy.getPceHardConstraints();
+ PceConstraints gnpySoftConstraints = constraintsGnpy.getPceSoftConstraints();
+ pathComputationWithConstraints(gnpyHardConstraints, gnpySoftConstraints, PceConstraintMode.Strict);
AToZDirection atoz = rc.getAtoZDirection();
ZToADirection ztoa = rc.getZtoADirection();
- if ((atoz == null) || (atoz.getAToZ() == null)) {
- rc.setRC("400");
- LOG.error("In pathComputation empty atoz path after description: result = {}", rc.toString());
- return;
+ if (gnpyToCheckFeasiblity(atoz, ztoa,gnpy)) {
+ LOG.info("In pceSendingPceRPC: the new path computed by GNPy is valid");
+ this.success = true;
+ this.message = "Path is calculated by GNPy";
+ this.responseCode = ResponseCodes.RESPONSE_OK;
+ setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
+ } else {
+ LOG.info("In pceSendingPceRPC: the new path computed by GNPy is not valid");
+ this.success = false;
+ this.message = "No path available";
+ this.responseCode = ResponseCodes.RESPONSE_FAILED;
+ setPathDescription(new PathDescriptionBuilder().setAToZDirection(null).setZToADirection(null));
}
- if ((ztoa == null) || (ztoa.getZToA() == null)) {
- rc.setRC("400");
- LOG.error("In pathComputation empty ztoa path after description: result = {}", rc.toString());
- return;
- }
- setPathDescription(new PathDescriptionBuilder()
- .setAToZDirection(atoz)
- .setZToADirection(ztoa));
- LOG.info("In pathComputation Graph is Found");
}
private PceGraph patchRerunGraph(PceGraph graph) {
LOG.info("In pathComputation patchRerunGraph : rerun Graph with metric = PROPAGATION-DELAY ");
- graph.setConstrains(pceHardConstraints, pceSoftConstraints);
+ graph.setConstrains(pceHardConstraints);
graph.calcPath();
return graph;
-
}
public PathDescriptionBuilder getPathDescription() {
}
public Boolean getSuccess() {
- return rc.getStatus();
+ return this.success;
}
public String getMessage() {
- return rc.getMessage();
+ return this.message;
}
public String getResponseCode() {
- return rc.getResponseCode();
+ return this.responseCode;
}
+ public GnpyResult getGnpyAtoZ() {
+ return gnpyAtoZ;
+ }
+
+ public GnpyResult getGnpyZtoA() {
+ return gnpyZtoA;
+ }
}