eb94fa6bd67d2413f5f0d75c9cc4ab4c037e4708
[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
104         if (this.linkType == OpenroadmLinkType.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         } else if (this.linkType == OpenroadmLinkType.OTNLINK) {
118             this.availableBandwidth = MapUtils.getAvailableBandwidth(link);
119             this.usedBandwidth = MapUtils.getUsedBandwidth(link);
120             this.srlgList = MapUtils.getSRLGfromLink(link);
121             this.latency = 0L;
122             this.length = 0.0;
123             this.omsAttributesSpan = null;
124             this.spanLoss = 0.0;
125             this.powerCorrection = 0.0;
126             this.cd = 0.0;
127             this.pmd2 = 0.0;
128         } else {
129             this.omsAttributesSpan = null;
130             this.srlgList = null;
131             this.latency = 0L;
132             this.length = 0.0;
133             this.availableBandwidth = 0L;
134             this.usedBandwidth = 0L;
135             this.spanLoss = 0.0;
136             this.powerCorrection = 0.0;
137             this.cd = 0.0;
138             this.pmd2 = 0.0;
139         }
140         LOG.debug("PceLink: created PceLink  {}", linkId);
141     }
142
143     //Retrieve the opposite link
144     private LinkId calcOpposite(Link link) {
145         LinkId tmpoppositeLink = MapUtils.extractOppositeLink(link);
146         if (tmpoppositeLink == null) {
147             LOG.error("PceLink: Error calcOpposite. Link is ignored {}", link.getLinkId().getValue());
148             isValid = false;
149         }
150         return tmpoppositeLink;
151     }
152
153     //Compute the link latency : if the latency is not defined, the latency is computed from the length
154     private Long calcLatency(Link link) {
155         Link1 link1 = link.augmentation(Link1.class);
156         if (link1.getLinkLatency() != null) {
157             return link1.getLinkLatency().toJava();
158         }
159         Double linkLength = calcLength(link);
160         if (linkLength == null) {
161             LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
162             return 1L;
163         }
164         LOG.debug("In PceLink: The latency of link {} is extrapolated from link length and == {}",
165             link.getLinkId(), linkLength / GLASSCELERITY);
166         return (long) Math.ceil(linkLength / GLASSCELERITY);
167     }
168
169     private Double calcLength(Link link) {
170         Link1 link1 = link.augmentation(Link1.class);
171         if (link1.getLinkLength() != null) {
172             return link1.getLinkLength().doubleValue();
173         }
174         if (this.omsAttributesSpan == null) {
175             LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
176             return null;
177         }
178         double linkLength = 0;
179         Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap = this.omsAttributesSpan
180             .nonnullLinkConcatenation();
181         for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
182             // Length is expressed in meter according to OpenROADM MSA
183             if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null) {
184                 LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
185                 return null;
186             }
187             linkLength += entry.getValue().getSRLGLength().doubleValue();
188             LOG.debug("In PceLink: The length of the link {} == {}", link.getLinkId(), linkLength / 1000.0);
189         }
190         return (linkLength / 1000.0);
191     }
192
193     //Calculate CD and PMD of the link from link length
194     private Map<String, Double> calcCDandPMDfromLength() {
195         Map<String, Double> cdAndPmd = new HashMap<>();
196         if (this.length != null) {
197             cdAndPmd.put("CD", 16.5 * this.length);
198             cdAndPmd.put("PMD2", Math.pow(this.length * PMD_CONSTANT, 2));
199         }
200         return cdAndPmd;
201     }
202
203     //Calculate CD and PMD of the link
204     private Map<String, Double> calcCDandPMD(Link link) {
205         double linkCd = 0.0;
206         double linkPmd2 = 0.0;
207         if (this.omsAttributesSpan == null) {
208             LOG.debug("In PceLink {} no OMS present, assume G.652 fiber, calculation based on fiber length of {} km",
209                 link.getLinkId(), this.length);
210             return calcCDandPMDfromLength();
211         }
212         Map<LinkConcatenationKey, LinkConcatenation> linkConcatenationMap = this.omsAttributesSpan
213             .nonnullLinkConcatenation();
214         for (Map.Entry<LinkConcatenationKey, LinkConcatenation> entry : linkConcatenationMap.entrySet()) {
215             // If the link-concatenation list is not populated or partially populated CD &
216             // PMD shall be derived from link-length (expressed in km in OR topology)
217             if (entry == null || entry.getValue() == null || entry.getValue().getSRLGLength() == null
218                     || entry.getValue().augmentation(LinkConcatenation1.class).getFiberType() == null) {
219                 if (this.length > 0.0) {
220                     LOG.debug("In PceLink: no OMS present; cd and PMD for the link {} extrapolated from link length {}"
221                         + "assuming SMF fiber type", link.getLinkId().getValue(), this.length);
222                     return calcCDandPMDfromLength();
223                 }
224                 // If Link-length upper attributes not present or incorrectly populated, no way
225                 // to calculate CD & PMD
226                 LOG.error("In PceLink: no Link length declared and no OMS present for the link {}."
227                     + " No Way to compute CD and PMD", link.getLinkId().getValue());
228                 return Map.of();
229             }
230             // SRLG length is expressed in OR topology in meter
231             linkCd += entry.getValue().getSRLGLength().doubleValue() / 1000.0 * retrieveCdFromFiberType(
232                 entry.getValue().augmentation(LinkConcatenation1.class).getFiberType());
233             if (entry.getValue().augmentation(LinkConcatenation1.class).getPmd() == null
234                     || entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue().doubleValue() == 0.0
235                     || entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue()
236                     .toString().isEmpty()) {
237                 linkPmd2 += Math.pow(entry.getValue().getSRLGLength().doubleValue() / 1000.0
238                     * retrievePmdFromFiberType(entry.getValue().augmentation(LinkConcatenation1.class)
239                     .getFiberType()),2);
240             } else {
241                 linkPmd2 += Math
242                     .pow(entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue().doubleValue(), 2);
243             }
244         }
245         LOG.debug("In PceLink: The CD and PMD2 of link {} are respectively {} ps and {} ps", link.getLinkId(), linkCd,
246             linkPmd2);
247         return Map.of("CD", linkCd,"PMD2", linkPmd2);
248     }
249
250     // compute default spanLoss and power correction from fiber length
251     // when no OMS attribute defined
252     private Map<String, Double> calcDefaultSpanLoss(Link link) {
253         Map<String, Double> omsExtrapolatedCharac = new HashMap<>();
254         Link1 link1 = link.augmentation(Link1.class);
255         if (link1.getLinkLength() == null || link1.getLinkLength().doubleValue() == 0) {
256             LOG.error("In PceLink, no link length present or length declared = 0,"
257                 + " unable to calculate default span Loss ");
258             return omsExtrapolatedCharac;
259         }
260         long linkLength = link1.getLinkLength().longValue();
261         LOG.warn("In PceLink {}, assume G.652 fiber, calculation "
262             + "based on fiber length of {} km and typical loss of 0.25dB per Km ",
263             link.getLinkId(), linkLength);
264         omsExtrapolatedCharac.put("SpanLoss", linkLength * 0.25);
265         omsExtrapolatedCharac.put("PoutCorrection", retrievePower(FiberType.Smf));
266         return omsExtrapolatedCharac;
267     }
268
269     // Compute the attenuation of a span from OMS attribute
270     private Map<String, Double> calcSpanLoss(Link link) {
271         if (this.omsAttributesSpan == null) {
272             return calcDefaultSpanLoss(link);
273         }
274         Collection<LinkConcatenation> linkConcatenationList = this.omsAttributesSpan.nonnullLinkConcatenation()
275             .values();
276         if (linkConcatenationList == null) {
277             LOG.error("in PceLink : Null field in the OmsAttrubtesSpan");
278             return calcDefaultSpanLoss(link);
279         }
280         Iterator<LinkConcatenation> linkConcatenationiterator = linkConcatenationList.iterator();
281         if (!linkConcatenationiterator.hasNext()) {
282             return calcDefaultSpanLoss(link);
283         }
284         // Reference of power to be launched at input of ROADM (dBm)
285         Map<String, Double> omsCharacteristics = new HashMap<>();
286         omsCharacteristics.put("PoutCorrection",
287             retrievePower(linkConcatenationiterator.next().augmentation(LinkConcatenation1.class)
288                 .getFiberType()) - 2.0);
289         // span loss of the span
290         omsCharacteristics.put("SpanLoss", this.omsAttributesSpan.getSpanlossCurrent().getValue().doubleValue());
291         return omsCharacteristics;
292     }
293
294     private double retrievePower(FiberType fiberType) {
295         double power;
296         switch (fiberType) {
297             case Smf:
298                 power = 2;
299                 break;
300             case Eleaf:
301                 power = 1;
302                 break;
303             case Truewavec:
304                 power = -1;
305                 break;
306             case Oleaf:
307             case Dsf:
308             case Truewave:
309             case NzDsf:
310             case Ull:
311             default:
312                 power = 0;
313                 break;
314         }
315         return power;
316     }
317
318     private double retrievePmdFromFiberType(FiberType fiberType) {
319         if (fiberType.toString().equalsIgnoreCase("Dsf")) {
320             return 0.2;
321         } else {
322             return PMD_CONSTANT;
323         }
324     }
325
326     private double retrieveCdFromFiberType(FiberType fiberType) {
327         double cdPerKm;
328         switch (fiberType) {
329             case Smf:
330                 cdPerKm = 16.5;
331                 break;
332             case Eleaf:
333                 cdPerKm = 4.3;
334                 break;
335             case Truewavec:
336                 cdPerKm = 3.0;
337                 break;
338             case Oleaf:
339                 cdPerKm = 4.3;
340                 break;
341             case Dsf:
342                 cdPerKm = 0.0;
343                 break;
344             case Truewave:
345                 cdPerKm = 4.4;
346                 break;
347             case NzDsf:
348                 cdPerKm = 4.3;
349                 break;
350             case Ull:
351                 cdPerKm = 16.5;
352                 break;
353             default:
354                 cdPerKm = 16.5;
355                 break;
356         }
357         return cdPerKm;
358     }
359
360     public LinkId getOppositeLink() {
361         return oppositeLink;
362     }
363
364     public AdminStates getAdminStates() {
365         return adminStates;
366     }
367
368     public State getState() {
369         return state;
370     }
371
372     public TpId getSourceTP() {
373         return sourceTP;
374     }
375
376     public TpId getDestTP() {
377         return destTP;
378     }
379
380     public OpenroadmLinkType getlinkType() {
381         return linkType;
382     }
383
384     public LinkId getLinkId() {
385         return linkId;
386     }
387
388     public NodeId getSourceId() {
389         return sourceId;
390     }
391
392     public NodeId getDestId() {
393         return destId;
394     }
395
396     public String getClient() {
397         return client;
398     }
399
400     public Double getLength() {
401         return length;
402     }
403
404     public void setClient(String client) {
405         this.client = client;
406     }
407
408     // Double for transformer of JUNG graph
409     public Double getLatency() {
410         return latency.doubleValue();
411     }
412
413     public Long getAvailableBandwidth() {
414         return availableBandwidth;
415     }
416
417     public Long getUsedBandwidth() {
418         return usedBandwidth;
419     }
420
421     public String getsourceNetworkSupNodeId() {
422         return sourceNetworkSupNodeId;
423     }
424
425     public String getdestNetworkSupNodeId() {
426         return destNetworkSupNodeId;
427     }
428
429     public List<Long> getsrlgList() {
430         return srlgList;
431     }
432
433     public String getsourceCLLI() {
434         return sourceCLLI;
435     }
436
437     public String getdestCLLI() {
438         return destCLLI;
439     }
440
441     public Double getspanLoss() {
442         return spanLoss;
443     }
444
445     public Double getcd() {
446         return cd;
447     }
448
449     public Double getpmd2() {
450         return pmd2;
451     }
452
453     public Double getpowerCorrection() {
454         return powerCorrection;
455     }
456
457     public boolean isValid() {
458         if ((this.linkId == null) || (this.linkType == null) || (this.oppositeLink == null)) {
459             isValid = false;
460             LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
461         }
462         isValid = checkParams();
463         if (this.linkType == OpenroadmLinkType.ROADMTOROADM) {
464             if ((this.length == null || this.length == 0.0)
465                     && this.omsAttributesSpan == null) {
466                 isValid = false;
467                 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
468                     + " Link is ignored {}", linkId);
469             } else if ((this.length == null || this.length == 0.0)
470                     && this.omsAttributesSpan.getSpanlossCurrent() == null) {
471                 isValid = false;
472                 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
473                     + " Link is ignored {}", linkId);
474             }
475         }
476         if (this.srlgList != null && this.srlgList.isEmpty()) {
477             isValid = false;
478             LOG.error("PceLink: Empty srlgList for OMS link. Link is ignored {}", linkId);
479         }
480         return isValid;
481     }
482
483     public boolean isOtnValid(Link link, String serviceType) {
484
485         if (this.linkType != OpenroadmLinkType.OTNLINK) {
486             LOG.error("PceLink: Not an OTN link. Link is ignored {}", linkId);
487             return false;
488         }
489
490         OtnLinkType otnLinkType = link
491             .augmentation(org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils
492                     .rev220630.Link1.class)
493             .getOtnLinkType();
494         if (this.availableBandwidth == 0L) {
495             LOG.error("PceLink: No bandwidth available for OTN Link, link {}  is ignored ", linkId);
496             return false;
497         }
498
499         long neededBW;
500         OtnLinkType neededType = null;
501         switch (serviceType) {
502             case "ODUC2":
503                 if (this.usedBandwidth != 0L) {
504                     return false;
505                 }
506                 neededBW = 200000L;
507                 // Add intermediate rate otn-link-type
508                 neededType = OtnLinkType.OTUC2;
509                 break;
510             case "ODUC3":
511                 if (this.usedBandwidth != 0L) {
512                     return false;
513                 }
514                 neededBW = 300000L;
515                 // change otn-link-type
516                 neededType = OtnLinkType.OTUC3;
517                 break;
518             case "ODUC4":
519                 if (this.usedBandwidth != 0L) {
520                     return false;
521                 }
522                 neededBW = 400000L;
523                 neededType = OtnLinkType.OTUC4;
524                 break;
525             case "ODU4":
526             case "100GEs":
527                 if (this.usedBandwidth != 0L) {
528                     return false;
529                 }
530                 neededBW = 100000L;
531                 neededType = OtnLinkType.OTU4;
532                 break;
533             case "ODU2":
534             case "ODU2e":
535                 neededBW = 12500L;
536                 break;
537             case "ODU0":
538                 neededBW = 1250L;
539                 break;
540             case "ODU1":
541                 neededBW = 2500L;
542                 break;
543             case "100GEm":
544                 neededBW = 100000L;
545                 // TODO: Here link type needs to be changed, based on the line-rate
546                 neededType = OtnLinkType.ODUC4;
547                 break;
548             case "10GE":
549                 neededBW = 10000L;
550                 neededType = OtnLinkType.ODTU4;
551                 break;
552             case "1GE":
553                 neededBW = 1000L;
554                 neededType = OtnLinkType.ODTU4;
555                 break;
556             default:
557                 LOG.error("PceLink: isOtnValid Link {} unsupported serviceType {} ", linkId, serviceType);
558                 return false;
559         }
560
561         if ((this.availableBandwidth >= neededBW)
562             && ((neededType == null) || (neededType.equals(otnLinkType)))) {
563             LOG.debug("PceLink: Selected Link {} has available bandwidth and is eligible for {} creation ",
564                 linkId, serviceType);
565         }
566
567         return checkParams();
568     }
569
570     private boolean checkParams() {
571         if ((this.linkId == null) || (this.linkType == null) || (this.oppositeLink == null)) {
572             LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
573             return false;
574         }
575         if ((this.adminStates == null) || (this.state == null)) {
576             LOG.error("PceLink: Link is not available. Link is ignored {}", linkId);
577             return false;
578         }
579         if ((this.sourceId == null) || (this.destId == null) || (this.sourceTP == null) || (this.destTP == null)) {
580             LOG.error("PceLink: No Link source or destination is available. Link is ignored {}", linkId);
581             return false;
582         }
583         if ((this.sourceNetworkSupNodeId.equals("")) || (this.destNetworkSupNodeId.equals(""))) {
584             LOG.error("PceLink: No Link source SuppNodeID or destination SuppNodeID is available. Link is ignored {}",
585                 linkId);
586             return false;
587         }
588         if ((this.sourceCLLI.equals("")) || (this.destCLLI.equals(""))) {
589             LOG.error("PceLink: No Link source CLLI or destination CLLI is available. Link is ignored {}", linkId);
590             return false;
591         }
592
593         return true;
594     }
595
596     @Override
597     public String toString() {
598         return "PceLink type=" + linkType + " ID=" + linkId.getValue() + " latency=" + latency;
599     }
600 }