From 1f526e901ac556cff9914b3c001c852db3b555e4 Mon Sep 17 00:00:00 2001 From: Gilles Thouenon Date: Wed, 25 Oct 2023 13:30:09 +0200 Subject: [PATCH] Fix PCE bug to select the path proposed by GNPy 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 Change-Id: I34c0e3491fc341af3de0ff5b0dc702f40c7dd653 --- .../transportpce/pce/PceSendingPceRPCs.java | 10 +++-- .../transportpce/pce/graph/PceGraph.java | 9 ++++- .../pce/graph/PostAlgoPathValidator.java | 37 +++++++++++++------ .../transportpce/pce/graph/PceGraphTest.java | 21 ++++++----- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java index 1319a8248..90a8862dd 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java @@ -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)) { diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java index 0a2d75fc6..dbd4111b2 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PceGraph.java @@ -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 allPceNodes, Map 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 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"); diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java index cf4c7e9bb..7a3124b49 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/PostAlgoPathValidator.java @@ -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 path, Map allPceNodes, Map 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 path, PceConstraints pceHardConstraintsInput) { - List 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 path, PceConstraints pceHardConstraintsInput, + PceConstraintMode mode) { + List listToInclude = pceHardConstraintsInput.getListToInclude(); if (listToInclude.isEmpty()) { return true; } List pathEdges = path.getEdgeList(); LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList()); + LOG.debug("listToInclude = {}", listToInclude); List 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 listOfElementsBuild(List pathEdges, PceConstraints.ResourceType type, PceConstraints pceHardConstraints) { - List listOfElements = new ArrayList<>(); + Set 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 chooseTribPort(GraphPath