2 * Copyright © 2017 AT&T, Inc. and others. All rights reserved.
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
9 package org.opendaylight.transportpce.pce.networkanalyzer;
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;
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;
35 @SuppressWarnings("serial")
37 value = "SE_NO_SERIALVERSIONID",
38 justification = "https://github.com/rzwitserloot/lombok/wiki/WHY-NOT:-serialVersionUID")
39 public class PceLink implements Serializable {
42 private static final Logger LOG = LoggerFactory.getLogger(PceLink.class);
43 ///////////////////////// LINKS ////////////////////
45 * extension of Link to include constraints and Graph weight
48 private boolean isValid = true;
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;
79 private static final double GLASSCELERITY = 2.99792458 * 1e5 / 1.5;
80 private static final double PMD_CONSTANT = 0.04;
82 public PceLink(Link link, PceNode source, PceNode dest) {
83 LOG.debug("PceLink: : PceLink start ");
85 this.linkId = link.getLinkId();
87 this.sourceId = link.getSource().getSourceNode();
88 this.destId = link.getDestination().getDestNode();
90 this.sourceTP = link.getSource().getSourceTp();
91 this.destTP = link.getDestination().getDestTp();
93 this.sourceNetworkSupNodeId = source.getSupNetworkNodeId();
94 this.destNetworkSupNodeId = dest.getSupNetworkNodeId();
96 this.sourceCLLI = source.getSupClliNodeId();
97 this.destCLLI = dest.getSupClliNodeId();
99 this.linkType = MapUtils.calcType(link);
101 this.oppositeLink = calcOpposite(link);
103 this.adminStates = link.augmentation(Link1.class).getAdministrativeState();
104 this.state = link.augmentation(Link1.class).getOperationalState();
105 switch (this.linkType) {
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");
121 this.availableBandwidth = MapUtils.getAvailableBandwidth(link);
122 this.usedBandwidth = MapUtils.getUsedBandwidth(link);
123 this.srlgList = MapUtils.getSRLGfromLink(link);
126 this.omsAttributesSpan = null;
128 this.powerCorrection = 0.0;
133 this.omsAttributesSpan = null;
134 this.srlgList = null;
137 this.availableBandwidth = 0L;
138 this.usedBandwidth = 0L;
140 this.powerCorrection = 0.0;
145 LOG.debug("PceLink: created PceLink {}", linkId);
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());
155 return tmpoppositeLink;
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();
164 Double linkLength = calcLength(link);
165 if (linkLength == null) {
166 LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
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);
174 private Double calcLength(Link link) {
175 var augLinkLength = link.augmentation(Link1.class).getLinkLength();
176 if (augLinkLength != null) {
177 return augLinkLength.doubleValue();
179 if (this.omsAttributesSpan == null) {
180 LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
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());
192 linkLength += entry.getValue().getSRLGLength().doubleValue();
193 LOG.debug("In PceLink: The length of the link {} == {}", link.getLinkId(), linkLength / 1000.0);
195 return linkLength / 1000.0;
198 //Calculate CD and PMD of the link from link length
199 private Map<String, Double> calcCDandPMDfromLength() {
200 return this.length == null
204 "CD", 16.5 * this.length,
205 "PMD2", Math.pow(this.length * PMD_CONSTANT, 2)));
208 //Calculate CD and PMD of the link
209 private Map<String, Double> calcCDandPMD(Link link) {
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();
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();
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());
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()),
247 linkPmd2 += Math.pow(entryAug.getPmd().getValue().doubleValue(), 2);
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);
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<>();
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<>(
270 "SpanLoss", linkLength * 0.25,
271 "PoutCorrection", retrievePower(FiberType.Smf)
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);
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);
286 Iterator<LinkConcatenation> linkConcatenationiterator = linkConcatenationList.iterator();
287 if (!linkConcatenationiterator.hasNext()) {
288 return calcDefaultSpanLoss(link);
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()));
297 private double retrievePower(FiberType fiberType) {
315 private double retrievePmdFromFiberType(FiberType fiberType) {
316 return fiberType.toString().equalsIgnoreCase("Dsf")
321 private double retrieveCdFromFiberType(FiberType fiberType) {
340 public LinkId getOppositeLink() {
344 public AdminStates getAdminStates() {
348 public State getState() {
352 public TpId getSourceTP() {
356 public TpId getDestTP() {
360 public OpenroadmLinkType getlinkType() {
364 public LinkId getLinkId() {
368 public NodeId getSourceId() {
372 public NodeId getDestId() {
376 public String getClientA() {
380 public Double getLength() {
384 public void setClientA(String client) {
385 this.clientA = client;
388 public String getClientZ() {
392 public void setClientZ(String client) {
393 this.clientZ = client;
396 // Double for transformer of JUNG graph
397 public Double getLatency() {
398 return latency.doubleValue();
401 public Long getAvailableBandwidth() {
402 return availableBandwidth;
405 public Long getUsedBandwidth() {
406 return usedBandwidth;
409 public String getsourceNetworkSupNodeId() {
410 return sourceNetworkSupNodeId;
413 public String getdestNetworkSupNodeId() {
414 return destNetworkSupNodeId;
417 public List<Long> getsrlgList() {
421 public String getsourceCLLI() {
425 public String getdestCLLI() {
429 public Double getspanLoss() {
433 public Double getcd() {
437 public Double getpmd2() {
441 public Double getpowerCorrection() {
442 return powerCorrection;
445 public boolean isValid() {
446 if (this.linkId == null || this.linkType == null || this.oppositeLink == null) {
448 LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
450 isValid = checkParams();
451 if (this.linkType == OpenroadmLinkType.ROADMTOROADM && (this.length == null || this.length == 0.0)) {
452 if (this.omsAttributesSpan == null) {
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) {
458 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
459 + " Link is ignored {}", linkId);
462 if (this.srlgList != null && this.srlgList.isEmpty()) {
464 LOG.error("PceLink: Empty srlgList for OMS link. Link is ignored {}", linkId);
469 public boolean isOtnValid(Link link, String serviceType) {
471 if (this.linkType != OpenroadmLinkType.OTNLINK) {
472 LOG.error("PceLink: Not an OTN link. Link is ignored {}", linkId);
476 if (this.availableBandwidth == 0L) {
477 LOG.error("PceLink: No bandwidth available for OTN Link, link {} is ignored ", linkId);
482 OtnLinkType neededType = null;
483 switch (serviceType) {
485 if (this.usedBandwidth != 0L) {
489 // Add intermediate rate otn-link-type
490 neededType = OtnLinkType.OTUC2;
493 if (this.usedBandwidth != 0L) {
497 // change otn-link-type
498 neededType = OtnLinkType.OTUC3;
501 if (this.usedBandwidth != 0L) {
505 neededType = OtnLinkType.OTUC4;
509 if (this.usedBandwidth != 0L) {
513 neededType = OtnLinkType.OTU4;
527 // TODO: Here link type needs to be changed, based on the line-rate
528 neededType = OtnLinkType.ODUC4;
532 neededType = OtnLinkType.ODTU4;
536 neededType = OtnLinkType.ODTU4;
539 LOG.error("PceLink: isOtnValid Link {} unsupported serviceType {} ", linkId, serviceType);
542 if (this.availableBandwidth >= neededBW
543 && (neededType == null
544 || neededType.equals(
546 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630
548 .getOtnLinkType()))) {
549 LOG.debug("PceLink: Selected Link {} has available bandwidth and is eligible for {} creation ",
550 linkId, serviceType);
552 return checkParams();
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);
560 if (this.adminStates == null || this.state == null) {
561 LOG.error("PceLink: Link is not available. Link is ignored {}", linkId);
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);
568 if (this.sourceNetworkSupNodeId.equals("") || this.destNetworkSupNodeId.equals("")) {
569 LOG.error("PceLink: No Link source SuppNodeID or destination SuppNodeID is available. Link is ignored {}",
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);
582 public String toString() {
583 return "PceLink type=" + linkType + " ID=" + linkId.getValue() + " latency=" + latency;