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