Add perltidy to pre-commit linters
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / networkanalyzer / PceLink.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.networkanalyzer;
10
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.io.Serializable;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
19 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.Link1;
20 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
21 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
22 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.span.attributes.LinkConcatenation1;
23 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.span.attributes.LinkConcatenation1.FiberType;
24 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev230526.networks.network.link.oms.attributes.Span;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmLinkType;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.link.concatenation.LinkConcatenation;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.link.concatenation.LinkConcatenationKey;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 @SuppressWarnings("serial")
36 @SuppressFBWarnings(
37     value = "SE_NO_SERIALVERSIONID",
38     justification = "https://github.com/rzwitserloot/lombok/wiki/WHY-NOT:-serialVersionUID")
39 public class PceLink implements Serializable {
40
41     /* Logging. */
42     private static final Logger LOG = LoggerFactory.getLogger(PceLink.class);
43     ///////////////////////// LINKS ////////////////////
44     /*
45      * extension of Link to include constraints and Graph weight
46      */
47     double weight = 0;
48     private boolean isValid = true;
49
50     // this member is for XPONDER INPUT/OUTPUT links.
51     // it keeps name of client corresponding to NETWORK TP
52     private String clientA = "";
53     private String clientZ = "";
54     private final LinkId linkId;
55     private final OpenroadmLinkType linkType;
56     private final NodeId sourceId;
57     private final NodeId destId;
58     private final TpId sourceTP;
59     private final TpId destTP;
60     private final String sourceNetworkSupNodeId;
61     private final String destNetworkSupNodeId;
62     private final String sourceCLLI;
63     private final String destCLLI;
64     private final LinkId oppositeLink;
65     private final AdminStates adminStates;
66     private final State state;
67     private final Long latency;
68     private final Long availableBandwidth;
69     private final Long usedBandwidth;
70     private final List<Long> srlgList;
71 //    private final double osnr;
72     private final Double length;
73     private final Double cd;
74     private final Double pmd2;
75     private final Double spanLoss;
76     private final Double powerCorrection;
77     private final transient Span omsAttributesSpan;
78     //meter per ms
79     private static final double GLASSCELERITY = 2.99792458 * 1e5 / 1.5;
80     private static final double PMD_CONSTANT = 0.04;
81
82     public PceLink(Link link, PceNode source, PceNode dest) {
83         LOG.debug("PceLink: : PceLink start ");
84
85         this.linkId = link.getLinkId();
86
87         this.sourceId = link.getSource().getSourceNode();
88         this.destId = link.getDestination().getDestNode();
89
90         this.sourceTP = link.getSource().getSourceTp();
91         this.destTP = link.getDestination().getDestTp();
92
93         this.sourceNetworkSupNodeId = source.getSupNetworkNodeId();
94         this.destNetworkSupNodeId = dest.getSupNetworkNodeId();
95
96         this.sourceCLLI = source.getSupClliNodeId();
97         this.destCLLI = dest.getSupClliNodeId();
98
99         this.linkType = MapUtils.calcType(link);
100
101         this.oppositeLink = calcOpposite(link);
102
103         this.adminStates = link.augmentation(Link1.class).getAdministrativeState();
104         this.state = link.augmentation(Link1.class).getOperationalState();
105         switch (this.linkType) {
106             case ROADMTOROADM:
107                 this.omsAttributesSpan = MapUtils.getOmsAttributesSpan(link);
108                 this.length = calcLength(link);
109                 this.srlgList = MapUtils.getSRLG(link);
110                 this.latency = calcLatency(link);
111                 this.availableBandwidth = 0L;
112                 this.usedBandwidth = 0L;
113                 Map<String, Double> spanLossMap = calcSpanLoss(link);
114                 this.spanLoss = spanLossMap.get("SpanLoss");
115                 this.powerCorrection = spanLossMap.get("PoutCorrection");
116                 Map<String, Double> cdAndPmdMap = calcCDandPMD(link);
117                 this.cd = cdAndPmdMap.get("CD");
118                 this.pmd2 = cdAndPmdMap.get("PMD2");
119                 break;
120             case OTNLINK:
121                 this.availableBandwidth = MapUtils.getAvailableBandwidth(link);
122                 this.usedBandwidth = MapUtils.getUsedBandwidth(link);
123                 this.srlgList = MapUtils.getSRLGfromLink(link);
124                 this.latency = 0L;
125                 this.length = 0.0;
126                 this.omsAttributesSpan = null;
127                 this.spanLoss = 0.0;
128                 this.powerCorrection = 0.0;
129                 this.cd = 0.0;
130                 this.pmd2 = 0.0;
131                 break;
132             default:
133                 this.omsAttributesSpan = null;
134                 this.srlgList = null;
135                 this.latency = 0L;
136                 this.length = 0.0;
137                 this.availableBandwidth = 0L;
138                 this.usedBandwidth = 0L;
139                 this.spanLoss = 0.0;
140                 this.powerCorrection = 0.0;
141                 this.cd = 0.0;
142                 this.pmd2 = 0.0;
143                 break;
144         }
145         LOG.debug("PceLink: created PceLink  {}", linkId);
146     }
147
148     //Retrieve the opposite link
149     private LinkId calcOpposite(Link link) {
150         LinkId tmpoppositeLink = MapUtils.extractOppositeLink(link);
151         if (tmpoppositeLink == null) {
152             LOG.error("PceLink: Error calcOpposite. Link is ignored {}", link.getLinkId().getValue());
153             isValid = false;
154         }
155         return tmpoppositeLink;
156     }
157
158     //Compute the link latency : if the latency is not defined, the latency is computed from the length
159     private Long calcLatency(Link link) {
160         var augLinkLatency = link.augmentation(Link1.class).getLinkLatency();
161         if (augLinkLatency != null) {
162             return augLinkLatency.toJava();
163         }
164         Double linkLength = calcLength(link);
165         if (linkLength == null) {
166             LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
167             return 1L;
168         }
169         LOG.debug("In PceLink: The latency of link {} is extrapolated from link length and == {}",
170             link.getLinkId(), linkLength / GLASSCELERITY);
171         return (long) Math.ceil(linkLength / GLASSCELERITY);
172     }
173
174     private Double calcLength(Link link) {
175         var augLinkLength = link.augmentation(Link1.class).getLinkLength();
176         if (augLinkLength != null) {
177             return augLinkLength.doubleValue();
178         }
179         if (this.omsAttributesSpan == null) {
180             LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
181             return null;
182         }
183         double linkLength = 0;
184         Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap =
185             this.omsAttributesSpan.nonnullLinkConcatenation();
186         for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
187             // Length is expressed in meter according to OpenROADM MSA
188             if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null) {
189                 LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
190                 return null;
191             }
192             linkLength += entry.getValue().getSRLGLength().doubleValue();
193             LOG.debug("In PceLink: The length of the link {} == {}", link.getLinkId(), linkLength / 1000.0);
194         }
195         return linkLength / 1000.0;
196     }
197
198     //Calculate CD and PMD of the link from link length
199     private Map<String, Double> calcCDandPMDfromLength() {
200         return this.length == null
201             ? new HashMap<>()
202             : new HashMap<>(
203                 Map.of(
204                     "CD", 16.5 * this.length,
205                     "PMD2", Math.pow(this.length * PMD_CONSTANT, 2)));
206     }
207
208     //Calculate CD and PMD of the link
209     private Map<String, Double> calcCDandPMD(Link link) {
210         double linkCd = 0.0;
211         double linkPmd2 = 0.0;
212         if (this.omsAttributesSpan == null) {
213             LOG.debug("In PceLink {} no OMS present, assume G.652 fiber, calculation based on fiber length of {} km",
214                 link.getLinkId(), this.length);
215             return calcCDandPMDfromLength();
216         }
217         Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap =
218             this.omsAttributesSpan.nonnullLinkConcatenation();
219         for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
220             // If the link-concatenation list is not populated or partially populated CD &
221             // PMD shall be derived from link-length (expressed in km in OR topology)
222             if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null
223                     || entry.getValue().augmentation(LinkConcatenation1.class).getFiberType() == null) {
224                 if (this.length > 0.0) {
225                     LOG.debug("In PceLink: no OMS present; cd and PMD for the link {} extrapolated from link length {}"
226                         + "assuming SMF fiber type", link.getLinkId().getValue(), this.length);
227                     return calcCDandPMDfromLength();
228                 }
229                 // If Link-length upper attributes not present or incorrectly populated, no way
230                 // to calculate CD & PMD
231                 LOG.error("In PceLink: no Link length declared and no OMS present for the link {}."
232                     + " No Way to compute CD and PMD", link.getLinkId().getValue());
233                 return Map.of();
234             }
235             // SRLG length is expressed in OR topology in meter
236             var entryAug = entry.getValue().augmentation(LinkConcatenation1.class);
237             linkCd += entry.getValue().getSRLGLength().doubleValue() / 1000.0
238                 * retrieveCdFromFiberType(entryAug.getFiberType());
239             if (entryAug.getPmd() == null
240                     || entryAug.getPmd().getValue().doubleValue() == 0.0
241                     || entryAug.getPmd().getValue().toString().isEmpty()) {
242                 linkPmd2 += Math.pow(
243                     entry.getValue().getSRLGLength().doubleValue() / 1000.0
244                         * retrievePmdFromFiberType(entryAug.getFiberType()),
245                     2);
246             } else {
247                 linkPmd2 += Math.pow(entryAug.getPmd().getValue().doubleValue(), 2);
248             }
249         }
250         LOG.debug("In PceLink: The CD and PMD2 of link {} are respectively {} ps and {} ps",
251             link.getLinkId(), linkCd, linkPmd2);
252         return Map.of("CD", linkCd, "PMD2", linkPmd2);
253     }
254
255     // compute default spanLoss and power correction from fiber length
256     // when no OMS attribute defined
257     private Map<String, Double> calcDefaultSpanLoss(Link link) {
258         var augLinkLength = link.augmentation(Link1.class).getLinkLength();
259         if (augLinkLength == null || augLinkLength.doubleValue() == 0) {
260             LOG.error("In PceLink, no link length present or length declared = 0,"
261                 + " unable to calculate default span Loss ");
262             return new HashMap<>();
263         }
264         long linkLength = augLinkLength.longValue();
265         LOG.warn("In PceLink {}, assume G.652 fiber, calculation "
266                 + "based on fiber length of {} km and typical loss of 0.25dB per Km ",
267             link.getLinkId(), linkLength);
268         return new HashMap<>(
269             Map.of(
270                 "SpanLoss", linkLength * 0.25,
271                 "PoutCorrection", retrievePower(FiberType.Smf)
272             ));
273     }
274
275     // Compute the attenuation of a span from OMS attribute
276     private Map<String, Double> calcSpanLoss(Link link) {
277         if (this.omsAttributesSpan == null) {
278             return calcDefaultSpanLoss(link);
279         }
280         Collection<LinkConcatenation> linkConcatenationList =
281             this.omsAttributesSpan.nonnullLinkConcatenation().values();
282         if (linkConcatenationList == null) {
283             LOG.error("in PceLink : Null field in the OmsAttrubtesSpan");
284             return calcDefaultSpanLoss(link);
285         }
286         Iterator<LinkConcatenation> linkConcatenationiterator = linkConcatenationList.iterator();
287         if (!linkConcatenationiterator.hasNext()) {
288             return calcDefaultSpanLoss(link);
289         }
290         // Reference of power to be launched at input of ROADM (dBm)
291         return new HashMap<>(Map.of(
292             "PoutCorrection", retrievePower(
293                 linkConcatenationiterator.next().augmentation(LinkConcatenation1.class).getFiberType()) - 2.0,
294             "SpanLoss", this.omsAttributesSpan.getSpanlossCurrent().getValue().doubleValue()));
295     }
296
297     private double retrievePower(FiberType fiberType) {
298         switch (fiberType) {
299             case Smf:
300                 return 2;
301             case Eleaf:
302                 return 1;
303             case Truewavec:
304                 return -1;
305             case Oleaf:
306             case Dsf:
307             case Truewave:
308             case NzDsf:
309             case Ull:
310             default:
311                 return 0;
312         }
313     }
314
315     private double retrievePmdFromFiberType(FiberType fiberType) {
316         return fiberType.toString().equalsIgnoreCase("Dsf")
317             ? 0.2
318             : PMD_CONSTANT;
319     }
320
321     private double retrieveCdFromFiberType(FiberType fiberType) {
322         switch (fiberType) {
323             case Dsf:
324                 return 0.0;
325             case Truewavec:
326                 return 3.0;
327             case Eleaf:
328             case Oleaf:
329             case NzDsf:
330                 return 4.3;
331             case Truewave:
332                 return 4.4;
333             case Smf:
334             case Ull:
335             default:
336                 return 16.5;
337         }
338     }
339
340     public LinkId getOppositeLink() {
341         return oppositeLink;
342     }
343
344     public AdminStates getAdminStates() {
345         return adminStates;
346     }
347
348     public State getState() {
349         return state;
350     }
351
352     public TpId getSourceTP() {
353         return sourceTP;
354     }
355
356     public TpId getDestTP() {
357         return destTP;
358     }
359
360     public OpenroadmLinkType getlinkType() {
361         return linkType;
362     }
363
364     public LinkId getLinkId() {
365         return linkId;
366     }
367
368     public NodeId getSourceId() {
369         return sourceId;
370     }
371
372     public NodeId getDestId() {
373         return destId;
374     }
375
376     public String getClientA() {
377         return clientA;
378     }
379
380     public Double getLength() {
381         return length;
382     }
383
384     public void setClientA(String client) {
385         this.clientA = client;
386     }
387
388     public String getClientZ() {
389         return clientZ;
390     }
391
392     public void setClientZ(String client) {
393         this.clientZ = client;
394     }
395
396     // Double for transformer of JUNG graph
397     public Double getLatency() {
398         return latency.doubleValue();
399     }
400
401     public Long getAvailableBandwidth() {
402         return availableBandwidth;
403     }
404
405     public Long getUsedBandwidth() {
406         return usedBandwidth;
407     }
408
409     public String getsourceNetworkSupNodeId() {
410         return sourceNetworkSupNodeId;
411     }
412
413     public String getdestNetworkSupNodeId() {
414         return destNetworkSupNodeId;
415     }
416
417     public List<Long> getsrlgList() {
418         return srlgList;
419     }
420
421     public String getsourceCLLI() {
422         return sourceCLLI;
423     }
424
425     public String getdestCLLI() {
426         return destCLLI;
427     }
428
429     public Double getspanLoss() {
430         return spanLoss;
431     }
432
433     public Double getcd() {
434         return cd;
435     }
436
437     public Double getpmd2() {
438         return pmd2;
439     }
440
441     public Double getpowerCorrection() {
442         return powerCorrection;
443     }
444
445     public boolean isValid() {
446         if (this.linkId == null || this.linkType == null || this.oppositeLink == null) {
447             isValid = false;
448             LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
449         }
450         isValid = checkParams();
451         if (this.linkType == OpenroadmLinkType.ROADMTOROADM && (this.length == null || this.length == 0.0)) {
452             if (this.omsAttributesSpan == null) {
453                 isValid = false;
454                 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
455                     + " Link is ignored {}", linkId);
456             } else if (this.omsAttributesSpan.getSpanlossCurrent() == null) {
457                 isValid = false;
458                 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
459                     + " Link is ignored {}", linkId);
460             }
461         }
462         if (this.srlgList != null && this.srlgList.isEmpty()) {
463             isValid = false;
464             LOG.error("PceLink: Empty srlgList for OMS link. Link is ignored {}", linkId);
465         }
466         return isValid;
467     }
468
469     public boolean isOtnValid(Link link, String serviceType) {
470
471         if (this.linkType != OpenroadmLinkType.OTNLINK) {
472             LOG.error("PceLink: Not an OTN link. Link is ignored {}", linkId);
473             return false;
474         }
475
476         if (this.availableBandwidth == 0L) {
477             LOG.error("PceLink: No bandwidth available for OTN Link, link {}  is ignored ", linkId);
478             return false;
479         }
480
481         long neededBW;
482         OtnLinkType neededType = null;
483         switch (serviceType) {
484             case "ODUC2":
485                 if (this.usedBandwidth != 0L) {
486                     return false;
487                 }
488                 neededBW = 200000L;
489                 // Add intermediate rate otn-link-type
490                 neededType = OtnLinkType.OTUC2;
491                 break;
492             case "ODUC3":
493                 if (this.usedBandwidth != 0L) {
494                     return false;
495                 }
496                 neededBW = 300000L;
497                 // change otn-link-type
498                 neededType = OtnLinkType.OTUC3;
499                 break;
500             case "ODUC4":
501                 if (this.usedBandwidth != 0L) {
502                     return false;
503                 }
504                 neededBW = 400000L;
505                 neededType = OtnLinkType.OTUC4;
506                 break;
507             case "ODU4":
508             case "100GEs":
509                 if (this.usedBandwidth != 0L) {
510                     return false;
511                 }
512                 neededBW = 100000L;
513                 neededType = OtnLinkType.OTU4;
514                 break;
515             case "ODU2":
516             case "ODU2e":
517                 neededBW = 12500L;
518                 break;
519             case "ODU0":
520                 neededBW = 1250L;
521                 break;
522             case "ODU1":
523                 neededBW = 2500L;
524                 break;
525             case "100GEm":
526                 neededBW = 100000L;
527                 // TODO: Here link type needs to be changed, based on the line-rate
528                 neededType = OtnLinkType.ODUC4;
529                 break;
530             case "10GE":
531                 neededBW = 10000L;
532                 neededType = OtnLinkType.ODTU4;
533                 break;
534             case "1GE":
535                 neededBW = 1000L;
536                 neededType = OtnLinkType.ODTU4;
537                 break;
538             default:
539                 LOG.error("PceLink: isOtnValid Link {} unsupported serviceType {} ", linkId, serviceType);
540                 return false;
541         }
542         if (this.availableBandwidth >= neededBW
543                 && (neededType == null
544                     || neededType.equals(
545                         link.augmentation(
546                                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630
547                                     .Link1.class)
548                             .getOtnLinkType()))) {
549             LOG.debug("PceLink: Selected Link {} has available bandwidth and is eligible for {} creation ",
550                 linkId, serviceType);
551         }
552         return checkParams();
553     }
554
555     private boolean checkParams() {
556         if (this.linkId == null || this.linkType == null || this.oppositeLink == null) {
557             LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
558             return false;
559         }
560         if (this.adminStates == null || this.state == null) {
561             LOG.error("PceLink: Link is not available. Link is ignored {}", linkId);
562             return false;
563         }
564         if (this.sourceId == null || this.destId == null || this.sourceTP == null || this.destTP == null) {
565             LOG.error("PceLink: No Link source or destination is available. Link is ignored {}", linkId);
566             return false;
567         }
568         if (this.sourceNetworkSupNodeId.equals("") || this.destNetworkSupNodeId.equals("")) {
569             LOG.error("PceLink: No Link source SuppNodeID or destination SuppNodeID is available. Link is ignored {}",
570                 linkId);
571             return false;
572         }
573         if (this.sourceCLLI.equals("") || this.destCLLI.equals("")) {
574             LOG.error("PceLink: No Link source CLLI or destination CLLI is available. Link is ignored {}", linkId);
575             return false;
576         }
577
578         return true;
579     }
580
581     @Override
582     public String toString() {
583         return "PceLink type=" + linkType + " ID=" + linkId.getValue() + " latency=" + latency;
584     }
585 }