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