From aafa2ea596dc9ea93b5ce5a7156ae68acf4b403f Mon Sep 17 00:00:00 2001 From: Olivier Renais Date: Wed, 23 Oct 2019 15:29:13 +0200 Subject: [PATCH] PCE OTN layer support init -Add PceOtnNode Class and complete PceLinkClass -Add Algorithm in PceCalculation and PceGraph to handle path calculation at the WDM or OTN layer -Adapt InAlgoPathValidator to work with the OTN layer -Adapt PostAlgoPathValidator with method to retrieve trib-port/slot in place of wavelengths CAUTION: at that time, it does not handle trib-slot and trib-port pass to Service Handler (still based on old path-computation-request) -Adapt PCE functional tests -change topo to include supporting nodes CAUTION: Expected node in rpc path-computation-request is of OTN type JIRA: TRNSPRTPCE-162 Signed-off-by: Olivier Renais Co-authored-by: Gilles Thouenon Co-authored-by: Christophe Betoule Change-Id: If5c29cae48b94660f2536f86b2df814b6515969b --- .../transportpce/pce/PceSendingPceRPCs.java | 5 +- .../pce/graph/InAlgoPathValidator.java | 3 +- .../transportpce/pce/graph/PceGraph.java | 26 +- .../pce/graph/PostAlgoPathValidator.java | 226 ++++++-- .../pce/networkanalyzer/MapUtils.java | 87 ++- .../pce/networkanalyzer/PceCalculation.java | 399 +++++++++----- .../pce/networkanalyzer/PceLink.java | 89 ++- .../pce/networkanalyzer/PceNode.java | 66 ++- .../pce/networkanalyzer/PceOtnNode.java | 506 ++++++++++++++++++ .../pce/networkanalyzer/PceResult.java | 10 + tests/sample_configs/honeynode-topo.xml | 44 +- tests/transportpce_tests/1.2.1/test_pce.py | 62 ++- 12 files changed, 1308 insertions(+), 215 deletions(-) mode change 100755 => 100644 pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOtnNode.java diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java old mode 100755 new mode 100644 index e8f0f9aac..064140cb6 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java @@ -93,14 +93,15 @@ public class PceSendingPceRPCs { new PceCalculation(input, networkTransaction, hardConstraints, softConstraints, rc); nwAnalizer.retrievePceNetwork(); rc = nwAnalizer.getReturnStructure(); + String serviceType = nwAnalizer.getServiceType(); if (!rc.getStatus()) { LOG.error("In pathComputationWithConstraints, nwAnalizer: result = {}", rc.toString()); return; } LOG.info("PceGraph ..."); PceGraph graph = new PceGraph(nwAnalizer.getaendPceNode(), - nwAnalizer.getzendPceNode(), nwAnalizer.getAllPceNodes(), - hardConstraints, softConstraints, rc); + nwAnalizer.getzendPceNode(), nwAnalizer.getAllPceNodes(), + pceHardConstraints, pceSoftConstraints, rc, serviceType); graph.calcPath(); rc = graph.getReturnStructure(); if (!rc.getStatus()) { diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/InAlgoPathValidator.java b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/InAlgoPathValidator.java index 963ce4564..92ffaea23 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/graph/InAlgoPathValidator.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/graph/InAlgoPathValidator.java @@ -11,6 +11,7 @@ package org.opendaylight.transportpce.pce.graph; import org.jgrapht.GraphPath; import org.jgrapht.alg.shortestpath.PathValidator; import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType; +//import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,5 +73,5 @@ public class InAlgoPathValidator implements PathValidator return true; } +} -} \ No newline at end of file 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 3f2210b53..c7733ddd5 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 @@ -44,6 +44,7 @@ public class PceGraph { private Map allPceNodes = new HashMap(); private PceNode apceNode = null; private PceNode zpceNode = null; + private String serviceType = ""; PceConstraints pceHardConstraints; PceConstraints pceSoftConstraints; @@ -58,7 +59,8 @@ public class PceGraph { private List pathAtoZ = new ArrayList(); public PceGraph(PceNode aendNode, PceNode zendNode, Map allPceNodes, - PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints, PceResult pceResult) { + PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints, PceResult pceResult, + String serviceType) { super(); this.apceNode = aendNode; this.zpceNode = zendNode; @@ -66,6 +68,7 @@ public class PceGraph { this.pceResult = pceResult; this.pceHardConstraints = pceHardConstraints; this.pceSoftConstraints = pceSoftConstraints; + this.serviceType = serviceType; LOG.info("In GraphCalculator: A and Z = {} / {} ", aendNode.toString(), zendNode.toString()); LOG.debug("In GraphCalculator: allPceNodes size {}, nodes {} ", allPceNodes.size(), allPceNodes.toString()); @@ -89,7 +92,7 @@ public class PceGraph { pceResult.setRC(ResponseCodes.RESPONSE_FAILED); for (GraphPath path : allWPaths) { PostAlgoPathValidator papv = new PostAlgoPathValidator(); - pceResult = papv.checkPath(path, allPceNodes, pceResult, pceHardConstraints); + pceResult = papv.checkPath(path, allPceNodes, pceResult, pceHardConstraints, serviceType); LOG.info("In calcPath after PostAlgoPathValidator {} {}", pceResult.getResponseCode(), ResponseCodes.RESPONSE_OK); @@ -105,9 +108,17 @@ public class PceGraph { } shortestPathAtoZ = new ArrayList<>(pathAtoZ); - LOG.info("In calcPath Path FOUND path for wl [{}], hops {}, distance per metrics {}, path AtoZ {}", - pceResult.getResultWavelength(), pathAtoZ.size(), path.getWeight(), pathAtoZ.toString()); - break; + if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) { + LOG.info("In calcPath Path FOUND path for wl [{}], hops {}, distance per metrics {}, path AtoZ {}", + pceResult.getResultWavelength(), pathAtoZ.size(), path.getWeight(), pathAtoZ.toString()); + break; + } else { + // Service is at OTN layer and is relying on a supporting wavelength service + LOG.info("In calcPath Path FOUND path for hops {}, distance per metrics {}, path AtoZ {}", + pathAtoZ.size(), path.getWeight(), pathAtoZ.toString()); + break; + } + } if (shortestPathAtoZ != null) { @@ -222,6 +233,11 @@ public class PceGraph { case PropagationDelay : weight = link.getLatency(); LOG.debug("In PceGraph PropagationDelay is used as a metrics. {}", link.toString()); + if ((("1GE".equals(serviceType)) || ("10GE".equals(serviceType)) || ("ODU4".equals(serviceType))) + && (weight == 0)) { + LOG.warn("PropagationDelay set as metric, but latency is null: is latency set for OTN link {}?", + link.toString()); + } break; default: 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 626895fd1..1d28a2dd2 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 @@ -17,6 +17,7 @@ import org.opendaylight.transportpce.common.ResponseCodes; import org.opendaylight.transportpce.pce.constraints.PceConstraints; import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair; import org.opendaylight.transportpce.pce.networkanalyzer.PceNode; +import org.opendaylight.transportpce.pce.networkanalyzer.PceOtnNode; import org.opendaylight.transportpce.pce.networkanalyzer.PceResult; import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId; @@ -35,56 +36,78 @@ public class PostAlgoPathValidator { public static final Long CONST_OSNR = 1L; public static final double SYS_MARGIN = 0; - public PceResult checkPath(GraphPath path, - Map allPceNodes, PceResult pceResult, PceConstraints pceHardConstraints) { + public PceResult checkPath(GraphPath path, Map allPceNodes, + PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) { - //check if the path is empty + // check if the path is empty if (path.getEdgeList().size() == 0) { pceResult.setRC(ResponseCodes.RESPONSE_FAILED); return pceResult; } + if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) { + // choose wavelength available in all nodes of the path + Long waveL = chooseWavelength(path, allPceNodes); + if (waveL < 0) { + pceResult.setRC(ResponseCodes.RESPONSE_FAILED); + pceResult.setLocalCause(PceResult.LocalCause.NO_PATH_EXISTS); + return pceResult; + } + pceResult.setResultWavelength(waveL); + LOG.info("In PostAlgoPathValidator: chooseWavelength WL found {} {}", waveL, path.toString()); - //Choose wavelength available in all nodes of the path - Long waveL = chooseWavelength(path, allPceNodes); - if (waveL < 0) { - pceResult.setRC(ResponseCodes.RESPONSE_FAILED); - pceResult.setLocalCause(PceResult.LocalCause.NO_PATH_EXISTS); - return pceResult; - } - pceResult.setResultWavelength(waveL); - LOG.info("In PostAlgoPathValidator: chooseWavelength WL found {} {}", waveL, path.toString()); + // TODO here other post algo validations can be added + // more data can be sent to PceGraph module via PceResult structure if required - // TODO here other post algo validations can be added - // more data can be sent to PceGraph module via PceResult structure if required + // Check the OSNR + if (!checkOSNR(path)) { + pceResult.setRC(ResponseCodes.RESPONSE_FAILED); + pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR); + return pceResult; + } - //Check the OSNR - if (!checkOSNR(path)) { - pceResult.setRC(ResponseCodes.RESPONSE_FAILED); - pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR); - return pceResult; - } + // Check if MaxLatency is defined in the hard constraints + if (pceHardConstraints.getMaxLatency() != -1) { + if (!checkLatency(pceHardConstraints.getMaxLatency(), path)) { + pceResult.setRC(ResponseCodes.RESPONSE_FAILED); + pceResult.setLocalCause(PceResult.LocalCause.TOO_HIGH_LATENCY); + return pceResult; + } + } - //Check if MaxLatency is defined in the hard constraints - if (pceHardConstraints.getMaxLatency() != -1) { - if (!checkLatency(pceHardConstraints.getMaxLatency(), path)) { + // Check if nodes are included in the hard constraints + if (!checkInclude(path, pceHardConstraints)) { pceResult.setRC(ResponseCodes.RESPONSE_FAILED); - pceResult.setLocalCause(PceResult.LocalCause.TOO_HIGH_LATENCY); + pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE); return pceResult; } - } + pceResult.setRC(ResponseCodes.RESPONSE_OK); - //Check if nodes are included in the hard constraints - if (!checkInclude(path, pceHardConstraints)) { + } else if (("1GE".equals(serviceType)) || ("10GE".equals(serviceType))) { + // Path is at the OTN layer pceResult.setRC(ResponseCodes.RESPONSE_FAILED); - pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE); - return pceResult; + // In a first step we select the first tribPort available on the first edge + // TODO : after the way to pass trib-ports and trib-slots to the renderer has + // been adapted to fit + // with multiple OTN Hops, each first available port shall be passed for each + // edge to Renderer + Integer tribPort = chooseTribPort(path, allPceNodes).get(0).get(0); + // TODO : Same comment apply for tribSlot + Integer tribSlot = chooseTribSlot(path, allPceNodes).get(0).get(0); + + if (tribPort != null) { + // Temporarily we use wavelength-number to provide the TribPort + // TODO adapt the path-description + // TODO make the adaptation to return the first tribSlot in an intermediate + // phase + pceResult.setResultWavelength(tribPort); + pceResult.setRC(ResponseCodes.RESPONSE_OK); + LOG.info("In PostAlgoPathValidator: chooseTribPort TribPort found {} {}", tribPort, path.toString()); + } } - - pceResult.setRC(ResponseCodes.RESPONSE_OK); return pceResult; } - //Choose the first available wavelength from the source to the destination + // Choose the first available wavelength from the source to the destination private Long chooseWavelength(GraphPath path, Map allPceNodes) { Long wavelength = -1L; @@ -107,14 +130,14 @@ public class PostAlgoPathValidator { return wavelength; } - //Check the latency + // Check the latency private boolean checkLatency(Long maxLatency, GraphPath path) { double latency = 0; for (PceGraphEdge edge : path.getEdgeList()) { try { latency += edge.link().getLatency(); - LOG.debug("- In checkLatency: latency of {} = {} units", edge.link().getLinkId().getValue(),latency); + LOG.debug("- In checkLatency: latency of {} = {} units", edge.link().getLinkId().getValue(), latency); } catch (NullPointerException e) { LOG.warn("- In checkLatency: the link {} does not contain latency field", edge.link().getLinkId().getValue()); @@ -126,7 +149,7 @@ public class PostAlgoPathValidator { return true; } - //Check the inclusion if it is defined in the hard constraints + // Check the inclusion if it is defined in the hard constraints private boolean checkInclude(GraphPath path, PceConstraints pceHardConstraintsInput) { List listToInclude = pceHardConstraintsInput.getListToInclude(); if (listToInclude.isEmpty()) { @@ -195,7 +218,7 @@ public class PostAlgoPathValidator { PceConstraints pceHardConstraints) { List listOfElements = new ArrayList(); - for (PceGraphEdge link: pathEdges) { + for (PceGraphEdge link : pathEdges) { switch (type) { case NODE: listOfElements.add(link.link().getdestSupNodeId()); @@ -209,14 +232,16 @@ public class PostAlgoPathValidator { break; } - // srlg of link is List. But in this algo we need string representation of one SRLG - // this should be any SRLG mentioned in include constraints if any of them if mentioned + // srlg of link is List. But in this algo we need string representation of + // one SRLG + // this should be any SRLG mentioned in include constraints if any of them if + // mentioned boolean found = false; for (Long srlg : link.link().getsrlgList()) { String srlgStr = String.valueOf(srlg); if (pceHardConstraints.getSRLGnames().contains(srlgStr)) { listOfElements.add(srlgStr); - LOG.info("listOfElementsBuild. FOUND SRLG {} in link {}", srlgStr, link.link().toString()); + LOG.info("listOfElementsBuild. FOUND SRLG {} in link {}", srlgStr, link.link()); found = true; continue; } @@ -233,7 +258,120 @@ public class PostAlgoPathValidator { return listOfElements; } - //Check the path OSNR + private List> chooseTribPort(GraphPath path, Map allPceNodes) { + List> tribPort = new ArrayList<>(); + boolean statusOK = true; + boolean check = false; + Object nodeClass = allPceNodes.getClass(); + if (nodeClass.getClass().isInstance(PceNode.class)) { + LOG.debug("In choosetribPort: AllPceNodes contains PceNode instance, no trib port search"); + return tribPort; + } else if (nodeClass.getClass().isInstance(PceOtnNode.class)) { + LOG.debug("In choosetribPort: {} {}", path.getLength(), path.toString()); + for (PceGraphEdge edge : path.getEdgeList()) { + LOG.debug("In chooseTribPort: source {} ", edge.link().getSourceId().toString()); + PceNode pceNode = allPceNodes.get(edge.link().getSourceId()); + Object tps = allPceNodes.get(edge.link().getSourceTP()); + Object tpd = allPceNodes.get(edge.link().getDestTP()); + if ((pceNode.getAvailableTribPorts().containsKey(tps.toString())) + && (pceNode.getAvailableTribPorts().containsKey(tpd.toString()))) { + + List tribPortEdgeSourceN = new ArrayList<>(); + List tribPortEdgeDestN = new ArrayList<>(); + tribPortEdgeSourceN = pceNode.getAvailableTribPorts().get(tps.toString()); + tribPortEdgeDestN = pceNode.getAvailableTribPorts().get(tps.toString()); + check = false; + for (int i = 0; i <= 9; i++) { + if (tribPortEdgeSourceN.get(i) == null) { + break; + } + if (tribPortEdgeSourceN.get(i) == tribPortEdgeDestN.get(i)) { + check = true; + } else { + check = false; + LOG.debug("In chooseTribPort: Misalignement of trib port between source {} and dest {}", + edge.link().getSourceId().toString(), edge.link().getDestId().toString()); + break; + } + } + if (check) { + tribPort.add(tribPortEdgeSourceN); + } + } else { + LOG.debug("In chooseTribPort: source {} does not have provisonned hosting HO interface ", + edge.link().getSourceId().toString()); + statusOK = false; + } + } + } + if (statusOK && check) { + return tribPort; + } else { + tribPort.clear(); + return tribPort; + } + + } + + private List> chooseTribSlot(GraphPath path, Map allPceNodes) { + List> tribSlot = new ArrayList<>(); + boolean statusOK = true; + boolean check = false; + Object nodeClass = allPceNodes.getClass(); + if (nodeClass.getClass().isInstance(PceNode.class)) { + LOG.debug("In choosetribSlot: AllPceNodes contains PceNode instance, no trib port search"); + return tribSlot; + } else if (nodeClass.getClass().isInstance(PceOtnNode.class)) { + LOG.debug("In choosetribPort: {} {}", path.getLength(), path.toString()); + for (PceGraphEdge edge : path.getEdgeList()) { + LOG.debug("In chooseTribSlot: source {} ", edge.link().getSourceId().toString()); + PceNode pceNode = allPceNodes.get(edge.link().getSourceId()); + Object tps = allPceNodes.get(edge.link().getSourceTP()); + Object tpd = allPceNodes.get(edge.link().getDestTP()); + if ((pceNode.getAvailableTribSlots().containsKey(tps.toString())) + && (pceNode.getAvailableTribSlots().containsKey(tpd.toString()))) { + + List tribSlotEdgeSourceN = new ArrayList<>(); + List tribSlotEdgeDestN = new ArrayList<>(); + tribSlotEdgeSourceN = pceNode.getAvailableTribSlots().get(tps.toString()); + tribSlotEdgeDestN = pceNode.getAvailableTribSlots().get(tps.toString()); + check = false; + for (int i = 0; i <= 79; i++) { + if (tribSlotEdgeSourceN.get(i) == null) { + break; + } + // TODO This will need to be modified as soon as the trib-slots allocation per + // trib-port + // policy applied by the different manufacturer is known + if (tribSlotEdgeSourceN.get(i) == tribSlotEdgeDestN.get(i)) { + check = true; + } else { + check = false; + LOG.debug("In chooseTribSlot: Misalignement of trib slots between source {} and dest {}", + edge.link().getSourceId().toString(), edge.link().getDestId().toString()); + break; + } + } + if (check) { + tribSlot.add(tribSlotEdgeSourceN); + } + } else { + LOG.debug("In chooseTribSlot: source {} does not have provisonned hosting HO interface ", + edge.link().getSourceId().toString()); + statusOK = false; + } + } + } + if (statusOK && check) { + return tribSlot; + } else { + tribSlot.clear(); + return tribSlot; + } + + } + + // Check the path OSNR private boolean checkOSNR(GraphPath path) { double linkOsnrDb; double osnrDb = 0; @@ -251,8 +389,7 @@ public class PostAlgoPathValidator { } try { osnrDb = getOsnrDb(1 / inverseLocalOsnr); - } - catch (ArithmeticException e) { + } catch (ArithmeticException e) { LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}", path.getEdgeList().size()); return false; } @@ -260,6 +397,9 @@ public class PostAlgoPathValidator { if ((osnrDb + SYS_MARGIN) < MIN_OSNR_W100G) { return false; } + double localOsnr = 0L; + LOG.info("In OSNR Stub: {}", localOsnr); + // TODO : change this to return OSNR value and validate or invalidate the path return true; } @@ -277,4 +417,4 @@ public class PostAlgoPathValidator { return (CONST_OSNR / linkOsnrLu); } -} \ No newline at end of file +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/MapUtils.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/MapUtils.java index e6b9e3a4c..54868a35e 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/MapUtils.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/MapUtils.java @@ -10,11 +10,11 @@ package org.opendaylight.transportpce.pce.networkanalyzer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.TreeMap; import org.opendaylight.transportpce.common.NetworkUtils; import org.opendaylight.transportpce.pce.constraints.PceConstraints; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Link1; import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.span.attributes.LinkConcatenation; - import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.networks.network.link.oms.attributes.Span; import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node; @@ -92,6 +92,30 @@ public final class MapUtils { return srlgList; } + public static List getSRLGfromLink(Link link) { + List srlgList = new ArrayList(); + org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Link1 linkC = + link.augmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Link1.class); + if (linkC == null) { + LOG.error("MapUtils: No Link augmentation available. {}", link.getLinkId().getValue()); + + } else { + try { + List linkConcatenation = linkC.getLinkConcatenation(); + + + for (org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.networks.network.link + .LinkConcatenation lc : linkConcatenation) { + srlgList.add(lc.getSRLGId()); + } + } catch (NullPointerException e) { + LOG.debug("No concatenation for this link"); + } + } + return srlgList; + } + public static String getSupNode(Node node) { List supNodes = node.getSupportingNode(); for (SupportingNode snode : supNodes) { @@ -102,6 +126,67 @@ public final class MapUtils { return null; } + public static TreeMap getAllSupNode(Node node) { + TreeMap allSupNodes = new TreeMap(); + List supNodes = new ArrayList(); + try { + supNodes = node.getSupportingNode(); + } catch (NullPointerException e) { + LOG.debug("No Supporting Node for the node {}", node); + } + for (SupportingNode supnode :supNodes) { + allSupNodes.put(supnode.getNetworkRef().getValue(), + supnode.getNodeRef().getValue()); + } + return allSupNodes; + } + + public static String getSupLink(Link link) { + String supLink = ""; + try { + supLink = link.getSupportingLink().get(0).getLinkRef().toString(); + } catch (NullPointerException e) { + LOG.debug("No Supporting Link for the link {}", link); + } + return supLink; + } + + + public static Long getAvailableBandwidth(Link link) { + Link1 link1 = null; + Long availableBW = 0L; + // ID and type + link1 = link.augmentation(Link1.class); + if (link1 == null) { + LOG.error("MapUtils: No Link augmentation available. {}", link.getLinkId().getValue()); + return availableBW; + } else { + OpenroadmLinkType tmplType = null; + tmplType = link1.getLinkType(); + if (tmplType == null) { + LOG.error("MapUtils: No Link type available. {}", link.getLinkId().getValue()); + return null; + } else if (tmplType == OpenroadmLinkType.OTNLINK) { + org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.Link1 link11 = + link.augmentation( + org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.Link1.class); + if (link11 == null) { + LOG.error("MapUtils: No Link augmentation available for {}", link.getLinkId().getValue()); + return availableBW; + } else { + availableBW = link11.getAvailableBandwidth(); + return availableBW; + } + + } else { + LOG.error("MapUtils: Evaluated Link is not of OTN Type"); + } + } + + + return 0L; + } + public static OpenroadmLinkType calcType(Link link) { Link1 link1 = null; OpenroadmLinkType tmplType = null; diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceCalculation.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceCalculation.java index 7217b0c3a..61f288e00 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceCalculation.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceCalculation.java @@ -38,6 +38,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.top import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +//import org.opendaylight.yangtools.yang.common.Decimal64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,6 +51,10 @@ public class PceCalculation { private PathComputationRequestInput input; private String anodeId = ""; private String znodeId = ""; + private String serviceFormatA = ""; + private String serviceFormatZ = ""; + private String serviceType = ""; + private Long serviceRate = 0L; private PceConstraints pceHardConstraints; @@ -109,16 +114,71 @@ public class PceCalculation { private boolean parseInput() { anodeId = input.getServiceAEnd().getNodeId(); znodeId = input.getServiceZEnd().getNodeId(); + serviceFormatA = input.getServiceAEnd().getServiceFormat().getName(); + serviceFormatZ = input.getServiceZEnd().getServiceFormat().getName(); + serviceRate = input.getServiceAEnd().getServiceRate(); + LOG.info("parseInput: A and Z :[{}] and [{}]", anodeId, znodeId); + if (!(serviceFormatA.equals(serviceFormatZ))) { + LOG.info("parseInput: different service format for A and Z not handled, will use service format from Aend"); + } else if (serviceRate == 100L) { + switch (serviceFormatA) { + case "Ethernet": + case "OC": + serviceType = "100GE"; + break; + case "OTU": + serviceType = "OTU4"; + break; + case "ODU": + serviceType = "ODU4"; + break; + default: + LOG.debug("parseInput: unsupported service type: Format {} Rate 100L", serviceFormatA); + break; + } + //switch(serviceRate) may seem a better option at first glance. + //But switching on Long or long is not directly possible in Java. + //And casting to int bumps the limit here. + //Passing by ENUM or String are possible alternatives. + //Maybe HashMap and similar options should also be considered here. + } else if (serviceFormatA == "Ethernet") { + //only rate 100L is currently supported except in Ethernet + if (serviceRate == 10L) { + serviceType = "10GE"; + } else if (serviceRate == 1L) { + serviceType = "1GE"; + } else { + LOG.debug("parseInput: unsupported service type: Format Ethernet Rate {}", String.valueOf(serviceRate)); + } + } else { + LOG.debug("parseInput: unsupported service type: Format {} Rate {}", + serviceFormatA, String.valueOf(serviceRate)); + } + returnStructure.setRate(input.getServiceAEnd().getServiceRate()); + returnStructure.setServiceFormat(input.getServiceAEnd().getServiceFormat()); return true; } private boolean readMdSal() { - LOG.info("readMdSal: network {}", NetworkUtils.OVERLAY_NETWORK_ID); - InstanceIdentifier nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class) - .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + InstanceIdentifier nwInstanceIdentifier = null; Network nw = null; + if (("OC".equals(serviceFormatA)) || ("OTU".equals(serviceFormatA)) || (("Ethernet".equals(serviceFormatA)) + && (serviceRate == 100L))) { + + LOG.info("readMdSal: network {}", NetworkUtils.OVERLAY_NETWORK_ID); + nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + } else if ("ODU".equals(serviceFormatA)) { + LOG.info("readMdSal: network {}", NetworkUtils.OTN_NETWORK_ID); + nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID))).build(); + } else { + LOG.info("readMdSal: service-rate {} / service-format not handled {}", serviceRate, serviceFormatA); + return false; + } + try { Optional nwOptional = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier).get(); @@ -131,7 +191,7 @@ public class PceCalculation { networkTransactionService.close(); returnStructure.setRC(ResponseCodes.RESPONSE_FAILED); throw new RuntimeException( - "readMdSal: Error reading from operational store, topology : " + nwInstanceIdentifier + " :" + e); + "readMdSal: Error reading from operational store, topology : " + nwInstanceIdentifier + " :" + e); } networkTransactionService.close(); @@ -166,34 +226,66 @@ public class PceCalculation { LOG.debug("analyzeNw: allNodes size {}, allLinks size {}", allNodes.size(), allLinks.size()); - for (Node node : allNodes) { - validateNode(node); - } - LOG.debug("analyzeNw: allPceNodes size {}", allPceNodes.size()); - - if (aendPceNode == null || zendPceNode == null) { - LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network"); - return false; - } + if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) { + // 100GE service and OTU4 service are handled at the openroadm-topology layer + for (Node node : allNodes) { + validateNode(node); + } - for (Link link : allLinks) { - validateLink(link); - } + LOG.debug("analyzeNw: allPceNodes size {}", allPceNodes.size()); - LOG.debug("analyzeNw: addLinks size {}, dropLinks size {}", addLinks.size(), dropLinks.size()); + if (aendPceNode == null || zendPceNode == null) { + LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network"); + return false; + } + for (Link link : allLinks) { + validateLink(link); + } + // debug prints + LOG.debug("analyzeNw: addLinks size {}, dropLinks size {}", addLinks.size(), dropLinks.size()); + // debug prints + LOG.debug("analyzeNw: azSrgs size = {}", azSrgs.size()); + for (NodeId srg : azSrgs) { + LOG.debug("analyzeNw: A/Z Srgs SRG = {}", srg.getValue()); + } + // debug prints + for (PceLink link : addLinks) { + filteraddLinks(link); + } + for (PceLink link : dropLinks) { + filterdropLinks(link); + } - // debug prints - LOG.debug("analyzeNw: azSrgs size = {}", azSrgs.size()); - for (NodeId srg : azSrgs) { - LOG.debug("analyzeNw: A/Z Srgs SRG = {}", srg.getValue()); - } - // debug prints + } else { + // ODU4, 10GE/ODU2e or 1GE/ODU0 services are handled at openroadm-otn layer + OpenroadmNodeType typeOfNode = null; + for (Node node : allNodes) { + String nodeId = node.getNodeId().getValue(); + if (this.anodeId.equals(nodeId) || (this.znodeId.equals(nodeId))) { + typeOfNode = validateOtnNode(node, "AZ"); + } + } + if (typeOfNode == null) { + LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network"); + } else if (typeOfNode == OpenroadmNodeType.MUXPDR) { + LOG.debug("analyzeNw: A/Z end node are of muxponder type, no intermediate switch allowed on the path"); + } else { + LOG.debug("analyzeNw: A/Z end node are of switch type, searching for potential intermediate switch"); + for (Node node : allNodes) { + String nodeId = node.getNodeId().getValue(); + if (!(this.anodeId.equals(nodeId) || (this.znodeId.equals(nodeId)))) { + // A and Z node have been validated, then if A and Z end nodes are not muxponders + // we allow intermediate switch on the path + typeOfNode = validateOtnNode(node, "intermediate"); + } + // else : typeOfNode is MUXPDR and we do not authorize any intermediate switch on the path + // TODO : handle regens and authorize them on the path if needed + } + } - for (PceLink link : addLinks) { - filteraddLinks(link); - } - for (PceLink link : dropLinks) { - filterdropLinks(link); + for (Link link : allLinks) { + validateLink(link); + } } LOG.info("analyzeNw: allPceNodes size {}, allPceLinks size {}", allPceNodes.size(), allPceLinks.size()); @@ -260,87 +352,119 @@ public class PceCalculation { if (source == null) { LOG.debug("validateLink: Link is ignored due source node is rejected by node validation - {}", - link.getSource().getSourceNode().getValue()); + link.getSource().getSourceNode().getValue()); return false; } if (dest == null) { LOG.debug("validateLink: Link is ignored due dest node is rejected by node validation - {}", - link.getDestination().getDestNode().getValue()); + link.getDestination().getDestNode().getValue()); return false; } - PceLink pcelink = new PceLink(link, source, dest); - if (!pcelink.isValid()) { - dropOppositeLink(link); - LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link"); - return false; - } + if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) { + // 100GE or OTU4 services are handled at WDM Layer + PceLink pcelink = new PceLink(link, source, dest); + if (!pcelink.isValid()) { + dropOppositeLink(link); + LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link"); + return false; + } + LinkId linkId = pcelink.getLinkId(); + switch (validateLinkConstraints(pcelink)) { + case HARD_EXCLUDE: + dropOppositeLink(link); + LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue()); + return false; + default: + break; + } + switch (pcelink.getlinkType()) { + case ROADMTOROADM: + case EXPRESSLINK: + allPceLinks.put(linkId, pcelink); + source.addOutgoingLink(pcelink); + LOG.debug("validateLink: {}-LINK added to allPceLinks {}", + pcelink.getlinkType(), pcelink.toString()); + break; + case ADDLINK: + pcelink.setClient(source.getRdmSrgClient(pcelink.getSourceTP().toString(), true)); + addLinks.add(pcelink); + LOG.debug("validateLink: ADD-LINK saved {}", pcelink.toString()); + break; + case DROPLINK: + pcelink.setClient(dest.getRdmSrgClient(pcelink.getDestTP().toString(), false)); + dropLinks.add(pcelink); + LOG.debug("validateLink: DROP-LINK saved {}", pcelink.toString()); + break; + case XPONDERINPUT: + // store separately all SRG links directly + azSrgs.add(sourceId); + // connected to A/Z + if (!dest.checkTP(pcelink.getDestTP().toString())) { + LOG.debug( + "validateLink: XPONDER-INPUT is rejected as NW port is busy - {} ", pcelink.toString()); + return false; + } + pcelink.setClient(dest.getClient(pcelink.getDestTP().toString())); + allPceLinks.put(linkId, pcelink); + source.addOutgoingLink(pcelink); + LOG.debug("validateLink: XPONDER-INPUT link added to allPceLinks {}", pcelink.toString()); + break; + // does it mean XPONDER==>>SRG ? + case XPONDEROUTPUT: + // store separately all SRG links directly + azSrgs.add(destId); + // connected to A/Z + if (!source.checkTP(pcelink.getSourceTP().toString())) { + LOG.debug( + "validateLink: XPONDER-OUTPUT is rejected as NW port is busy - {} ", pcelink.toString()); + return false; + } + pcelink.setClient(source.getClient(pcelink.getSourceTP().toString())); + allPceLinks.put(linkId, pcelink); + source.addOutgoingLink(pcelink); + LOG.debug("validateLink: XPONDER-OUTPUT link added to allPceLinks {}", pcelink.toString()); + break; + default: + LOG.warn("validateLink: link type is not supported {}", pcelink.toString()); + } + return true; - LinkId linkId = pcelink.getLinkId(); + } else if (("ODU4".equals(serviceType)) || ("10GE".equals(serviceType)) || ("1GE".equals(serviceType))) { + // ODU4, 1GE and 10GE services relying on ODU2, ODU2e or ODU0 services are handled at OTN layer + PceLink pceOtnLink = new PceLink(link, source, dest); - switch (validateLinkConstraints(pcelink)) { - case HARD_EXCLUDE : + if (!pceOtnLink.isOtnValid(link, serviceType)) { dropOppositeLink(link); - LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue()); + LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link"); return false; - default: - break; - } + } - switch (pcelink.getlinkType()) { - case ROADMTOROADM : - allPceLinks.put(linkId, pcelink); - source.addOutgoingLink(pcelink); - LOG.debug("validateLink: ROADMTOROADM-LINK added to allPceLinks {}", pcelink.toString()); - break; - case EXPRESSLINK : - allPceLinks.put(linkId, pcelink); - source.addOutgoingLink(pcelink); - LOG.debug("validateLink: EXPRESS-LINK added to allPceLinks {}", pcelink.toString()); - break; - case ADDLINK : - pcelink.setClient(source.getRdmSrgClient(pcelink.getSourceTP().toString(), true)); - addLinks.add(pcelink); - LOG.debug("validateLink: ADD-LINK saved {}", pcelink.toString()); - break; - case DROPLINK : - pcelink.setClient(dest.getRdmSrgClient(pcelink.getDestTP().toString(), false)); - dropLinks.add(pcelink); - LOG.debug("validateLink: DROP-LINK saved {}", pcelink.toString()); - break; - case XPONDERINPUT : - // store separately all SRG links directly - azSrgs.add(sourceId); - // connected to A/Z - if (!dest.checkTP(pcelink.getDestTP().toString())) { - LOG.debug("validateLink: XPONDER-INPUT is rejected as NW port is busy - {} ", pcelink.toString()); - return false; - } - pcelink.setClient(dest.getClient(pcelink.getDestTP().toString())); - allPceLinks.put(linkId, pcelink); - source.addOutgoingLink(pcelink); - LOG.debug("validateLink: XPONDER-INPUT link added to allPceLinks {}", pcelink.toString()); - break; - // does it mean XPONDER==>>SRG ? - case XPONDEROUTPUT : - // store separately all SRG links directly - azSrgs.add(destId); - // connected to A/Z - if (!source.checkTP(pcelink.getSourceTP().toString())) { - LOG.debug("validateLink: XPONDER-OUTPUT is rejected as NW port is busy - {} ", pcelink.toString()); + LinkId linkId = pceOtnLink.getLinkId(); + switch (validateLinkConstraints(pceOtnLink)) { + case HARD_EXCLUDE: + dropOppositeLink(link); + LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue()); return false; - } - pcelink.setClient(source.getClient(pcelink.getSourceTP().toString())); - allPceLinks.put(linkId, pcelink); - source.addOutgoingLink(pcelink); - LOG.debug("validateLink: XPONDER-OUTPUT link added to allPceLinks {}", pcelink.toString()); - break; - default: - LOG.warn("validateLink: link type is not supported {}", pcelink.toString()); + default: + break; + } + switch (pceOtnLink.getlinkType()) { + case OTNLINK: + allPceLinks.put(linkId, pceOtnLink); + source.addOutgoingLink(pceOtnLink); + LOG.debug("validateLink: OTN-LINK added to allPceLinks {}", pceOtnLink.toString()); + break; + default: + LOG.warn("validateLink: link type is not supported {}", pceOtnLink.toString()); + } + return true; + } else { + LOG.error(" validateLink: Unmanaged service type {}", serviceType); + return false; } - return true; } private boolean validateNode(Node node) { @@ -353,7 +477,7 @@ public class PceCalculation { } OpenroadmNodeType nodeType = node1.getNodeType(); - PceNode pceNode = new PceNode(node,nodeType,node.getNodeId()); + PceNode pceNode = new PceNode(node, nodeType, node.getNodeId()); pceNode.validateAZxponder(anodeId, znodeId); pceNode.initWLlist(); @@ -363,28 +487,19 @@ public class PceCalculation { } switch (validateNodeConstraints(pceNode)) { - case HARD_EXCLUDE : + case HARD_EXCLUDE: return false; - default : + default: break; } - - if (pceNode.getSupNodeIdPceNode().equals(this.anodeId)) { - if (this.aendPceNode != null) { - LOG.debug("aendPceNode already gets: {}", this.aendPceNode); - } else if (endPceNode(nodeType,pceNode.getNodeId(), pceNode)) { - this.aendPceNode = pceNode; - } - // returning false otherwise would break E2E test + if ((pceNode.getSupNetworkNodeIdPceNode().equals(anodeId) && (this.aendPceNode == null)) + && (endPceNode(nodeType, pceNode.getNodeId(), pceNode))) { + this.aendPceNode = pceNode; } - if (pceNode.getSupNodeIdPceNode().equals(this.znodeId)) { - if (this.zendPceNode != null) { - LOG.debug("zendPceNode already gets: {}", this.zendPceNode); - } else if (endPceNode(nodeType,pceNode.getNodeId(), pceNode)) { - this.zendPceNode = pceNode; - } - // returning false otherwise would break E2E test + if ((pceNode.getSupNetworkNodeIdPceNode().equals(znodeId) && (this.zendPceNode == null)) + && (endPceNode(nodeType, pceNode.getNodeId(), pceNode))) { + this.zendPceNode = pceNode; } allPceNodes.put(pceNode.getNodeId(), pceNode); @@ -392,13 +507,58 @@ public class PceCalculation { return true; } + private OpenroadmNodeType validateOtnNode(Node node, String mode) { + + LOG.debug("validateNode: node {} ", node.toString()); + // PceOtnNode will be used in Graph algorithm + Node1 node1 = node.augmentation(Node1.class); + if (node1 == null) { + LOG.error("getNodeType: no Node1 (type) Augmentation for node: [{}]. Node is ignored", node.getNodeId()); + } + OpenroadmNodeType nodeType = node1.getNodeType(); + + PceOtnNode pceOtnNode = new PceOtnNode(node, nodeType, node.getNodeId(), serviceType); + if (mode == "AZ") { + pceOtnNode.validateAZxponder(anodeId, znodeId); + } else if (mode == "intermediate") { + pceOtnNode.validateIntermediateSwitch(); + } else { + LOG.error("validateOtnNode: unproper mode passed to the method : {} not supported", mode); + return null; + } + + if (!pceOtnNode.isValid()) { + LOG.warn(" validateNode: Node is ignored"); + return null; + } + + switch (validateNodeConstraints(pceOtnNode)) { + case HARD_EXCLUDE: + return null; + + default: + break; + } + + if ((pceOtnNode.getNodeId().equals(anodeId))) { + this.aendPceNode = pceOtnNode; + } + if ((pceOtnNode.getNodeId().equals(znodeId))) { + this.zendPceNode = pceOtnNode; + } + + allPceNodes.put(pceOtnNode.getNodeId(), pceOtnNode); + LOG.debug("validateNode: node is saved {}", pceOtnNode.getNodeId().getValue()); + return nodeType; + } + private ConstraintTypes validateNodeConstraints(PceNode pcenode) { if (pceHardConstraints.getExcludeSupNodes().isEmpty() && pceHardConstraints.getExcludeCLLI().isEmpty()) { return ConstraintTypes.NONE; } - if (pceHardConstraints.getExcludeSupNodes().contains(pcenode.getSupNodeIdPceNode())) { + if (pceHardConstraints.getExcludeSupNodes().contains(pcenode.getSupNetworkNodeIdPceNode())) { LOG.info("validateNodeConstraints: {}", pcenode.getNodeId().getValue()); return ConstraintTypes.HARD_EXCLUDE; } @@ -443,11 +603,11 @@ public class PceCalculation { private Boolean endPceNode(OpenroadmNodeType openroadmNodeType, NodeId nodeId, PceNode pceNode) { switch (openroadmNodeType) { - case SRG : + case SRG: pceNode.initSrgTps(); this.azSrgs.add(nodeId); break; - case XPONDER : + case XPONDER: pceNode.initXndrTps(); break; default: @@ -478,6 +638,10 @@ public class PceCalculation { return this.allPceLinks; } + public String getServiceType() { + return serviceType; + } + public PceResult getReturnStructure() { return returnStructure; } @@ -491,11 +655,4 @@ public class PceCalculation { } } - /*private static void printLinksInfo(Map allpcelinks) { - Iterator> links = allpcelinks.entrySet().iterator(); - while (links.hasNext()) { - LOG.info("In printLinksInfo link {} : ", links.next().getValue().toString()); - } - }*/ - } diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLink.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLink.java index 58215e8f2..9929b4dc0 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLink.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceLink.java @@ -30,6 +30,8 @@ public class PceLink { */ double weight = 0; private boolean isValid = true; + private boolean isOtnValid = true; + // this member is for XPONDER INPUT/OUTPUT links. // it keeps name of client corresponding to NETWORK TP private String client = ""; @@ -41,10 +43,13 @@ public class PceLink { private final Object destTP; private final String sourceSupNodeId; private final String destSupNodeId; + private final String sourceNetworkSupNodeId; + private final String destNetworkSupNodeId; private final String sourceCLLI; private final String destCLLI; private final LinkId oppositeLink; private final Long latency; + private final Long availableBandwidth; private final List srlgList; private final double osnr; private final Span omsAttributesSpan; @@ -67,9 +72,11 @@ public class PceLink { this.sourceSupNodeId = source.getSupNodeIdPceNode(); this.destSupNodeId = dest.getSupNodeIdPceNode(); + this.sourceNetworkSupNodeId = source.getSupNetworkNodeIdPceNode(); + this.destNetworkSupNodeId = dest.getSupNetworkNodeIdPceNode(); - this.sourceCLLI = source.getCLLI(); - this.destCLLI = dest.getCLLI(); + this.sourceCLLI = source.getClliSupNodeId(); + this.destCLLI = dest.getClliSupNodeId(); this.linkType = MapUtils.calcType(link); @@ -80,13 +87,20 @@ public class PceLink { this.srlgList = MapUtils.getSRLG(link); this.latency = calcLatency(link); this.osnr = calcSpanOSNR(); + this.availableBandwidth = 0L; + } else if (this.linkType == OpenroadmLinkType.OTNLINK) { + this.availableBandwidth = MapUtils.getAvailableBandwidth(link); + this.srlgList = MapUtils.getSRLGfromLink(link); + this.osnr = 0.0; + this.latency = 0L; + this.omsAttributesSpan = null; } else { this.omsAttributesSpan = null; this.srlgList = null; this.latency = 0L; this.osnr = 100L; //infinite OSNR in DB + this.availableBandwidth = 0L; } - LOG.debug("PceLink: created PceLink {}", toString()); } @@ -210,14 +224,27 @@ public class PceLink { return latency.doubleValue(); } + public Long getAvailableBandwidth() { + return availableBandwidth; + } + + public String getsourceSupNodeId() { return sourceSupNodeId; } + public String getsourceNetworkSupNodeId() { + return sourceNetworkSupNodeId; + } + public String getdestSupNodeId() { return destSupNodeId; } + public String getdestNetworkSupNodeId() { + return destNetworkSupNodeId; + } + public List getsrlgList() { return srlgList; } @@ -265,6 +292,62 @@ public class PceLink { return isValid; } + public boolean isOtnValid(Link link, String oduType) { + if (this.linkType == OpenroadmLinkType.OTNLINK) { + isOtnValid = false; + Long availableBW = MapUtils.getAvailableBandwidth(link); + if ((availableBW == 0L) || (availableBW == null)) { + LOG.error("PceLink: No bandwidth available or not valid OTN Link, Link {} is ignored ", linkId); + } else if (("ODU4".equals(oduType)) && (availableBW == 100000L)) { + isOtnValid = true; + LOG.debug("PceLink: Selected OTU4 Link {} is eligible for ODU creation OTN Link", linkId); + } else if (("ODU2".equals(oduType)) || ("ODU2e".equals(oduType)) && (availableBW >= 12500L)) { + isOtnValid = true; + LOG.debug("PceLink: Selected ODU4 Link {} has available bandwidth and is eligible for {} creation ", + linkId, oduType); + } else if (("ODU0".equals(oduType)) && (availableBW >= 1250L)) { + isOtnValid = true; + LOG.debug("PceLink: Selected ODU4 Link {} has available bandwidth and is eligible for {} creation ", + linkId, oduType); + } else if (("ODU1".equals(oduType)) && (availableBW >= 2500L)) { + isOtnValid = true; + LOG.debug("PceLink: Selected ODU4 Link {} has available bandwidth and is eligible for {} creation ", + linkId, oduType); + } else { + isOtnValid = false; + LOG.error( + "PceLink: Selected OTN Link {} is not eligible for ODU creation: not enough available bandwidth", + linkId); + } + + } else { + isOtnValid = false; + LOG.error("PceLink: Not an OTN link. Link is ignored {}", linkId); + } + + if ((this.linkId == null) || (this.linkType == null) + || (this.oppositeLink == null)) { + isOtnValid = false; + LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId); + } + if ((this.sourceId == null) || (this.destId == null) + || (this.sourceTP == null) || (this.destTP == null)) { + isOtnValid = false; + LOG.error("PceLink: No Link source or destination is available. Link is ignored {}", linkId); + } + if ((this.sourceNetworkSupNodeId.equals("")) || (this.destNetworkSupNodeId.equals(""))) { + isOtnValid = false; + LOG.error("PceLink: No Link source SuppNodeID or destination SuppNodeID is available. Link is ignored {}", + linkId); + } + if ((this.sourceCLLI.equals("")) || (this.destCLLI.equals(""))) { + isOtnValid = false; + LOG.error("PceLink: No Link source CLLI or destination CLLI is available. Link is ignored {}", linkId); + } + + return isOtnValid; + } + public String toString() { return "PceLink type=" + linkType + " ID=" + linkId.getValue() + " latency=" + latency; } diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceNode.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceNode.java index c869f1675..52e01056a 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceNode.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceNode.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.Optional; import java.util.TreeMap; +import org.opendaylight.transportpce.common.NetworkUtils; import org.opendaylight.transportpce.pce.SortPortsByName; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.TerminationPoint1; import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.Node1; @@ -35,10 +36,11 @@ public class PceNode { private boolean valid = true; - private final Node node; - private final NodeId nodeId; - private final OpenroadmNodeType nodeType; + protected final Node node; + protected final NodeId nodeId; + protected final OpenroadmNodeType nodeType; private final String supNodeId; + private final String supNetworkNodeId; private final String clli; // wavelength calculation per node type @@ -48,13 +50,19 @@ public class PceNode { private List usedXpndrNWTps = new ArrayList(); private List outgoingLinks = new ArrayList(); private Map clientPerNwTp = new HashMap(); + private Map> tpAvailableTribPort = new TreeMap>(); + private Map> tpAvailableTribSlot = new TreeMap>(); public PceNode(Node node, OpenroadmNodeType nodeType, NodeId nodeId) { this.node = node; this.nodeId = nodeId; this.nodeType = nodeType; this.supNodeId = getSupNodeId(node); - this.clli = MapUtils.getCLLI(node); + this.supNetworkNodeId = getNetworkSupNodeId(node); + //this.clli = MapUtils.getCLLI(node); + this.clli = getClliSupNodeId(node); + this.tpAvailableTribPort.clear(); + this.tpAvailableTribSlot.clear(); if ((node == null) || (nodeId == null) || (nodeType == null)) { LOG.error("PceNode: one of parameters is not populated : nodeId, node type"); @@ -289,23 +297,49 @@ public class PceNode { } } + private String getClliSupNodeId(Node inputNode) { + TreeMap allSupNodes = new TreeMap(); + String tempNetworkSupNodeId = ""; + allSupNodes = MapUtils.getAllSupNode(inputNode); + if (allSupNodes.get(NetworkUtils.CLLI_NETWORK_ID) == null) { + LOG.error("getClliSupNodeId: No Supporting node at CLLI layer for node: [{}].", inputNode.getNodeId()); + } else { + tempNetworkSupNodeId = allSupNodes.get(NetworkUtils.CLLI_NETWORK_ID); + } + return tempNetworkSupNodeId; + } + + public String getClliSupNodeId() { + return clli; + } + + private String getNetworkSupNodeId(Node inputNode) { + TreeMap allSupNodes = new TreeMap(); + String tempNetworkSupNodeId = ""; + allSupNodes = MapUtils.getAllSupNode(inputNode); + if (allSupNodes.get(NetworkUtils.UNDERLAY_NETWORK_ID) == null) { + LOG.error( + "getNetworkSupNodeId: No Supporting node at NETWORK layer for node: [{}].", inputNode.getNodeId()); + } else { + tempNetworkSupNodeId = allSupNodes.get(NetworkUtils.UNDERLAY_NETWORK_ID); + } + return tempNetworkSupNodeId; + } + + public void validateAZxponder(String anodeId, String znodeId) { if (!isValid()) { return; } - if (this.nodeType != OpenroadmNodeType.XPONDER) { return; } - // Detect A and Z - if (this.supNodeId.equals(anodeId) || (this.supNodeId.equals(znodeId))) { - + if (this.supNetworkNodeId.equals(anodeId) || (this.supNetworkNodeId.equals(znodeId))) { LOG.info("validateAZxponder: A or Z node detected == {}", nodeId.getValue()); initXndrTps(); return; } - LOG.debug("validateAZxponder: XPONDER is ignored == {}", nodeId.getValue()); valid = false; } @@ -323,7 +357,7 @@ public class PceNode { } public boolean isValid() { - if ((node == null) || (nodeId == null) || (nodeType == null) || (supNodeId == null) || (clli == null)) { + if ((node == null) || (nodeId == null) || (nodeType == null) || (supNetworkNodeId == null) || (clli == null)) { LOG.error("PceNode: one of parameters is not populated : nodeId, node type, supporting nodeId"); valid = false; } @@ -354,6 +388,10 @@ public class PceNode { return supNodeId; } + public String getSupNetworkNodeIdPceNode() { + return supNetworkNodeId; + } + public String getCLLI() { return clli; } @@ -366,4 +404,12 @@ public class PceNode { LOG.info(" outgoing links of node {} : {} ", nodeId.getValue(), this.getOutgoingLinks().toString()); } + public Map> getAvailableTribPorts() { + return tpAvailableTribPort; + } + + public Map> getAvailableTribSlots() { + return tpAvailableTribSlot; + } + } diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOtnNode.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOtnNode.java new file mode 100644 index 000000000..9da697f99 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceOtnNode.java @@ -0,0 +1,506 @@ +/* + * Copyright © 2019 Orange, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.transportpce.pce.networkanalyzer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +//import java.util.Optional; +import java.util.TreeMap; + +//import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.transportpce.common.NetworkUtils; +//import org.opendaylight.transportpce.pce.SortPortsByName; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.Node1; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.TerminationPoint1; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.networks +//.network.node.termination.point.pp.attributes.UsedWavelength; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev181130.xpdr.odu.switching.pools.OduSwitchingPools; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev181130.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingList; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmNodeType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmTpType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.xpdr.tp.supported.interfaces.SupportedInterfaceCapability; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev181130.ODTU4TsAllocated; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.TerminationPoint1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.networks.network.node.SwitchingPools; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev181130.If100GEODU4; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev181130.If10GEODU2e; +//import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev181130.If1GEODU0; +import org.opendaylight.yang.gen.v1.http.org.openroadm.xponder.rev181130.xpdr.otn.tp.attributes.OdtuTpnPool; +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.rev180226.networks.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PceOtnNode extends PceNode { + /* Logging. */ + private static final Logger LOG = LoggerFactory.getLogger(PceCalculation.class); + ////////////////////////// OTN NODES /////////////////////////// + /* + * For This Class the node passed shall be at the otn-openroadm Layer + */ + + private boolean valid = true; + + private final String supNetworkNodeId; + private final String supTopoNodeId; + private final String clli; + private final String otnServiceType; + + private Map> tpAvailableTribPort = new TreeMap>(); + private Map> tpAvailableTribSlot = new TreeMap>(); + private Map availableXponderTp = new TreeMap(); + private List usedXpdrNWTps = new ArrayList(); + private List unusableXpdrNWTps = new ArrayList(); + private List usedXpdrClientTps = new ArrayList(); + private List unusableXpdrClientTps = new ArrayList(); + private List outgoingLinks = new ArrayList(); + private Map clientPerNwTp = new HashMap(); + + public PceOtnNode(Node node, OpenroadmNodeType nodeType, NodeId nodeId, String serviceType) { + super(node, nodeType, nodeId); + this.supNetworkNodeId = getNetworkSupNodeId(node); + this.supTopoNodeId = getTopoSupNodeId(node); + this.clli = getClliSupNodeId(node); + this.otnServiceType = serviceType; + this.tpAvailableTribPort.clear(); + this.tpAvailableTribSlot.clear(); + this.usedXpdrNWTps.clear(); + this.unusableXpdrNWTps.clear(); + this.usedXpdrClientTps.clear(); + this.unusableXpdrClientTps.clear(); + + if ((node == null) || (nodeId == null) || (nodeType == null)) { + LOG.error("PceOtnNode: one of parameters is not populated : nodeId, node type"); + this.valid = false; + } + } + + public void initXndrTps(String mode) { + LOG.info("initXndrTps for node : {}", this.nodeId); + int availableNetworkTpNumber = 0; + int availableClientTpNumber = 0; + + this.availableXponderTp.clear(); + + if (!isValid()) { + return; + } + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1 nodeTp = + this.node.augmentation( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1.class); + List allTps = nodeTp.getTerminationPoint(); + this.valid = false; + if (allTps == null) { + LOG.error("initXndrTps: XPONDER TerminationPoint list is empty for node {}", this.toString()); + return; + } + + for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks + .network.node.TerminationPoint tp : allTps) { + TerminationPoint1 otnTp1 = tp.augmentation(TerminationPoint1.class); + //TODO many nested if-structures below, this needs to be reworked + if (otnTp1.getTpType() == OpenroadmTpType.XPONDERNETWORK) { + if (otnTp1.getXpdrTpPortConnectionAttributes().getWavelength() != null) { + this.usedXpdrNWTps.add(tp.getTpId().getValue()); + } else { + // find server of this network TP + String server = otnTp1.getXpdrTpPortConnectionAttributes().getTailEquipmentId(); + if ((server.equals("")) || (server == null)) { + this.unusableXpdrNWTps.add(tp.getTpId().getValue()); + } else { + // tp is not used and as a tail to server WDM layer + if (("10GE".equals(this.otnServiceType)) || ("1GE".equals(this.otnServiceType))) { + // LO-ODU needs to be created on a parent HO-ODU + // interface + List presenceOdtu = + otnTp1.getXpdrTpPortConnectionAttributes().getOdtuTpnPool(); + if (presenceOdtu == null) { + this.unusableXpdrNWTps.add(tp.getTpId().getValue()); + } else { + List sic = + otnTp1.getTpSupportedInterfaces().getSupportedInterfaceCapability(); + if ((findNetworkCompliantInterface(sic)) & (checkAvailableTribPort(tp)) + & (checkAvailableTribSlot(tp))) { + this.availableXponderTp.put(tp.getTpId().getValue(), + OpenroadmTpType.XPONDERNETWORK); + availableNetworkTpNumber++; + } + /* + * Add the retrieval of outgoing ingoing links + * through an external function + */ + } + } else { + // service is HO service + List sic = + otnTp1.getTpSupportedInterfaces().getSupportedInterfaceCapability(); + if (findNetworkCompliantInterface(sic)) { + this.availableXponderTp.put(tp.getTpId().getValue(), OpenroadmTpType.XPONDERNETWORK); + availableNetworkTpNumber++; + /* + * Add the retrieval of outgoing ingoing links + * through an external function + */ + } else { + this.unusableXpdrNWTps.add(tp.getTpId().getValue()); + + } + + } + + } + + } + + // The port is not a network port + } else if (otnTp1.getTpType() == OpenroadmTpType.XPONDERCLIENT) { + // For Client port we verify that it supports needed interfaces + // TBD : How shall we check a client port is available and not + // in use? + List sic = + otnTp1.getTpSupportedInterfaces().getSupportedInterfaceCapability(); + if (findClientCompliantInterface(sic)) { + this.availableXponderTp.put(tp.getTpId().getValue(), OpenroadmTpType.XPONDERCLIENT); + availableClientTpNumber++; + } + } + LOG.debug("initXndrTps: XPONDER tp = {} is used", tp.getTpId().getValue()); + LOG.error("initXndrTps: XPONDER {} NW TP doesn't have defined server ROADM SRG {}", this.toString(), tp + .getTpId().getValue()); + } + if ("AZ".equals(mode)) { + if ((availableClientTpNumber >= 1) || (availableNetworkTpNumber >= 1)) { + // for A and Z node we need to have one valid client port & one + // valid network port + this.valid = true; + } + } else if ("intermediate".equals(mode)) { + if ((availableNetworkTpNumber >= 2)) { + // for OTN switching node used in transit we need to have two + // valid network ports + this.valid = true; + } + } + + if (!isValid()) { + LOG.debug("initXndrTps: XPONDER doesn't have the required ports available {}", this.toString()); + return; + } else { + LOG.debug("initXndrTps: XPONDER {} is elligible", this.toString()); + } + } + + private Boolean findClientCompliantInterface(List sic) { + boolean compliant = false; + for (SupportedInterfaceCapability sit : sic) { + String interfacetype = sit.getIfCapType().toString(); + switch (interfacetype) { + case "If1GEODU0": + case "If1GE": + if ("1GE".equals(this.otnServiceType)) { + compliant = true; + } + break; + case "If10GEODU2e": + case "If10GE": + if ("10GE".equals(this.otnServiceType)) { + compliant = true; + } + break; + case "If100GEODU4": + case "If100GE": + if ("100GE".equals(this.otnServiceType)) { + compliant = true; + } + break; + case "IfOTU4ODU4": + case "IfOCHOTU4ODU4": + if (("OTU4".equals(this.otnServiceType)) || ("ODU4".equals(this.otnServiceType))) { + compliant = true; + } + break; + default: + compliant = false; + break; + } + + } + return compliant; + } + + private Boolean findNetworkCompliantInterface(List sic) { + boolean compliant = false; + for (SupportedInterfaceCapability sit : sic) { + String interfacetype = sit.getIfCapType().toString(); + switch (interfacetype) { + case "IfOTU4ODU4": + case "IfOCHOTU4ODU4": + compliant = true; + break; + case "IfOTU2ODU2": + case "IfOCHOTU2ODU2": + if (("1GE".equals(this.otnServiceType)) || ("10GE".equals(this.otnServiceType))) { + compliant = true; + } + break; + // add all use case with higher rate interfaces when it shows up + default: + compliant = false; + break; + } + + } + return compliant; + } + + private String getClliSupNodeId(Node inputNode) { + TreeMap allSupNodes = new TreeMap(); + String tempNetworkSupNodeId = ""; + allSupNodes = MapUtils.getAllSupNode(inputNode); + if (allSupNodes.get(NetworkUtils.CLLI_NETWORK_ID) == null) { + LOG.error("getClliSupNodeId: No Supporting node at CLLI layer for node: [{}].", inputNode.getNodeId()); + } else { + tempNetworkSupNodeId = allSupNodes.get(NetworkUtils.CLLI_NETWORK_ID); + } + return tempNetworkSupNodeId; + } + + private String getNetworkSupNodeId(Node inputNode) { + TreeMap allSupNodes = new TreeMap(); + String tempNetworkSupNodeId = ""; + allSupNodes = MapUtils.getAllSupNode(inputNode); + if (allSupNodes.get(NetworkUtils.UNDERLAY_NETWORK_ID) == null) { + LOG.error( + "getNetworkSupNodeId: No Supporting node at NETWORK layer for node: [{}].", inputNode.getNodeId()); + } else { + tempNetworkSupNodeId = allSupNodes.get(NetworkUtils.UNDERLAY_NETWORK_ID); + } + return tempNetworkSupNodeId; + } + + private String getTopoSupNodeId(Node inputNode) { + TreeMap allSupNodes = new TreeMap(); + String tempTopoSupNodeId = ""; + allSupNodes = MapUtils.getAllSupNode(inputNode); + if (allSupNodes.get(NetworkUtils.OVERLAY_NETWORK_ID) == null) { + LOG.error( + "getTopologySupNodeId: No Supporting node at TOPOLOGY layer for node: [{}].", inputNode.getNodeId()); + } else { + tempTopoSupNodeId = allSupNodes.get(NetworkUtils.OVERLAY_NETWORK_ID); + } + return tempTopoSupNodeId; + } + + public void validateAZxponder(String anodeId, String znodeId) { + if (!isValid()) { + return; + } + if ((this.nodeType != OpenroadmNodeType.MUXPDR) & (this.nodeType != OpenroadmNodeType.SWITCH) + & (this.nodeType != OpenroadmNodeType.TPDR)) { + return; + } + // Detect A and Z, a/znodeId correspond to otn layer, supporting node + // might be of Network or Topology layer + if (this.nodeId.equals(anodeId) || (this.nodeId.equals(znodeId))) { + initXndrTps("AZ"); + if (!this.valid) { + LOG.debug("validateAZxponder: XPONDER unusable for A or Z == {}", nodeId.getValue()); + } else { + LOG.info("validateAZxponder: A or Z node detected and validated == {}", nodeId.getValue()); + } + return; + } else { + LOG.debug("validateAZxponder: XPONDER is ignored == {}", nodeId.getValue()); + valid = false; + } + + } + + public boolean validateSwitchingPoolBandwidth( + Node node, + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks + .network.node.TerminationPoint tp1, + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks + .network.node.TerminationPoint tp2, + Long neededBW) { + Long availableBW = 0L; + if (this.nodeType != OpenroadmNodeType.TPDR) { + return true; + } else { + org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.Node1 node1 = + node.augmentation( + org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev181130.Node1.class); + SwitchingPools sp = node1.getSwitchingPools(); + List osp = new ArrayList(); + osp = sp.getOduSwitchingPools(); + for (OduSwitchingPools ospx : osp) { + List nbl = ospx.getNonBlockingList(); + for (NonBlockingList nbll : nbl) { + if (nbll.getAvailableInterconnectBandwidth() >= neededBW) { + List tplist = new ArrayList(nbll.getTpList()); + if ((tplist.contains(tp1.getTpId())) & (tplist.contains(tp2.getTpId()))) { + LOG.debug("validateSwitchingPoolBandwidth: couple of tp {} x {} valid for crossconnection", + tp1.getTpId().toString(), tp2.getTpId().toString()); + return true; + } + } + } + + } + LOG.debug("validateSwitchingPoolBandwidth: No valid Switching pool for crossconnecting tp {} and {}", + tp1.getTpId().toString(), tp2.getTpId().toString()); + return false; + } + + } + + public void validateIntermediateSwitch() { + if (!isValid()) { + return; + } + if (this.nodeType != OpenroadmNodeType.SWITCH) { + return; + } + // Validate switch for use as an intermediate XPONDER on the path + initXndrTps("intermediate"); + if (!this.valid) { + LOG.debug("validateIntermediateSwitch: Switch unusable for transit == {}", nodeId.getValue()); + } else { + LOG.info("validateIntermediateSwitch: Switch usable for transit == {}", nodeId.getValue()); + } + return; + + } + + public boolean checkAvailableTribPort( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks + .network.node.TerminationPoint tp) { + boolean compatibleSupInt = false; + TerminationPoint1 otnTp1 = tp.augmentation(TerminationPoint1.class); + if (otnTp1.getTpType() == OpenroadmTpType.XPONDERNETWORK) { + try { + List otpp = otnTp1.getXpdrTpPortConnectionAttributes().getOdtuTpnPool(); + + for (OdtuTpnPool otppi : otpp) { + if (otppi.getOdtuType().getClass().equals(ODTU4TsAllocated.class)) { + this.tpAvailableTribPort.put(tp.getTpId().getValue(), otppi.getTpnPool()); + LOG.debug("checkAvailableTribPort: tp {} and his trib Ports have been added to " + + "tpAvailableTribPortMap", tp.getTpId().getValue()); + compatibleSupInt = true; + + } + } + } catch (NullPointerException e) { + LOG.debug("checkAvailableTribPort: OdtuTpnPool not present for tp {} ", tp.getTpId().toString()); + } + + } else { + LOG.debug("checkAvailableTribPort: tp {} has no odtu tpn Pool", tp.getTpId().getValue()); + } + return compatibleSupInt; + } + + public boolean checkAvailableTribSlot( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks + .network.node.TerminationPoint tp) { + boolean compatibleSupInt = false; + TerminationPoint1 otnTp1 = tp.augmentation(TerminationPoint1.class); + if (otnTp1.getTpType() == OpenroadmTpType.XPONDERNETWORK) { + List otpp; + try { + otpp = otnTp1.getXpdrTpPortConnectionAttributes().getOdtuTpnPool(); + + for (OdtuTpnPool otppi : otpp) { + if (otppi.getOdtuType().getClass().equals(ODTU4TsAllocated.class)) { + this.tpAvailableTribSlot.put( + tp.getTpId().getValue(), + otnTp1.getXpdrTpPortConnectionAttributes().getTsPool()); + LOG.debug( + "checkAvailableTribPort: tp {} and its trib Slots were added to tpAvailableTribSlotMap", + tp.getTpId().getValue()); + compatibleSupInt = true; + + } + } + + } catch (NullPointerException e) { + LOG.debug("checkAvailableTribSlot: OdtuTpnPool not present for tp {} ", tp.getTpId().toString()); + } + } else { + LOG.debug("checkAvailableTribPort: tp {} is not a network Port", tp.getTpId().getValue()); + } + return compatibleSupInt; + } + + public String getXpdrClient(String tp) { + return this.clientPerNwTp.get(tp); + } + + public boolean checkTP(String tp) { + return !((this.usedXpdrNWTps.contains(tp)) || (this.usedXpdrClientTps.contains(tp)) + || (this.unusableXpdrNWTps.contains(tp)) || (this.unusableXpdrClientTps.contains(tp))); + } + + public boolean isValid() { + if ((node == null) || (nodeId == null) || (nodeType == null) || (supNetworkNodeId == null) || (clli == null)) { + LOG.error("PceNode: one of parameters is not populated : nodeId, node type, supporting nodeId"); + valid = false; + } + return valid; + } + + public Map getAvailableTps() { + return availableXponderTp; + } + + public void addOutgoingLink(PceLink outLink) { + this.outgoingLinks.add(outLink); + } + + public List getOutgoingLinks() { + return outgoingLinks; + } + + public String getClient(String tp) { + return clientPerNwTp.get(tp); + } + + public String getTopoSupNodeIdPceNode() { + return supTopoNodeId; + } + + public String getNetworkSupNodeIdPceNode() { + return supNetworkNodeId; + } + + public String getCLLI() { + return clli; + } + + public String toString() { + return "PceNode type=" + nodeType + " ID=" + nodeId.getValue() + " CLLI=" + clli; + } + + public void printLinksOfNode() { + LOG.info(" outgoing links of node {} : {} ", nodeId.getValue(), this.getOutgoingLinks().toString()); + } + + public Map> getAvailableTribPorts() { + return tpAvailableTribPort; + } + + public Map> getAvailableTribSlots() { + return tpAvailableTribSlot; + } + +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceResult.java b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceResult.java index abce70280..aea19299f 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceResult.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/networkanalyzer/PceResult.java @@ -9,6 +9,7 @@ package org.opendaylight.transportpce.pce.networkanalyzer; import org.opendaylight.transportpce.common.ResponseCodes; +import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat; 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; @@ -22,6 +23,7 @@ public class PceResult { private String responseCode = ResponseCodes.RESPONSE_FAILED; private long resultWavelength = -1; private long rate = -1; + private ServiceFormat serviceFormat = ServiceFormat.OC; public enum LocalCause { NONE, TOO_HIGH_LATENCY, OUT_OF_SPEC_OSNR, NO_PATH_EXISTS, INT_PROBLEM, HD_NODE_INCLUDE; @@ -102,6 +104,14 @@ public class PceResult { this.rate = rate; } + public ServiceFormat getServiceFormat() { + return serviceFormat; + } + + public void setServiceFormat(ServiceFormat serviceFormat) { + this.serviceFormat = serviceFormat; + } + public LocalCause getLocalCause() { return localCause; } diff --git a/tests/sample_configs/honeynode-topo.xml b/tests/sample_configs/honeynode-topo.xml index 2a616bbb7..bc18c1359 100644 --- a/tests/sample_configs/honeynode-topo.xml +++ b/tests/sample_configs/honeynode-topo.xml @@ -347,6 +347,10 @@ openroadm-network ROADMC01 + + clli-network + NodeC + 93 @@ -649,11 +653,15 @@ DEG1-TTP-TXRX DEGREE-TXRX-TTP + DEGREE openroadm-network ROADMC01 - DEGREE + + clli-network + NodeC + 1 @@ -956,11 +964,15 @@ DEG2-CTP-TXRX DEGREE-TXRX-CTP + DEGREE openroadm-network ROADMC01 - DEGREE + + clli-network + NodeC + 2 @@ -1327,6 +1339,10 @@ openroadm-network ROADMA01 + + clli-network + NodeA + 93 @@ -1641,11 +1657,15 @@ XPONDER-NETWORK XPDR1-CLIENT1 + XPONDER openroadm-network XPDRA01 - XPONDER + + clli-network + NodeA + ROADMA01-DEG2 @@ -1657,11 +1677,15 @@ DEG2-CTP-TXRX DEGREE-TXRX-CTP + DEGREE openroadm-network ROADMA01 - DEGREE + + clli-network + NodeA + 2 @@ -1976,11 +2000,15 @@ XPONDER-NETWORK XPDR1-CLIENT1 + XPONDER openroadm-network XPDRC01 - XPONDER + + clli-network + NodeC + ROADMA01-DEG1 @@ -1992,11 +2020,15 @@ DEG1-TTP-TXRX DEGREE-TXRX-TTP + DEGREE openroadm-network ROADMA01 - DEGREE + + clli-network + NodeA + 1 diff --git a/tests/transportpce_tests/1.2.1/test_pce.py b/tests/transportpce_tests/1.2.1/test_pce.py index 1465bf2dd..2cad24181 100644 --- a/tests/transportpce_tests/1.2.1/test_pce.py +++ b/tests/transportpce_tests/1.2.1/test_pce.py @@ -117,12 +117,14 @@ class TransportPCEtesting(unittest.TestCase): }, "service-a-end": { "node-id": "XPDRA01", - "service-rate": "0", + "service-rate": "100", + "service-format": "Ethernet", "clli": "nodeA" }, "service-z-end": { "node-id": "XPDRC01", - "service-rate": "0", + "service-rate": "100", + "service-format": "Ethernet", "clli": "nodeC" } } @@ -151,13 +153,15 @@ class TransportPCEtesting(unittest.TestCase): }, "service-a-end": { "node-id": "ROADMA01", - "service-rate": "0", - "clli": "nodeA" + "service-rate": "100", + "service-format": "Ethernet", + "clli": "NodeA" }, "service-z-end": { "node-id": "ROADMC01", - "service-rate": "0", - "clli": "nodeC" + "service-rate": "100", + "service-format": "Ethernet", + "clli": "NodeC" } } } @@ -250,13 +254,15 @@ class TransportPCEtesting(unittest.TestCase): }, "service-a-end": { "node-id": "XPONDER-1-2", - "service-rate": "0", + "service-rate": "100", + "service-format": "Ethernet", "clli": "ORANGE1" }, "service-z-end": { "node-id": "XPONDER-3-2", - "service-rate": "0", - "clli": "ORANGE1" + "service-rate": "100", + "service-format": "Ethernet", + "clli": "ORANGE3" } } } @@ -282,12 +288,14 @@ class TransportPCEtesting(unittest.TestCase): "request-id": "request1" }, "service-a-end": { - "service-rate": "0", + "service-rate": "100", + "service-format": "Ethernet", "clli": "cll21", "node-id": "OpenROADM-2-1" }, "service-z-end": { - "service-rate": "0", + "service-rate": "100", + "service-format": "Ethernet", "clli": "ncli22", "node-id": "OpenROADM-2-2" }, @@ -400,8 +408,8 @@ class TransportPCEtesting(unittest.TestCase): }, "service-a-end": { "service-format": "Ethernet", - "service-rate": "0", - "clli": "clli11", + "service-rate": "100", + "clli": "ORANGE2", "node-id": "XPONDER-2-2", "tx-direction": { "port": { @@ -428,8 +436,8 @@ class TransportPCEtesting(unittest.TestCase): }, "service-z-end": { "service-format": "Ethernet", - "service-rate": "0", - "clli": "clli11", + "service-rate": "100", + "clli": "ORANGE1", "node-id": "XPONDER-1-2", "tx-direction": { "port": { @@ -500,12 +508,16 @@ class TransportPCEtesting(unittest.TestCase): "request-id": "request 1" }, "service-a-end": { - "service-rate": "0", - "node-id": "XPONDER-1-2" + "service-rate": "100", + "service-format": "Ethernet", + "node-id": "XPONDER-1-2", + "clli": "ORANGE1" }, "service-z-end": { - "service-rate": "0", - "node-id": "XPONDER-3-2" + "service-rate": "100", + "service-format": "Ethernet", + "node-id": "XPONDER-3-2", + "clli": "ORANGE3" }, "pce-metric": "hop-count" } @@ -536,12 +548,16 @@ class TransportPCEtesting(unittest.TestCase): "request-id": "request 1" }, "service-a-end": { - "service-rate": "0", - "node-id": "XPONDER-1-2" + "service-rate": "100", + "service-format": "Ethernet", + "node-id": "XPONDER-1-2", + "clli": "ORANGE1" }, "service-z-end": { - "service-rate": "0", - "node-id": "XPONDER-3-2" + "service-rate": "100", + "service-format": "Ethernet", + "node-id": "XPONDER-3-2", + "clli": "ORANGE3" }, "hard-constraints": { "exclude_": { -- 2.36.6