Adapt code to support the new version of GNPy
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / graph / PostAlgoPathValidator.java
1 /*
2  * Copyright © 2017 AT&T, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.transportpce.pce.graph;
10
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16
17 import org.jgrapht.GraphPath;
18 import org.opendaylight.transportpce.common.ResponseCodes;
19 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
20 import org.opendaylight.transportpce.pce.constraints.PceConstraints.ResourcePair;
21 import org.opendaylight.transportpce.pce.networkanalyzer.PceNode;
22 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
23 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 public class PostAlgoPathValidator {
29     /* Logging. */
30     private static final Logger LOG = LoggerFactory.getLogger(PceGraph.class);
31
32     // TODO hard-coded 96
33     private static final int MAX_WAWELENGTH = 96;
34     private static final double MIN_OSNR_W100G = 17;
35     private static final double TRX_OSNR = 33;
36     private static final double ADD_OSNR = 30;
37     public static final Long CONST_OSNR = 1L;
38     public static final double SYS_MARGIN = 0;
39
40     public PceResult checkPath(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes,
41         PceResult pceResult, PceConstraints pceHardConstraints, String serviceType) {
42
43         // check if the path is empty
44         if (path.getEdgeList().size() == 0) {
45             pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
46             return pceResult;
47         }
48
49         int tribSlotNb = 1;
50         //variable to deal with 1GE (Nb=1) and 10GE (Nb=10) cases
51         switch (serviceType) {
52
53             case "100GE":
54             case "OTU4":
55                 // choose wavelength available in all nodes of the path
56                 Long waveL = chooseWavelength(path, allPceNodes);
57                 pceResult.setServiceType(serviceType);
58                 if (waveL < 0) {
59                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
60                     pceResult.setLocalCause(PceResult.LocalCause.NO_PATH_EXISTS);
61                     return pceResult;
62                 }
63                 pceResult.setResultWavelength(waveL);
64                 LOG.info("In PostAlgoPathValidator: chooseWavelength WL found {} {}", waveL, path.toString());
65
66                 // Check the OSNR
67                 if (!checkOSNR(path)) {
68                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
69                     pceResult.setLocalCause(PceResult.LocalCause.OUT_OF_SPEC_OSNR);
70                     return pceResult;
71                 }
72
73                 // Check if MaxLatency is defined in the hard constraints
74                 if ((pceHardConstraints.getMaxLatency() != -1)
75                         && (!checkLatency(pceHardConstraints.getMaxLatency(), path))) {
76                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
77                     pceResult.setLocalCause(PceResult.LocalCause.TOO_HIGH_LATENCY);
78                     return pceResult;
79                 }
80
81                 // Check if nodes are included in the hard constraints
82                 if (!checkInclude(path, pceHardConstraints)) {
83                     pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
84                     pceResult.setLocalCause(PceResult.LocalCause.HD_NODE_INCLUDE);
85                     return pceResult;
86                 }
87
88                 // TODO here other post algo validations can be added
89                 // more data can be sent to PceGraph module via PceResult structure if required
90
91                 pceResult.setRC(ResponseCodes.RESPONSE_OK);
92                 pceResult.setLocalCause(PceResult.LocalCause.NONE);
93
94                 break;
95
96             case "10GE":
97                 tribSlotNb = 10;
98             //fallthrough
99             case "1GE":
100                 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
101                 pceResult.setServiceType(serviceType);
102                 Map<String, Integer> tribPort = chooseTribPort(path, allPceNodes);
103                 Map<String, List<Integer>> tribSlot = chooseTribSlot(path, allPceNodes, tribSlotNb);
104
105                 if (tribPort != null && tribSlot != null) {
106                     pceResult.setResultTribPort(tribPort);
107                     pceResult.setResultTribSlot(tribSlot);
108                     pceResult.setResultTribSlotNb(tribSlotNb);
109                     pceResult.setRC(ResponseCodes.RESPONSE_OK);
110                     LOG.info("In PostAlgoPathValidator: found TribPort {} - tribSlot {} - tribSlotNb {}",
111                         tribPort, tribSlot, tribSlotNb);
112                 }
113                 break;
114
115             case "ODU4":
116                 pceResult.setRC(ResponseCodes.RESPONSE_OK);
117                 LOG.info("In PostAlgoPathValidator: ODU4 path found {}", path.toString());
118                 break;
119
120             default:
121                 pceResult.setRC(ResponseCodes.RESPONSE_FAILED);
122                 LOG.warn("In PostAlgoPathValidator checkPath: unsupported serviceType {} found {}",
123                     serviceType, path.toString());
124                 break;
125         }
126
127         return pceResult;
128     }
129
130     // Choose the first available wavelength from the source to the destination
131     private Long chooseWavelength(GraphPath<String, PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes) {
132         Long wavelength = -1L;
133         for (long i = 1; i <= MAX_WAWELENGTH; i++) {
134             boolean completed = true;
135             LOG.debug("In chooseWavelength: {} {}", path.getLength(), path.toString());
136             for (PceGraphEdge edge : path.getEdgeList()) {
137                 LOG.debug("In chooseWavelength: source {} ", edge.link().getSourceId().toString());
138                 PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
139                 if (!pceNode.checkWL(i)) {
140                     completed = false;
141                     break;
142                 }
143             }
144             if (completed) {
145                 wavelength = i;
146                 break;
147             }
148         }
149         return wavelength;
150     }
151
152     // Check the latency
153     private boolean checkLatency(Long maxLatency, GraphPath<String, PceGraphEdge> path) {
154         double latency = 0;
155
156         for (PceGraphEdge edge : path.getEdgeList()) {
157             try {
158                 latency += edge.link().getLatency();
159                 LOG.debug("- In checkLatency: latency of {} = {} units", edge.link().getLinkId().getValue(), latency);
160             } catch (NullPointerException e) {
161                 LOG.warn("- In checkLatency: the link {} does not contain latency field",
162                     edge.link().getLinkId().getValue());
163             }
164         }
165         if (latency > maxLatency) {
166             return false;
167         }
168         return true;
169     }
170
171     // Check the inclusion if it is defined in the hard constraints
172     private boolean checkInclude(GraphPath<String, PceGraphEdge> path, PceConstraints pceHardConstraintsInput) {
173         List<ResourcePair> listToInclude = pceHardConstraintsInput.getListToInclude();
174         if (listToInclude.isEmpty()) {
175             return true;
176         }
177
178         List<PceGraphEdge> pathEdges = path.getEdgeList();
179         LOG.debug(" in checkInclude vertex list: [{}]", path.getVertexList());
180
181         List<String> listOfElementsSubNode = new ArrayList<String>();
182         listOfElementsSubNode.add(pathEdges.get(0).link().getsourceNetworkSupNodeId());
183         listOfElementsSubNode.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.NODE,
184             pceHardConstraintsInput));
185
186         List<String> listOfElementsCLLI = new ArrayList<String>();
187         listOfElementsCLLI.add(pathEdges.get(0).link().getsourceCLLI());
188         listOfElementsCLLI.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.CLLI,
189             pceHardConstraintsInput));
190
191         List<String> listOfElementsSRLG = new ArrayList<String>();
192         // first link is XPONDEROUTPUT, no SRLG for it
193         listOfElementsSRLG.add("NONE");
194         listOfElementsSRLG.addAll(listOfElementsBuild(pathEdges, PceConstraints.ResourceType.SRLG,
195             pceHardConstraintsInput));
196
197         // validation: check each type for each element
198         for (ResourcePair next : listToInclude) {
199             int indx = -1;
200             switch (next.getType()) {
201                 case NODE:
202                     if (listOfElementsSubNode.contains(next.getName())) {
203                         indx = listOfElementsSubNode.indexOf(next.getName());
204                     }
205                     break;
206                 case SRLG:
207                     if (listOfElementsSRLG.contains(next.getName())) {
208                         indx = listOfElementsSRLG.indexOf(next.getName());
209                     }
210                     break;
211                 case CLLI:
212                     if (listOfElementsCLLI.contains(next.getName())) {
213                         indx = listOfElementsCLLI.indexOf(next.getName());
214                     }
215                     break;
216                 default:
217                     LOG.warn(" in checkInclude vertex list unsupported resource type: [{}]", next.getType());
218             }
219
220             if (indx < 0) {
221                 LOG.debug(" in checkInclude stopped : {} ", next.getName());
222                 return false;
223             }
224
225             LOG.debug(" in checkInclude next found {} in {}", next.getName(), path.getVertexList());
226
227             listOfElementsSubNode.subList(0, indx).clear();
228             listOfElementsCLLI.subList(0, indx).clear();
229             listOfElementsSRLG.subList(0, indx).clear();
230         }
231
232         LOG.info(" in checkInclude passed : {} ", path.getVertexList());
233         return true;
234     }
235
236     private List<String> listOfElementsBuild(List<PceGraphEdge> pathEdges, PceConstraints.ResourceType type,
237         PceConstraints pceHardConstraints) {
238
239         List<String> listOfElements = new ArrayList<String>();
240         for (PceGraphEdge link : pathEdges) {
241             switch (type) {
242                 case NODE:
243                     listOfElements.add(link.link().getdestNetworkSupNodeId());
244                     break;
245                 case CLLI:
246                     listOfElements.add(link.link().getdestCLLI());
247                     break;
248                 case SRLG:
249                     if (link.link().getlinkType() != OpenroadmLinkType.ROADMTOROADM) {
250                         listOfElements.add("NONE");
251                         break;
252                     }
253                     // srlg of link is List<Long>. But in this algo we need string representation of
254                     // one SRLG
255                     // this should be any SRLG mentioned in include constraints if any of them if
256                     // mentioned
257                     boolean found = false;
258                     for (Long srlg : link.link().getsrlgList()) {
259                         String srlgStr = String.valueOf(srlg);
260                         if (pceHardConstraints.getSRLGnames().contains(srlgStr)) {
261                             listOfElements.add(srlgStr);
262                             LOG.info("listOfElementsBuild. FOUND SRLG {} in link {}", srlgStr, link.link());
263                             found = true;
264                             continue;
265                         }
266                     }
267                     if (!found) {
268                         // there is no specific srlg to include. thus add to list just the first one
269                         listOfElements.add("NONE");
270                     }
271                     break;
272                 default:
273                     LOG.debug("listOfElementsBuild unsupported resource type");
274             }
275         }
276         return listOfElements;
277     }
278
279     private Map<String, Integer> chooseTribPort(GraphPath<String,
280         PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes) {
281         LOG.info("In choosetribPort: edgeList = {} ", path.getEdgeList().toString());
282         Map<String, Integer> tribPortMap = new HashMap<>();
283
284         for (PceGraphEdge edge : path.getEdgeList()) {
285             NodeId linkSrcNode = edge.link().getSourceId();
286             String linkSrcTp = edge.link().getSourceTP().toString();
287             NodeId linkDestNode = edge.link().getDestId();
288             String linkDestTp = edge.link().getDestTP().toString();
289             PceNode pceOtnNodeSrc = allPceNodes.get(linkSrcNode);
290             PceNode pceOtnNodeDest = allPceNodes.get(linkDestNode);
291             List<Integer> srcTpnPool = pceOtnNodeSrc.getAvailableTribPorts().get(linkSrcTp);
292             List<Integer> destTpnPool = pceOtnNodeDest.getAvailableTribPorts().get(linkDestTp);
293             List<Integer> commonEdgeTpnPool = new ArrayList<>();
294             for (Integer integer : srcTpnPool) {
295                 if (destTpnPool.contains(integer)) {
296                     commonEdgeTpnPool.add(integer);
297                 }
298             }
299             Collections.sort(commonEdgeTpnPool);
300             if (!commonEdgeTpnPool.isEmpty()) {
301                 tribPortMap.put(edge.link().getLinkId().getValue(), commonEdgeTpnPool.get(0));
302             }
303         }
304         tribPortMap.forEach((k,v) -> LOG.info("TribPortMap : k = {}, v = {}", k, v));
305         return tribPortMap;
306     }
307
308     private Map<String, List<Integer>> chooseTribSlot(GraphPath<String,
309         PceGraphEdge> path, Map<NodeId, PceNode> allPceNodes, int nbSlot) {
310         LOG.info("In choosetribSlot2: edgeList = {} ", path.getEdgeList().toString());
311         Map<String, List<Integer>> tribSlotMap = new HashMap<>();
312
313         for (PceGraphEdge edge : path.getEdgeList()) {
314             NodeId linkSrcNode = edge.link().getSourceId();
315             String linkSrcTp = edge.link().getSourceTP().toString();
316             NodeId linkDestNode = edge.link().getDestId();
317             String linkDestTp = edge.link().getDestTP().toString();
318             PceNode pceOtnNodeSrc = allPceNodes.get(linkSrcNode);
319             PceNode pceOtnNodeDest = allPceNodes.get(linkDestNode);
320             List<Integer> srcTsPool = pceOtnNodeSrc.getAvailableTribSlots().get(linkSrcTp);
321             List<Integer> destTsPool = pceOtnNodeDest.getAvailableTribSlots().get(linkDestTp);
322             List<Integer> commonEdgeTsPool = new ArrayList<>();
323             List<Integer> tribSlotList = new ArrayList<>();
324             for (Integer integer : srcTsPool) {
325                 if (destTsPool.contains(integer)) {
326                     commonEdgeTsPool.add(integer);
327                 }
328             }
329             Collections.sort(commonEdgeTsPool);
330             boolean discontinue = true;
331             int index = 0;
332             while (discontinue && (commonEdgeTsPool.size() - index >= nbSlot)) {
333                 discontinue = false;
334                 Integer val = commonEdgeTsPool.get(index);
335                 for (int i = 0; i < nbSlot; i++) {
336                     if (commonEdgeTsPool.get(index + i).equals(val + i)) {
337                         tribSlotList.add(commonEdgeTsPool.get(index + i));
338                     } else {
339                         discontinue = true;
340                         tribSlotList.clear();
341                         index += i;
342                         break;
343                     }
344                 }
345             }
346             tribSlotMap.put(edge.link().getLinkId().getValue(), tribSlotList);
347         }
348         tribSlotMap.forEach((k,v) -> LOG.info("TribSlotMap : k = {}, v = {}", k, v));
349         return tribSlotMap;
350     }
351
352     private List<List<Integer>> chooseTribSlot3(GraphPath<String, PceGraphEdge> path,
353         Map<NodeId, PceNode> allPceNodes) {
354         List<List<Integer>> tribSlot = new ArrayList<>();
355         boolean statusOK = true;
356         boolean check = false;
357         Object nodeClass = allPceNodes.getClass();
358         if (nodeClass.getClass().isInstance(PceNode.class)) {
359             LOG.debug("In choosetribSlot: AllPceNodes contains PceNode instance, no trib port search");
360             return tribSlot;
361         } else if (nodeClass.getClass().isInstance(PceNode.class)) {
362             LOG.debug("In choosetribPort: {} {}", path.getLength(), path.toString());
363         }
364         for (PceGraphEdge edge : path.getEdgeList()) {
365             LOG.debug("In chooseTribSlot: source {} ", edge.link().getSourceId().toString());
366             PceNode pceNode = allPceNodes.get(edge.link().getSourceId());
367             Object tps = allPceNodes.get(edge.link().getSourceTP());
368             Object tpd = allPceNodes.get(edge.link().getDestTP());
369             if ((pceNode.getAvailableTribSlots().containsKey(tps.toString()))
370                 && (pceNode.getAvailableTribSlots().containsKey(tpd.toString()))) {
371                 List<Integer> tribSlotEdgeSourceN = new ArrayList<>();
372                 List<Integer> tribSlotEdgeDestN = new ArrayList<>();
373                 tribSlotEdgeSourceN = pceNode.getAvailableTribSlots().get(tps.toString());
374                 tribSlotEdgeDestN = pceNode.getAvailableTribSlots().get(tps.toString());
375                 check = false;
376                 for (int i = 0; i <= 79; i++) {
377                     if (tribSlotEdgeSourceN.get(i) == null) {
378                         break;
379                     }
380                     // TODO This will need to be modified as soon as the trib-slots allocation per
381                     // trib-port
382                     // policy applied by the different manufacturer is known
383                     if (tribSlotEdgeSourceN.get(i) == tribSlotEdgeDestN.get(i)) {
384                         check = true;
385                     } else {
386                         check = false;
387                         LOG.debug("In chooseTribSlot: Misalignement of trib slots between source {} and dest {}",
388                             edge.link().getSourceId().toString(), edge.link().getDestId().toString());
389                         break;
390                     }
391                 }
392                 if (check) {
393                     tribSlot.add(tribSlotEdgeSourceN);
394                 }
395             } else {
396                 LOG.debug("In chooseTribSlot: source {} does not have provisonned hosting HO interface ",
397                     edge.link().getSourceId().toString());
398                 statusOK = false;
399             }
400         }
401         if (statusOK && check) {
402             return tribSlot;
403         } else {
404             tribSlot.clear();
405             return tribSlot;
406         }
407     }
408
409     // Check the path OSNR
410     private boolean checkOSNR(GraphPath<String, PceGraphEdge> path) {
411         double linkOsnrDb;
412         double osnrDb = 0;
413         LOG.info("- In checkOSNR: OSNR of the transmitter = {} dB", TRX_OSNR);
414         LOG.info("- In checkOSNR: add-path incremental OSNR = {} dB", ADD_OSNR);
415         double inverseLocalOsnr = getInverseOsnrLinkLu(TRX_OSNR) + getInverseOsnrLinkLu(ADD_OSNR);
416         for (PceGraphEdge edge : path.getEdgeList()) {
417             if (edge.link().getlinkType() == OpenroadmLinkType.ROADMTOROADM) {
418                 // link OSNR in dB
419                 linkOsnrDb = edge.link().getosnr();
420                 LOG.info("- In checkOSNR: OSNR of {} = {} dB", edge.link().getLinkId().getValue(), linkOsnrDb);
421                 // 1 over the local OSNR, in linear units
422                 inverseLocalOsnr += getInverseOsnrLinkLu(linkOsnrDb);
423             }
424         }
425         try {
426             osnrDb = getOsnrDb(1 / inverseLocalOsnr);
427         } catch (ArithmeticException e) {
428             LOG.debug("In checkOSNR: OSNR is equal to 0 and the number of links is: {}", path.getEdgeList().size());
429             return false;
430         }
431         LOG.info("In checkOSNR: OSNR of the path is {} dB", osnrDb);
432         if ((osnrDb + SYS_MARGIN) < MIN_OSNR_W100G) {
433             return false;
434         }
435         return true;
436     }
437
438     private double getOsnrDb(double osnrLu) {
439         double osnrDb;
440         osnrDb = 10 * Math.log10(osnrLu);
441         return osnrDb;
442     }
443
444     private double getInverseOsnrLinkLu(double linkOsnrDb) {
445         // 1 over the link OSNR, in linear units
446         double linkOsnrLu;
447         linkOsnrLu = Math.pow(10, (linkOsnrDb / 10.0));
448         LOG.debug("In retrieveosnr: the inverse of link osnr is {} (Linear Unit)", linkOsnrLu);
449         return (CONST_OSNR / linkOsnrLu);
450     }
451
452 }