2 * Copyright © 2019 Orange, 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.gnpy;
11 import java.math.BigDecimal;
12 import java.math.RoundingMode;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19 import java.util.stream.IntStream;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.transportpce.common.NetworkUtils;
22 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
23 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Coordinate;
24 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Km;
25 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.edfa.params.Operational;
26 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.edfa.params.OperationalBuilder;
27 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.Edfa;
28 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.EdfaBuilder;
29 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.FiberRoadmBuilder;
30 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.Transceiver;
31 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.TransceiverBuilder;
32 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.Params;
33 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.ParamsBuilder;
34 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.Fiber;
35 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.FiberBuilder;
36 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.Roadm;
37 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.RoadmBuilder;
38 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.location.attributes.Location;
39 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.location.attributes.LocationBuilder;
40 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.Connections;
41 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.ConnectionsBuilder;
42 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.Elements;
43 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.ElementsBuilder;
44 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.ElementsKey;
45 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.elements.Metadata;
46 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.topo.elements.MetadataBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.Link1;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.SpanAttributes;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.amplified.link.attributes.AmplifiedLink;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.amplified.link.attributes.amplified.link.section.element.section.element.Span;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev230526.amplified.link.attributes.amplified.link.section.element.section.element.ila.Ila;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev230526.Node1;
53 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev230526.networks.network.link.OMSAttributes;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmLinkType;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.link.concatenation.LinkConcatenation;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNode;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.Decimal64;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 * Class to create the topology corresponding to GNPy requirements.
72 * @author Ahmed Triki ( ahmed.triki@orange.com )
76 public class GnpyTopoImpl {
77 private static final Logger LOG = LoggerFactory.getLogger(GnpyTopoImpl.class);
78 private final NetworkTransactionService networkTransactionService;
80 private Map<ElementsKey, Elements> elements = new HashMap<>();
81 private List<Connections> connections = new ArrayList<>();
82 private List<String> elementsList = new ArrayList<>();
84 //Mapping between the ord-topo and ord-ntw node
85 private Map<String, String> mapDisgNodeRefNode = new HashMap<>();
86 //Mapping between the ROADM-ROADM linkId/secElement and the linkId
87 private Map<String, List<String>> mapLinkFiber = new HashMap<>();
89 private List<String> trxList = new ArrayList<>();
90 private static final double LATITUDE = 0;
91 private static final double LONGITUTE = 0;
92 private static final String REGION = "N/A";
93 private static final String CITY = "N/A";
94 private static final int CONVERT_KM_M = 1000;
95 private static final double TARGET_PCH_OUT_DB = -20;
98 * Construct the ExtractTopoDataStoreImpl.
100 public GnpyTopoImpl(final NetworkTransactionService networkTransactionService) throws GnpyException {
101 this.networkTransactionService = networkTransactionService;
106 * extract the topology
109 private void extractTopo() throws GnpyException {
110 // Define the instance identifier of the OpenRoadm topology
111 InstanceIdentifier<Network> insIdOpenRoadmTopo = InstanceIdentifier
112 .builder(Networks.class)
113 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
114 // Define the instance identifier of the OpenRoadm network
115 InstanceIdentifier<Network> insIdrOpenRoadmNet = InstanceIdentifier
116 .builder(Networks.class)
117 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))).build();
119 // Initialize the reading of the networkTransactionService
120 // read the configuration part of the data broker that concerns the openRoadm topology and get all the nodes
121 java.util.Optional<Network> openRoadmTopo = this.networkTransactionService
122 .read(LogicalDatastoreType.CONFIGURATION, insIdOpenRoadmTopo).get();
123 java.util.Optional<Network> openRoadmNet = this.networkTransactionService
124 .read(LogicalDatastoreType.CONFIGURATION, insIdrOpenRoadmNet).get();
125 if (openRoadmNet.isPresent() && openRoadmTopo.isPresent()) {
126 extractElements(openRoadmTopo,openRoadmNet);
127 extractConnections(openRoadmTopo);
128 LOG.debug("In GnpyTopoImpl : elements and connections are well extracted");
131 throw new GnpyException(
132 "In GnpyTopoImpl : openroadm topology network or openroadm network are not well mounted ...");
134 } catch (InterruptedException | ExecutionException e) {
135 throw new GnpyException("In gnpyTopoImpl: error in reading the topology", e);
139 private void extractElements(java.util.Optional<Network> openRoadmTopo,
140 java.util.Optional<Network> openRoadmNet) throws GnpyException {
141 if ((!openRoadmNet.isPresent()) || (!openRoadmTopo.isPresent())) {
142 throw new GnpyException("In gnpyTopoImpl: openRoadmNet or openRoadmTopo is not present");
144 // Create the list of nodes
145 Collection<Node> openRoadmNetNodeList = openRoadmNet.orElseThrow().nonnullNode().values();
146 Collection<Node> openRoadmTopoNodeList = openRoadmTopo.orElseThrow().nonnullNode().values();
148 if (openRoadmTopoNodeList.isEmpty() || openRoadmNetNodeList.isEmpty()) {
149 throw new GnpyException("In gnpyTopoImpl: no nodes in the openradm topology or openroadm network");
152 for (Node openRoadmTopoNode : openRoadmTopoNodeList) {
153 // Retrieve the supporting node and the type of the node in openRoadm network
154 Collection<SupportingNode> supportingNodeList = openRoadmTopoNode.nonnullSupportingNode().values();
156 for (SupportingNode supportingNode : supportingNodeList) {
157 if (!supportingNode.getNetworkRef().getValue().equals("openroadm-network")) {
160 String nodeRef = supportingNode.getNodeRef().getValue();
161 if (nodeRef == null) {
162 throw new GnpyException("In gnpyTopoImpl: nodeRef is null");
164 // Retrieve the mapping between the openRoadm topology and openRoadm network
165 mapDisgNodeRefNode.put(openRoadmTopoNode.getNodeId().getValue(), nodeRef);
166 Node1 openRoadmNetNode1 = null;
167 org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526
168 .Node1 commonNetworkNode1 = null;
169 for (Node openRoadmNetNode : openRoadmNetNodeList) {
170 if (openRoadmNetNode.getNodeId().getValue().equals(nodeRef)) {
171 openRoadmNetNode1 = openRoadmNetNode.augmentation(Node1.class);
172 commonNetworkNode1 = openRoadmNetNode.augmentation(org.opendaylight.yang.gen.v1
173 .http.org.openroadm.common.network.rev230526.Node1.class);
177 if (commonNetworkNode1 == null) {
178 throw new GnpyException(String.format("In gnpyTopoImpl: the node type of %s is null",nodeRef));
180 if (commonNetworkNode1.getNodeType().getName().equals("ROADM")) {
181 if (!elementsList.contains(nodeRef)) {
182 Elements element = createElementsRoadm(LATITUDE, LONGITUTE, nodeRef,
183 openRoadmNetNode1.getShelf(),TARGET_PCH_OUT_DB, nodeRef);
184 this.elements.put(element.key(),element);
185 elementsList.add(nodeRef);
187 } else if (commonNetworkNode1.getNodeType().getName().equals("XPONDER")) {
188 if (!elementsList.contains(nodeRef)) {
189 Elements element = createElementsTransceiver(LATITUDE, LONGITUTE, nodeRef,
190 openRoadmNetNode1.getShelf(), nodeRef);
191 this.elements.put(element.key(),element);
192 elementsList.add(nodeRef);
193 trxList.add(nodeRef);
196 throw new GnpyException("In gnpyTopoImpl: the type is not implemented");
202 private void extractConnections(java.util.Optional<Network> openRoadmTopo) throws GnpyException {
203 // Create the list of connections
204 if (!openRoadmTopo.isPresent()) {
205 throw new GnpyException("In gnpyTopoImpl: openroadmTopo is not present");
207 Network1 nw1 = openRoadmTopo.orElseThrow().augmentation(Network1.class);
208 Collection<Link> linksList = nw1.nonnullLink().values();
209 // 1:EXPRESS-LINK 2:ADD-LINK 3:DROP-LINK
210 // 4:ROADM-To-ROADM 5:XPONDER-INPUT 6:XPONDER-OUTPUT
211 int[] externalLink = {OpenroadmLinkType.ROADMTOROADM.getIntValue(),OpenroadmLinkType.XPONDERINPUT.getIntValue(),
212 OpenroadmLinkType.XPONDEROUTPUT.getIntValue()};
214 if (linksList.isEmpty()) {
215 throw new GnpyException("In gnpyTopoImpl: no links in the network");
218 for (Link link : linksList) {
219 Link1 link1 = link.augmentation(Link1.class);
220 org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev230526
221 .Link1 openroadmNetworkLink1 = link.augmentation(org.opendaylight.yang.gen.v1.http
222 .org.openroadm.network.topology.rev230526.Link1.class);
223 if (link1.getLinkType() == null) {
224 throw new GnpyException("In gnpyTopoImpl: the link type is null");
226 int linkType = link1.getLinkType().getIntValue();
227 if (! IntStream.of(externalLink).anyMatch(x -> x == linkType)) {
231 String srcId = mapDisgNodeRefNode.get(link.getSource().getSourceNode().getValue());
232 String linkId = link.getLinkId().getValue();
233 String destId = null;
234 if (linkType == OpenroadmLinkType.ROADMTOROADM.getIntValue()) {
235 OMSAttributes omsAttributes = openroadmNetworkLink1.getOMSAttributes();
236 if (omsAttributes == null) {
237 throw new GnpyException(String.format(
238 "In gnpyTopoImpl: OMS attributes do not exit for ROADM to ROADM link: %s",linkId));
240 //Case of amplified link
241 if (omsAttributes.getAmplifiedLink() != null) {
242 srcId = extractAmplifiedLink(omsAttributes, linkId, srcId);
244 //Case of one span link
245 if (omsAttributes.getSpan() != null) {
246 srcId = extractSpanLink(omsAttributes, linkId, srcId);
250 destId = mapDisgNodeRefNode.get(link.getDestination().getDestNode().getValue());
251 createNewConnection(srcId,destId);
255 private String extractAmplifiedLink(OMSAttributes omsAttributes, String linkId, String srcId)
256 throws GnpyException {
258 List<AmplifiedLink> amplifiedLinkList = new ArrayList<>(omsAttributes.getAmplifiedLink()
259 .nonnullAmplifiedLink().values());
260 String destId = null;
261 if (!amplifiedLinkList.isEmpty()) {
262 for (AmplifiedLink amplifiedLink: amplifiedLinkList) {
263 String secElt = amplifiedLink .getSectionEltNumber().toString();
265 if (amplifiedLink.getSectionElement().getSectionElement() instanceof Ila) {
266 Ila ila = (Ila) amplifiedLink.getSectionElement().getSectionElement();
267 destId = extractILAFromAmpLink(ila);
270 if (amplifiedLink.getSectionElement().getSectionElement() instanceof Span) {
271 Span span = (Span) amplifiedLink.getSectionElement().getSectionElement();
272 destId = extractSpan(span.getSpan(), linkId, secElt);
275 if (createNewConnection(srcId,destId)) {
283 private String extractSpanLink(OMSAttributes omsAttributes, String linkId, String srcId)
284 throws GnpyException {
286 SpanAttributes span = omsAttributes.getSpan();
287 String destId = extractSpan(span, linkId, linkId);
288 if (createNewConnection(srcId, destId)) {
294 private String extractILAFromAmpLink(Ila ila) throws GnpyException {
295 String nodeId = ila.getNodeId().getValue();
296 mapDisgNodeRefNode.put(nodeId, nodeId);
297 Elements element = createElementsEdfa(LATITUDE, LONGITUTE, REGION, CITY,
298 ila.getGain().getValue().decimalValue(), ila.getTilt().getValue().decimalValue(),
299 ila.getOutVoaAtt().getValue().decimalValue(), "std_medium_gain",
301 this.elements.put(element.key(),element);
305 private String extractSpan(SpanAttributes span, String linkId, String subLinkId) throws GnpyException {
306 if (!mapLinkFiber.containsKey(linkId)) {
307 mapLinkFiber.put(linkId, new ArrayList<>());
309 mapLinkFiber.get(linkId).add(subLinkId);
310 //mapFiberIp.put(subLinkId, ipFiber);
311 //fiberId = incrementIdentifier(fiberId);
315 String typeVariety = "SSMF";
317 // Compute the length of the link
318 for (LinkConcatenation linkConcatenation : span.nonnullLinkConcatenation().values()) {
319 double srlgLength = linkConcatenation.getSRLGLength().doubleValue();
320 //convert to kilometer
321 length += srlgLength / CONVERT_KM_M;
324 throw new GnpyException(String.format(
325 "In gnpyTopoImpl: length of the link %s is equal to zero",linkId));
327 double lossCoef = span.getSpanlossCurrent().getValue().doubleValue() / length;
328 Elements element = createElementsFiber(LATITUDE, LONGITUTE, REGION, CITY,
329 subLinkId, length, attIn, lossCoef, connIn, connOut, typeVariety);
330 this.elements.put(element.key(),element);
335 * Method to create Fiber
337 private Elements createElementsFiber(double latitude, double longitude, String region, String city, String uidFiber,
338 double length, double attIn, double lossCoef, double connIn, double connOut, String typeVariety) {
339 // Create an amplifier after the ROADM
340 Coordinate c1 = new Coordinate(Decimal64.valueOf(String.valueOf(latitude)));
341 Coordinate c2 = new Coordinate(Decimal64.valueOf(String.valueOf(longitude)));
342 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
344 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
345 Fiber fiber = new FiberBuilder()
346 .setLength(Decimal64.valueOf(String.valueOf(length)))
347 .setLengthUnits(Km.VALUE)
348 .setAttIn(Decimal64.valueOf(String.valueOf(attIn)))
349 .setLossCoef(Decimal64.valueOf(String.valueOf(lossCoef)).scaleTo(5, RoundingMode.CEILING))
350 .setConIn(Decimal64.valueOf(String.valueOf(connIn)))
351 .setConOut(Decimal64.valueOf(String.valueOf(connOut)))
353 Params params1 = new ParamsBuilder().setFiberroadmfused(fiber).build();
354 return new ElementsBuilder().setUid(uidFiber)
355 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Fiber.VALUE)
356 .setTypeVariety(typeVariety).setMetadata(metadata1)
357 .setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
361 * Method to create EDFA
363 private Elements createElementsEdfa(double latitude, double longitude, String region, String city,
364 BigDecimal gainTarget, BigDecimal tiltTarget, BigDecimal outVoa, String typeVariety, String uidEdfa) {
365 // Create an amplifier after the ROADM
366 Coordinate c1 = new Coordinate(Decimal64.valueOf(String.valueOf(latitude)));
367 Coordinate c2 = new Coordinate(Decimal64.valueOf(String.valueOf(longitude)));
368 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
370 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
371 Operational operational = new OperationalBuilder()
372 .setGainTarget(Decimal64.valueOf(gainTarget))
373 .setTiltTarget(Decimal64.valueOf(tiltTarget))
374 .setOutVoa(Decimal64.valueOf(outVoa))
376 Edfa edfa = new EdfaBuilder()
377 .setOperational(operational).build();
378 return new ElementsBuilder().setUid(uidEdfa)
379 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Edfa.VALUE)
380 .setMetadata(metadata1).setElementType(edfa).setTypeVariety(typeVariety).build();
384 * Method to create ROADM
386 private Elements createElementsRoadm(double latitude, double longitude, String region, String city,
387 double targetPchOutDb, String uidRoadm) {
388 Coordinate c1 = new Coordinate(Decimal64.valueOf(String.valueOf(latitude)));
389 Coordinate c2 = new Coordinate(Decimal64.valueOf(String.valueOf(longitude)));
390 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
392 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
393 Roadm roadm = new RoadmBuilder()
394 .setTargetPchOutDb(Decimal64.valueOf(String.valueOf(targetPchOutDb)))
396 Params params1 = new ParamsBuilder().setFiberroadmfused(roadm).build();
397 return new ElementsBuilder().setUid(uidRoadm)
398 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Roadm.VALUE)
399 .setMetadata(metadata1).setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
403 * Method to create Transceiver
405 private Elements createElementsTransceiver(double latitude, double longitude, String region, String city,
407 Coordinate c1 = new Coordinate(Decimal64.valueOf(String.valueOf(latitude)));
408 Coordinate c2 = new Coordinate(Decimal64.valueOf(String.valueOf(longitude)));
409 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
411 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
412 Transceiver transceiver = new TransceiverBuilder().build();
413 return new ElementsBuilder().setUid(uidTrans)
414 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220615.Transceiver.VALUE)
415 .setMetadata(metadata1).setElementType(transceiver).build();
419 * Method to create Connection
421 private boolean createNewConnection(String fromNode, String toNode) throws GnpyException {
422 if (fromNode == null || toNode == null) {
423 throw new GnpyException("create new connection : null node IpAddress");
425 if (fromNode.equals(toNode)) {
428 Connections connection = new ConnectionsBuilder().setFromNode(fromNode).setToNode(toNode).build();
429 this.connections.add(connection);
433 public Map<ElementsKey, Elements> getElements() {
437 public void setElements(Map<ElementsKey, Elements> elements) {
438 this.elements = elements;
441 public List<Connections> getConnections() {
445 public void setConnections(List<Connections> connections) {
446 this.connections = connections;
449 public List<String> getElementsList() {
453 public void setElementsList(List<String> elementsList) {
454 this.elementsList = elementsList;
457 public Map<String, String> getMapDisgNodeRefNode() {
458 return mapDisgNodeRefNode;
461 public void setMapDisgNodeRefNode(Map<String, String> mapDisgNodeRefNode) {
462 this.mapDisgNodeRefNode = mapDisgNodeRefNode;
465 public Map<String, List<String>> getMapLinkFiber() {
469 public void setMapLinkFiber(Map<String, List<String>> mapLinkFiber) {
470 this.mapLinkFiber = mapLinkFiber;
473 public List<String> getTrxList() {
477 public void setTrxList(List<String> trxList) {
478 this.trxList = trxList;