2 * Copyright © 2017 AT&T, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.transportpce.pce.graph;
11 import java.util.ArrayList;
12 import java.util.List;
15 import org.jgrapht.GraphPath;
16 import org.opendaylight.transportpce.common.ResponseCodes;
17 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
18 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
19 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
20 import org.opendaylight.transportpce.pce.networkanalyzer.PceOtnNode;
21 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
22 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 public class PostAlgoPathValidator {
29 private static final Logger LOG = LoggerFactory.getLogger(PceGraph.class);
32 private static final int MAX_WAWELENGTH = 96;
33 private static final double MIN_OSNR_W100G = 17;
34 private static final double TRX_OSNR = 33;
35 private static final double ADD_OSNR = 30;
36 public static final Long CONST_OSNR = 1L;
37 public static final double SYS_MARGIN = 0;
39 public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
40 PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) {
42 // check if the path is empty
43 if (path.getEdgeList().size() == 0) {
44 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
47 if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) {
48 // choose wavelength available in all nodes of the path
49 Long waveL = chooseWavelength(path, allPceNodes);
51 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
52 pceResult.setLocalCause(PceResult.LocalCause.NO_PATH_EXISTS);
55 pceResult.setResultWavelength(waveL);
56 LOG.info("In PostAlgoPathValidator: chooseWavelength WL found {} {}", waveL, path.toString());
58 // TODO here other post algo validations can be added
59 // more data can be sent to PceGraph module via PceResult structure if required
62 if (!checkOSNR(path)) {
63 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
64 pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR);
68 // Check if MaxLatency is defined in the hard constraints
69 if (pceHardConstraints.getMaxLatency() != -1) {
70 if (!checkLatency(pceHardConstraints.getMaxLatency(), path)) {
71 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
72 pceResult.setLocalCause(PceResult.LocalCause.TOO_HIGH_LATENCY);
77 // Check if nodes are included in the hard constraints
78 if (!checkInclude(path, pceHardConstraints)) {
79 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
80 pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE);
83 pceResult.setRC(ResponseCodes.RESPONSE_OK);
85 } else if (("1GE".equals(serviceType)) || ("10GE".equals(serviceType))) {
86 // Path is at the OTN layer
87 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
88 // In a first step we select the first tribPort available on the first edge
89 // TODO : after the way to pass trib-ports and trib-slots to the renderer has
90 // been adapted to fit
91 // with multiple OTN Hops, each first available port shall be passed for each
93 Integer tribPort = chooseTribPort(path, allPceNodes).get(0).get(0);
94 // TODO : Same comment apply for tribSlot
95 Integer tribSlot = chooseTribSlot(path, allPceNodes).get(0).get(0);
97 if (tribPort != null) {
98 // Temporarily we use wavelength-number to provide the TribPort
99 // TODO adapt the path-description
100 // TODO make the adaptation to return the first tribSlot in an intermediate
102 pceResult.setResultWavelength(tribPort);
103 pceResult.setRC(ResponseCodes.RESPONSE_OK);
104 LOG.info("In PostAlgoPathValidator: chooseTribPort TribPort found {} {}", tribPort, path.toString());
110 // Choose the first available wavelength from the source to the destination
111 private Long chooseWavelength(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes) {
112 Long wavelength = -1L;
114 for (long i = 1; i <= MAX_WAWELENGTH; i++) {
115 boolean completed = true;
116 LOG.debug("In chooseWavelength: {} {}", path.getLength(), path.toString());
117 for (PceGraphEdge edge : path.getEdgeList()) {
118 LOG.debug("In chooseWavelength: source {} ", edge.link().getSourceId().toString());
119 PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
120 if (!pceNode.checkWL(i)) {
134 private boolean checkLatency(Long maxLatency, GraphPath<String, PceGraphEdge> path) {
137 for (PceGraphEdge edge : path.getEdgeList()) {
139 latency += edge.link().getLatency();
140 LOG.debug("- In checkLatency: latency of {} = {} units", edge.link().getLinkId().getValue(), latency);
141 } catch (NullPointerException e) {
142 LOG.warn("- In checkLatency: the link {} does not contain latency field",
143 edge.link().getLinkId().getValue());
146 if (latency > maxLatency) {
152 // Check the inclusion if it is defined in the hard constraints
153 private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput) {
154 List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude();
155 if (listToInclude.isEmpty()) {
159 List<PceGraphEdge> pathEdges = path.getEdgeList();
160 LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList());
162 List<String> listOfElementsSubNode = new ArrayList<String>();
163 listOfElementsSubNode.add(pathEdges.get(0).link().getsourceSupNodeId());
164 listOfElementsSubNode.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.NODE,
165 pceHardConstraintsInput));
167 List<String> listOfElementsCLLI = new ArrayList<String>();
168 listOfElementsCLLI.add(pathEdges.get(0).link().getsourceCLLI());
169 listOfElementsCLLI.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.CLLI,
170 pceHardConstraintsInput));
172 List<String> listOfElementsSRLG = new ArrayList<String>();
173 // first link is XPONDEROUTPUT, no SRLG for it
174 listOfElementsSRLG.add("NONE");
175 listOfElementsSRLG.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.SRLG,
176 pceHardConstraintsInput));
178 // validation: check each type for each element
179 for (ResourcePair next : listToInclude) {
181 switch (next.getType()) {
183 if (listOfElementsSubNode.contains(next.getName())) {
184 indx = listOfElementsSubNode.indexOf(next.getName());
188 if (listOfElementsSRLG.contains(next.getName())) {
189 indx = listOfElementsSRLG.indexOf(next.getName());
193 if (listOfElementsCLLI.contains(next.getName())) {
194 indx = listOfElementsCLLI.indexOf(next.getName());
198 LOG.warn(" in checkInclude vertex list unsupported resource type: [{}]", next.getType());
202 LOG.debug(" in checkInclude stopped : {} ", next.getName());
206 LOG.debug(" in checkInclude next found {} in {}", next.getName(), path.getVertexList());
208 listOfElementsSubNode.subList(0, indx).clear();
209 listOfElementsCLLI.subList(0, indx).clear();
210 listOfElementsSRLG.subList(0, indx).clear();
213 LOG.info(" in checkInclude passed : {} ", path.getVertexList());
217 private List<String> listOfElementsBuild(List<PceGraphEdge> pathEdges, PceConstraints.ResourceType type,
218 PceConstraints pceHardConstraints) {
220 List<String> listOfElements = new ArrayList<String>();
221 for (PceGraphEdge link : pathEdges) {
224 listOfElements.add(link.link().getdestSupNodeId());
227 listOfElements.add(link.link().getdestCLLI());
230 if (link.link().getlinkType() != OpenroadmLinkType.ROADMTOROADM) {
231 listOfElements.add("NONE");
235 // srlg of link is List<Long>. But in this algo we need string representation of
237 // this should be any SRLG mentioned in include constraints if any of them if
239 boolean found = false;
240 for (Long srlg : link.link().getsrlgList()) {
241 String srlgStr = String.valueOf(srlg);
242 if (pceHardConstraints.getSRLGnames().contains(srlgStr)) {
243 listOfElements.add(srlgStr);
244 LOG.info("listOfElementsBuild. FOUND SRLG {} in link {}", srlgStr, link.link());
250 // there is no specific srlg to include. thus add to list just the first one
251 listOfElements.add("NONE");
255 LOG.debug("listOfElementsBuild unsupported resource type");
258 return listOfElements;
261 private List<List<Integer>> chooseTribPort(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes) {
262 List<List<Integer>> tribPort = new ArrayList<>();
263 boolean statusOK = true;
264 boolean check = false;
265 Object nodeClass = allPceNodes.getClass();
266 if (nodeClass.getClass().isInstance(PceNode.class)) {
267 LOG.debug("In choosetribPort: AllPceNodes contains PceNode instance, no trib port search");
269 } else if (nodeClass.getClass().isInstance(PceOtnNode.class)) {
270 LOG.debug("In choosetribPort: {} {}", path.getLength(), path.toString());
271 for (PceGraphEdge edge : path.getEdgeList()) {
272 LOG.debug("In chooseTribPort: source {} ", edge.link().getSourceId().toString());
273 PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
274 Object tps = allPceNodes.get(edge.link().getSourceTP());
275 Object tpd = allPceNodes.get(edge.link().getDestTP());
276 if ((pceNode.getAvailableTribPorts().containsKey(tps.toString()))
277 && (pceNode.getAvailableTribPorts().containsKey(tpd.toString()))) {
279 List<Integer> tribPortEdgeSourceN = new ArrayList<>();
280 List<Integer> tribPortEdgeDestN = new ArrayList<>();
281 tribPortEdgeSourceN = pceNode.getAvailableTribPorts().get(tps.toString());
282 tribPortEdgeDestN = pceNode.getAvailableTribPorts().get(tps.toString());
284 for (int i = 0; i <= 9; i++) {
285 if (tribPortEdgeSourceN.get(i) == null) {
288 if (tribPortEdgeSourceN.get(i) == tribPortEdgeDestN.get(i)) {
292 LOG.debug("In chooseTribPort: Misalignement of trib port between source {} and dest {}",
293 edge.link().getSourceId().toString(), edge.link().getDestId().toString());
298 tribPort.add(tribPortEdgeSourceN);
301 LOG.debug("In chooseTribPort: source {} does not have provisonned hosting HO interface ",
302 edge.link().getSourceId().toString());
307 if (statusOK && check) {
316 private List<List<Integer>> chooseTribSlot(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes) {
317 List<List<Integer>> tribSlot = new ArrayList<>();
318 boolean statusOK = true;
319 boolean check = false;
320 Object nodeClass = allPceNodes.getClass();
321 if (nodeClass.getClass().isInstance(PceNode.class)) {
322 LOG.debug("In choosetribSlot: AllPceNodes contains PceNode instance, no trib port search");
324 } else if (nodeClass.getClass().isInstance(PceOtnNode.class)) {
325 LOG.debug("In choosetribPort: {} {}", path.getLength(), path.toString());
326 for (PceGraphEdge edge : path.getEdgeList()) {
327 LOG.debug("In chooseTribSlot: source {} ", edge.link().getSourceId().toString());
328 PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
329 Object tps = allPceNodes.get(edge.link().getSourceTP());
330 Object tpd = allPceNodes.get(edge.link().getDestTP());
331 if ((pceNode.getAvailableTribSlots().containsKey(tps.toString()))
332 && (pceNode.getAvailableTribSlots().containsKey(tpd.toString()))) {
334 List<Integer> tribSlotEdgeSourceN = new ArrayList<>();
335 List<Integer> tribSlotEdgeDestN = new ArrayList<>();
336 tribSlotEdgeSourceN = pceNode.getAvailableTribSlots().get(tps.toString());
337 tribSlotEdgeDestN = pceNode.getAvailableTribSlots().get(tps.toString());
339 for (int i = 0; i <= 79; i++) {
340 if (tribSlotEdgeSourceN.get(i) == null) {
343 // TODO This will need to be modified as soon as the trib-slots allocation per
345 // policy applied by the different manufacturer is known
346 if (tribSlotEdgeSourceN.get(i) == tribSlotEdgeDestN.get(i)) {
350 LOG.debug("In chooseTribSlot: Misalignement of trib slots between source {} and dest {}",
351 edge.link().getSourceId().toString(), edge.link().getDestId().toString());
356 tribSlot.add(tribSlotEdgeSourceN);
359 LOG.debug("In chooseTribSlot: source {} does not have provisonned hosting HO interface ",
360 edge.link().getSourceId().toString());
365 if (statusOK && check) {
374 // Check the path OSNR
375 private boolean checkOSNR(GraphPath<String, PceGraphEdge> path) {
378 LOG.info("- In checkOSNR: OSNR of the transmitter = {} dB", TRX_OSNR);
379 LOG.info("- In checkOSNR: add-path incremental OSNR = {} dB", ADD_OSNR);
380 double inverseLocalOsnr = getInverseOsnrLinkLu(TRX_OSNR) + getInverseOsnrLinkLu(ADD_OSNR);
381 for (PceGraphEdge edge : path.getEdgeList()) {
382 if (edge.link().getlinkType() == OpenroadmLinkType.ROADMTOROADM) {
384 linkOsnrDb = edge.link().getosnr();
385 LOG.info("- In checkOSNR: OSNR of {} = {} dB", edge.link().getLinkId().getValue(), linkOsnrDb);
386 // 1 over the local OSNR, in linear units
387 inverseLocalOsnr += getInverseOsnrLinkLu(linkOsnrDb);
391 osnrDb = getOsnrDb(1 / inverseLocalOsnr);
392 } catch (ArithmeticException e) {
393 LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}", path.getEdgeList().size());
396 LOG.info("In checkOSNR: OSNR of the path is {} dB", osnrDb);
397 if ((osnrDb + SYS_MARGIN) < MIN_OSNR_W100G) {
400 double localOsnr = 0L;
401 LOG.info("In OSNR Stub: {}", localOsnr);
402 // TODO : change this to return OSNR value and validate or invalidate the path
406 private double getOsnrDb(double osnrLu) {
408 osnrDb = 10 * Math.log10(osnrLu);
412 private double getInverseOsnrLinkLu(double linkOsnrDb) {
413 // 1 over the link OSNR, in linear units
415 linkOsnrLu = Math.pow(10, (linkOsnrDb / 10.0));
416 LOG.debug("In retrieveosnr: the inverse of link osnr is {} (Linear Unit)", linkOsnrLu);
417 return (CONST_OSNR / linkOsnrLu);