Fix PCE bug to select the path proposed by GNPy 54/108654/5
authorGilles Thouenon <gilles.thouenon@orange.com>
Wed, 25 Oct 2023 11:30:09 +0000 (13:30 +0200)
committerGilles Thouenon <gilles.thouenon@orange.com>
Thu, 9 Nov 2023 07:52:46 +0000 (08:52 +0100)
Introduce the "loose" or "strict" mode to differentiate two ways to
manage include node constraints: either the path must simply include
some nodes whatever the order of node inside the list is, or the path
must be exactly equal to the list of nodes.

JIRA: TRNSPRTPCE-769
Signed-off-by: Gilles Thouenon <gilles.thouenon@orange.com>
Change-Id: I34c0e3491fc341af3de0ff5b0dc702f40c7dd653

pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java
pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java
pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java
pce/src/test/java/org/opendaylight/transportpce/pce/graph/PceGraphTest.java

index 1319a8248bd402661392a71f5fbac63d26a56d7b..90a8862ddfb5776e9d8eacde8313fc33b2019a09 100644 (file)
@@ -22,6 +22,7 @@ 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.rev230925.PathComputationRequestInput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PathComputationRequestInputBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PceConstraintMode;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.path.computation.reroute.request.input.Endpoints;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.service.path.rpc.result.PathDescriptionBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.routing.constraints.rev221209.routing.constraints.HardConstraints;
@@ -108,7 +109,8 @@ public class PceSendingPceRPCs {
         LOG.info("cancelResourceReserve ...");
     }
 
-    public void pathComputationWithConstraints(PceConstraints hardConstraints, PceConstraints softConstraints) {
+    private void pathComputationWithConstraints(PceConstraints hardConstraints, PceConstraints softConstraints,
+            PceConstraintMode mode) {
 
         PceCalculation nwAnalizer = new PceCalculation(input, networkTransaction, hardConstraints, softConstraints, rc,
                 portMapping, endpoints);
@@ -122,7 +124,7 @@ public class PceSendingPceRPCs {
         LOG.info("PceGraph ...");
         PceGraph graph = new PceGraph(nwAnalizer.getaendPceNode(), nwAnalizer.getzendPceNode(),
                 nwAnalizer.getAllPceNodes(), nwAnalizer.getAllPceLinks(), hardConstraints, softConstraints,
-                rc, serviceType, networkTransaction);
+                rc, serviceType, networkTransaction, mode);
         graph.calcPath();
         rc = graph.getReturnStructure();
         if (!rc.getStatus()) {
@@ -159,7 +161,7 @@ public class PceSendingPceRPCs {
         PceConstraintsCalc constraints = new PceConstraintsCalc(input, networkTransaction);
         pceHardConstraints = constraints.getPceHardConstraints();
         pceSoftConstraints = constraints.getPceSoftConstraints();
-        pathComputationWithConstraints(pceHardConstraints, pceSoftConstraints);
+        pathComputationWithConstraints(pceHardConstraints, pceSoftConstraints, PceConstraintMode.Loose);
         this.success = rc.getStatus();
         this.message = rc.getMessage();
         this.responseCode = rc.getResponseCode();
@@ -233,7 +235,7 @@ public class PceSendingPceRPCs {
         PceConstraintsCalc constraintsGnpy = new PceConstraintsCalc(inputFromGnpy, networkTransaction);
         PceConstraints gnpyHardConstraints = constraintsGnpy.getPceHardConstraints();
         PceConstraints gnpySoftConstraints = constraintsGnpy.getPceSoftConstraints();
-        pathComputationWithConstraints(gnpyHardConstraints, gnpySoftConstraints);
+        pathComputationWithConstraints(gnpyHardConstraints, gnpySoftConstraints, PceConstraintMode.Strict);
         AToZDirection atoz = rc.getAtoZDirection();
         ZToADirection ztoa = rc.getZtoADirection();
         if (gnpyToCheckFeasiblity(atoz, ztoa,gnpy)) {
index 0a2d75fc67a6f43f1fe15e68ae6fe3c88344cc79..dbd4111b2e838f38ceaa802167f5d87ca11333ef 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.transportpce.pce.networkanalyzer.PceLink;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult.LocalCause;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PceConstraintMode;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
@@ -55,6 +56,7 @@ public class PceGraph {
     private Double margin = null;
     PceConstraints pceHardConstraints;
     PceConstraints pceSoftConstraints;
+    private PceConstraintMode pceConstraintMode;
 
     // results
     private PceResult pceResult = null;
@@ -69,7 +71,8 @@ public class PceGraph {
 
     public PceGraph(PceNode aendNode, PceNode zendNode, Map<NodeId, PceNode> allPceNodes,
             Map<LinkId, PceLink> allPceLinks, PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints,
-            PceResult pceResult, String serviceType, NetworkTransactionService networkTransactionService) {
+            PceResult pceResult, String serviceType, NetworkTransactionService networkTransactionService,
+            PceConstraintMode mode) {
         super();
         this.apceNode = aendNode;
         this.zpceNode = zendNode;
@@ -80,6 +83,7 @@ public class PceGraph {
         this.pceSoftConstraints = pceSoftConstraints;
         this.serviceType = serviceType;
         this.networkTransactionService = networkTransactionService;
+        this.pceConstraintMode = mode;
 
         LOG.info("In GraphCalculator: A and Z = {} / {} ", aendNode, zendNode);
         LOG.debug("In GraphCalculator: allPceNodes size {}, nodes {} ", allPceNodes.size(), allPceNodes);
@@ -104,7 +108,8 @@ public class PceGraph {
             GraphPath<String, PceGraphEdge> path = entry.getValue();
             LOG.info("validating path n° {} - {}", entry.getKey(), path.getVertexList());
             PostAlgoPathValidator papv = new PostAlgoPathValidator(networkTransactionService);
-            pceResult = papv.checkPath(path, allPceNodes, allPceLinks, pceResult, pceHardConstraints, serviceType);
+            pceResult = papv.checkPath(
+                    path, allPceNodes, allPceLinks, pceResult, pceHardConstraints, serviceType, pceConstraintMode);
             this.margin = papv.getTpceCalculatedMargin();
             if (ResponseCodes.RESPONSE_OK.equals(pceResult.getResponseCode())) {
                 LOG.info("Path is validated");
index cf4c7e9bbbc7822ce458313affba31f3a2f7f004..7a3124b492d47be49466fccd436ac521d70d8422 100644 (file)
@@ -16,8 +16,10 @@ import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
 import org.jgrapht.GraphPath;
@@ -36,6 +38,7 @@ import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair
 import org.opendaylight.transportpce.pce.networkanalyzer.PceLink;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PceConstraintMode;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.SpectrumAssignment;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.SpectrumAssignmentBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev230526.TerminationPoint1;
@@ -55,6 +58,7 @@ public class PostAlgoPathValidator {
 
     public static final Long CONST_OSNR = 1L;
     public static final double SYS_MARGIN = 0;
+
     private Double tpceCalculatedMargin = 0.0;
     private final NetworkTransactionService networkTransactionService;
 
@@ -68,7 +72,7 @@ public class PostAlgoPathValidator {
         justification = "intentional fallthrough")
     public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
             Map<LinkId, PceLink> allPceLinks, PceResult pceResult, PceConstraints pceHardConstraints,
-            String serviceType) {
+            String serviceType, PceConstraintMode mode) {
         LOG.info("path = {}", path);
         // check if the path is empty
         if (path.getEdgeList().isEmpty()) {
@@ -139,7 +143,7 @@ public class PostAlgoPathValidator {
                     return pceResult;
                 }
                 // Check if nodes are included in the hard constraints
-                if (!checkInclude(path, pceHardConstraints)) {
+                if (!checkInclude(path, pceHardConstraints, mode)) {
                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
                     pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE);
                     return pceResult;
@@ -202,15 +206,17 @@ public class PostAlgoPathValidator {
     }
 
     // Check the inclusion if it is defined in the hard constraints
-    private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput) {
-        List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude()
-            .stream().sorted((rp1, rp2) -> rp1.getName().compareTo(rp2.getName()))
-            .collect(Collectors.toList());
+    //TODO: remove this checkstyle false positive warning when the checkstyle bug will be fixed
+    @SuppressWarnings("MissingSwitchDefault")
+    private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput,
+            PceConstraintMode mode) {
+        List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude();
         if (listToInclude.isEmpty()) {
             return true;
         }
         List<PceGraphEdge> pathEdges = path.getEdgeList();
         LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList());
+        LOG.debug("listToInclude = {}", listToInclude);
         List<String> listOfElementsSubNode = new ArrayList<>();
         listOfElementsSubNode.add(pathEdges.get(0).link().getsourceNetworkSupNodeId());
         listOfElementsSubNode.addAll(
@@ -225,10 +231,17 @@ public class PostAlgoPathValidator {
         listOfElementsSRLG.addAll(
             listOfElementsBuild(pathEdges, PceConstraints.ResourceType.SRLG, pceHardConstraintsInput));
         // validation: check each type for each element
-        return listOfElementsSubNode.containsAll(
-                listToInclude
-                    .stream().filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
-                    .map(ResourcePair::getName).collect(Collectors.toList()))
+        LOG.debug("listOfElementsSubNode = {}", listOfElementsSubNode);
+        return switch (mode) {
+            case Loose -> listOfElementsSubNode
+                .containsAll(listToInclude.stream()
+                    .filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
+                    .map(ResourcePair::getName).collect(Collectors.toList()));
+            case Strict -> listOfElementsSubNode
+                .equals(listToInclude.stream()
+                    .filter(rp -> PceConstraints.ResourceType.NODE.equals(rp.getType()))
+                    .map(ResourcePair::getName).collect(Collectors.toList()));
+        }
             && listOfElementsSRLG.containsAll(
                 listToInclude
                     .stream().filter(rp -> PceConstraints.ResourceType.SRLG.equals(rp.getType()))
@@ -241,7 +254,7 @@ public class PostAlgoPathValidator {
 
     private List<String> listOfElementsBuild(List<PceGraphEdge> pathEdges, PceConstraints.ResourceType type,
             PceConstraints pceHardConstraints) {
-        List<String> listOfElements = new ArrayList<>();
+        Set<String> listOfElements = new LinkedHashSet<>();
         for (PceGraphEdge link : pathEdges) {
             switch (type) {
                 case NODE:
@@ -277,7 +290,7 @@ public class PostAlgoPathValidator {
                     LOG.debug("listOfElementsBuild unsupported resource type");
             }
         }
-        return listOfElements;
+        return new ArrayList<>(listOfElements);
     }
 
     private Map<String, Uint16> chooseTribPort(GraphPath<String,
index 44d2e8b3eeaa9d8139d7b9910d9788fdc22f8332..1a3297bc9161ef4fd8cdc238724d544a584412bc 100644 (file)
@@ -58,6 +58,7 @@ import org.opendaylight.transportpce.test.stub.MountPointServiceStub;
 import org.opendaylight.transportpce.test.stub.MountPointStub;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PathComputationRequestInput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PathComputationRequestInputBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PceConstraintMode;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.path.computation.request.input.ServiceAEndBuilder;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.path.computation.request.input.ServiceZEndBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.port.PortBuilder;
@@ -248,7 +249,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(3.0919881995992924));
     }
@@ -261,7 +262,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_OTUC2, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_OTUC2, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(1.1559963686478447));
     }
@@ -274,7 +275,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_OTUC3, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_OTUC3, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(0.3351048800367167));
     }
@@ -287,7 +288,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), false);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(0.0));
     }
@@ -300,7 +301,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_400GE, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(1.4432381874659086));
     }
@@ -313,7 +314,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(1.4432381874659086));
     }
@@ -326,7 +327,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_OTUC4, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(0.0));
     }
@@ -339,7 +340,7 @@ public class PceGraphTest extends AbstractTest {
         pceCalc.retrievePceNetwork();
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ, PceConstraintMode.Loose);
         assertEquals(pceGraph.calcPath(), true);
         assertEquals(Optional.ofNullable(pceGraph.getmargin()), Optional.ofNullable(3.0919881995992924));
     }
@@ -353,7 +354,7 @@ public class PceGraphTest extends AbstractTest {
         pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay);
         pceGraph = new PceGraph(pceCalc.getaendPceNode(), pceCalc.getzendPceNode(),
             pceCalc.getAllPceNodes(), pceCalc.getAllPceLinks(), pceHardConstraints,
-            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ);
+            null, rc, StringConstants.SERVICE_TYPE_100GE_T, netTransServ, PceConstraintMode.Loose);
         pceGraph.setConstrains(pceHardConstraints, null);
 
         assertEquals(pceGraph.calcPath(), true);
@@ -416,7 +417,7 @@ public class PceGraphTest extends AbstractTest {
             new NodeId("optical"), pceOtnNode,
             new NodeId("optical2"), pceOtnNode2);
         return new PceGraph(pceOtnNode, pceOtnNode2, allPceNodes, allPceLinks, pceHardConstraints, null,
-                new PceResult(), type, null);
+                new PceResult(), type, null, PceConstraintMode.Loose);
     }
 
     private void saveOpenRoadmNetwork(Network network, String networkId)