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 java.io.Serializable;
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
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;
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 {
41 private static final Logger LOG = LoggerFactory.getLogger(PceLink.class);
42 ///////////////////////// LINKS ////////////////////
44 * extension of Link to include constraints and Graph weight
47 private boolean isValid = true;
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;
77 private static final double GLASSCELERITY = 2.99792458 * 1e5 / 1.5;
78 private static final double PMD_CONSTANT = 0.04;
80 public PceLink(Link link, PceNode source, PceNode dest) {
81 LOG.debug("PceLink: : PceLink start ");
83 this.linkId = link.getLinkId();
85 this.sourceId = link.getSource().getSourceNode();
86 this.destId = link.getDestination().getDestNode();
88 this.sourceTP = link.getSource().getSourceTp();
89 this.destTP = link.getDestination().getDestTp();
91 this.sourceNetworkSupNodeId = source.getSupNetworkNodeId();
92 this.destNetworkSupNodeId = dest.getSupNetworkNodeId();
94 this.sourceCLLI = source.getSupClliNodeId();
95 this.destCLLI = dest.getSupClliNodeId();
97 this.linkType = MapUtils.calcType(link);
99 this.oppositeLink = calcOpposite(link);
101 this.adminStates = link.augmentation(Link1.class).getAdministrativeState();
102 this.state = link.augmentation(Link1.class).getOperationalState();
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);
123 this.omsAttributesSpan = null;
125 this.powerCorrection = 0.0;
129 this.omsAttributesSpan = null;
130 this.srlgList = null;
133 this.availableBandwidth = 0L;
134 this.usedBandwidth = 0L;
136 this.powerCorrection = 0.0;
140 LOG.debug("PceLink: created PceLink {}", linkId);
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());
150 return tmpoppositeLink;
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();
159 Double linkLength = calcLength(link);
160 if (linkLength == null) {
161 LOG.debug("In PceLink: cannot compute the latency for the link {}", link.getLinkId().getValue());
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);
169 private Double calcLength(Link link) {
170 Link1 link1 = link.augmentation(Link1.class);
171 if (link1.getLinkLength() != null) {
172 return link1.getLinkLength().doubleValue();
174 if (this.omsAttributesSpan == null) {
175 LOG.debug("In PceLink: cannot compute the length for the link {}", link.getLinkId().getValue());
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());
187 linkLength += entry.getValue().getSRLGLength().doubleValue();
188 LOG.debug("In PceLink: The length of the link {} == {}", link.getLinkId(), linkLength / 1000.0);
190 return (linkLength / 1000.0);
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));
203 //Calculate CD and PMD of the link
204 private Map<String, Double> calcCDandPMD(Link link) {
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();
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();
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());
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)
242 .pow(entry.getValue().augmentation(LinkConcatenation1.class).getPmd().getValue().doubleValue(), 2);
245 LOG.debug("In PceLink: The CD and PMD2 of link {} are respectively {} ps and {} ps", link.getLinkId(), linkCd,
247 return Map.of("CD", linkCd,"PMD2", linkPmd2);
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;
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;
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);
274 Collection<LinkConcatenation> linkConcatenationList = this.omsAttributesSpan.nonnullLinkConcatenation()
276 if (linkConcatenationList == null) {
277 LOG.error("in PceLink : Null field in the OmsAttrubtesSpan");
278 return calcDefaultSpanLoss(link);
280 Iterator<LinkConcatenation> linkConcatenationiterator = linkConcatenationList.iterator();
281 if (!linkConcatenationiterator.hasNext()) {
282 return calcDefaultSpanLoss(link);
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;
294 private double retrievePower(FiberType fiberType) {
318 private double retrievePmdFromFiberType(FiberType fiberType) {
319 if (fiberType.toString().equalsIgnoreCase("Dsf")) {
326 private double retrieveCdFromFiberType(FiberType fiberType) {
360 public LinkId getOppositeLink() {
364 public AdminStates getAdminStates() {
368 public State getState() {
372 public TpId getSourceTP() {
376 public TpId getDestTP() {
380 public OpenroadmLinkType getlinkType() {
384 public LinkId getLinkId() {
388 public NodeId getSourceId() {
392 public NodeId getDestId() {
396 public String getClient() {
400 public Double getLength() {
404 public void setClient(String client) {
405 this.client = client;
408 // Double for transformer of JUNG graph
409 public Double getLatency() {
410 return latency.doubleValue();
413 public Long getAvailableBandwidth() {
414 return availableBandwidth;
417 public Long getUsedBandwidth() {
418 return usedBandwidth;
421 public String getsourceNetworkSupNodeId() {
422 return sourceNetworkSupNodeId;
425 public String getdestNetworkSupNodeId() {
426 return destNetworkSupNodeId;
429 public List<Long> getsrlgList() {
433 public String getsourceCLLI() {
437 public String getdestCLLI() {
441 public Double getspanLoss() {
445 public Double getcd() {
449 public Double getpmd2() {
453 public Double getpowerCorrection() {
454 return powerCorrection;
457 public boolean isValid() {
458 if ((this.linkId == null) || (this.linkType == null) || (this.oppositeLink == null)) {
460 LOG.error("PceLink: No Link type or opposite link is available. Link is ignored {}", linkId);
462 isValid = checkParams();
463 if (this.linkType == OpenroadmLinkType.ROADMTOROADM) {
464 if ((this.length == null || this.length == 0.0)
465 && this.omsAttributesSpan == null) {
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) {
472 LOG.error("PceLink: Error reading Span for OMS link, and no available generic link information."
473 + " Link is ignored {}", linkId);
476 if (this.srlgList != null && this.srlgList.isEmpty()) {
478 LOG.error("PceLink: Empty srlgList for OMS link. Link is ignored {}", linkId);
483 public boolean isOtnValid(Link link, String serviceType) {
485 if (this.linkType != OpenroadmLinkType.OTNLINK) {
486 LOG.error("PceLink: Not an OTN link. Link is ignored {}", linkId);
490 OtnLinkType otnLinkType = link
491 .augmentation(org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils
492 .rev220630.Link1.class)
494 if (this.availableBandwidth == 0L) {
495 LOG.error("PceLink: No bandwidth available for OTN Link, link {} is ignored ", linkId);
500 OtnLinkType neededType = null;
501 switch (serviceType) {
503 if (this.usedBandwidth != 0L) {
507 // Add intermediate rate otn-link-type
508 neededType = OtnLinkType.OTUC2;
511 if (this.usedBandwidth != 0L) {
515 // change otn-link-type
516 neededType = OtnLinkType.OTUC3;
519 if (this.usedBandwidth != 0L) {
523 neededType = OtnLinkType.OTUC4;
527 if (this.usedBandwidth != 0L) {
531 neededType = OtnLinkType.OTU4;
545 // TODO: Here link type needs to be changed, based on the line-rate
546 neededType = OtnLinkType.ODUC4;
550 neededType = OtnLinkType.ODTU4;
554 neededType = OtnLinkType.ODTU4;
557 LOG.error("PceLink: isOtnValid Link {} unsupported serviceType {} ", linkId, serviceType);
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);
567 return checkParams();
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);
575 if ((this.adminStates == null) || (this.state == null)) {
576 LOG.error("PceLink: Link is not available. Link is ignored {}", linkId);
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);
583 if ((this.sourceNetworkSupNodeId.equals("")) || (this.destNetworkSupNodeId.equals(""))) {
584 LOG.error("PceLink: No Link source SuppNodeID or destination SuppNodeID is available. Link is ignored {}",
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);
597 public String toString() {
598 return "PceLink type=" + linkType + " ID=" + linkId.getValue() + " latency=" + latency;