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.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.stream.IntStream;
19 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
20 import org.opendaylight.transportpce.common.NetworkUtils;
21 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
22 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Coordinate;
23 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Km;
24 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.edfa.params.Operational;
25 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.edfa.params.OperationalBuilder;
26 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.Edfa;
27 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.EdfaBuilder;
28 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.FiberRoadmBuilder;
29 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.Transceiver;
30 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.TransceiverBuilder;
31 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.Params;
32 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.ParamsBuilder;
33 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.Fiber;
34 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.FiberBuilder;
35 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.Roadm;
36 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.element.type.choice.element.type.fiberroadm.params.fiberroadmfused.RoadmBuilder;
37 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.location.attributes.Location;
38 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.location.attributes.LocationBuilder;
39 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.Connections;
40 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.ConnectionsBuilder;
41 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.Elements;
42 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.ElementsBuilder;
43 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.ElementsKey;
44 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.elements.Metadata;
45 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.topo.elements.MetadataBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev211210.Link1;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.SpanAttributes;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.amplified.link.attributes.AmplifiedLink;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.amplified.link.attributes.amplified.link.section.element.section.element.Span;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev211210.amplified.link.attributes.amplified.link.section.element.section.element.ila.Ila;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev211210.Node1;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev211210.networks.network.link.OMSAttributes;
53 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.OpenroadmLinkType;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev211210.link.concatenation.LinkConcatenation;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNode;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
68 * Class to create the topology corresponding to GNPy requirements.
70 * @author Ahmed Triki ( ahmed.triki@orange.com )
74 public class GnpyTopoImpl {
75 private static final Logger LOG = LoggerFactory.getLogger(GnpyTopoImpl.class);
76 private final NetworkTransactionService networkTransactionService;
78 private Map<ElementsKey, Elements> elements = new HashMap<>();
79 private List<Connections> connections = new ArrayList<>();
80 private List<String> elementsList = new ArrayList<>();
82 //Mapping between the ord-topo and ord-ntw node
83 private Map<String, String> mapDisgNodeRefNode = new HashMap<>();
84 //Mapping between the ROADM-ROADM linkId/secElement and the linkId
85 private Map<String, List<String>> mapLinkFiber = new HashMap<>();
87 private List<String> trxList = new ArrayList<>();
88 private static final double LATITUDE = 0;
89 private static final double LONGITUTE = 0;
90 private static final String REGION = "N/A";
91 private static final String CITY = "N/A";
92 private static final int CONVERT_KM_M = 1000;
93 private static final double TARGET_PCH_OUT_DB = -20;
96 * Construct the ExtractTopoDataStoreImpl.
98 public GnpyTopoImpl(final NetworkTransactionService networkTransactionService) throws GnpyException {
99 this.networkTransactionService = networkTransactionService;
104 * extract the topology
107 private void extractTopo() throws GnpyException {
108 // Define the instance identifier of the OpenRoadm topology
109 InstanceIdentifier<Network> insIdOpenRoadmTopo = InstanceIdentifier
110 .builder(Networks.class)
111 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
112 // Define the instance identifier of the OpenRoadm network
113 InstanceIdentifier<Network> insIdrOpenRoadmNet = InstanceIdentifier
114 .builder(Networks.class)
115 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))).build();
117 // Initialize the reading of the networkTransactionService
118 // read the configuration part of the data broker that concerns the openRoadm topology and get all the nodes
119 java.util.Optional<Network> openRoadmTopo = this.networkTransactionService
120 .read(LogicalDatastoreType.CONFIGURATION, insIdOpenRoadmTopo).get();
121 java.util.Optional<Network> openRoadmNet = this.networkTransactionService
122 .read(LogicalDatastoreType.CONFIGURATION, insIdrOpenRoadmNet).get();
123 if (openRoadmNet.isPresent() && openRoadmTopo.isPresent()) {
124 extractElements(openRoadmTopo,openRoadmNet);
125 extractConnections(openRoadmTopo);
126 LOG.debug("In GnpyTopoImpl : elements and connections are well extracted");
129 throw new GnpyException(
130 "In GnpyTopoImpl : openroadm topology network or openroadm network are not well mounted ...");
132 } catch (InterruptedException | ExecutionException e) {
133 this.networkTransactionService.close();
134 throw new GnpyException("In gnpyTopoImpl: error in reading the topology", e);
136 this.networkTransactionService.close();
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.get().nonnullNode().values();
146 Collection<Node> openRoadmTopoNodeList = openRoadmTopo.get().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.rev211210
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.rev211210.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.get().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.rev211210
221 .Link1 openroadmNetworkLink1 = link.augmentation(org.opendaylight.yang.gen.v1.http
222 .org.openroadm.network.topology.rev211210.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(), ila.getTilt().getValue(),
299 ila.getOutVoaAtt().getValue(), "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(BigDecimal.valueOf(latitude));
341 Coordinate c2 = new Coordinate(BigDecimal.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().setLength(BigDecimal.valueOf(length)).setLengthUnits(Km.class)
346 .setAttIn(BigDecimal.valueOf(attIn)).setLossCoef(BigDecimal.valueOf(lossCoef))
347 .setConIn(BigDecimal.valueOf(connIn))
348 .setConOut(BigDecimal.valueOf(connOut)).build();
349 Params params1 = new ParamsBuilder().setFiberroadmfused(fiber).build();
350 return new ElementsBuilder().setUid(uidFiber)
351 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Fiber.class)
352 .setTypeVariety(typeVariety).setMetadata(metadata1)
353 .setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
357 * Method to create EDFA
359 private Elements createElementsEdfa(double latitude, double longitude, String region, String city,
360 BigDecimal gainTarget, BigDecimal tiltTarget, BigDecimal outVoa, String typeVariety, String uidEdfa) {
361 // Create an amplifier after the ROADM
362 Coordinate c1 = new Coordinate(BigDecimal.valueOf(latitude));
363 Coordinate c2 = new Coordinate(BigDecimal.valueOf(longitude));
364 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
366 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
367 Operational operational = new OperationalBuilder().setGainTarget(gainTarget).setTiltTarget(tiltTarget)
368 .setOutVoa(outVoa).build();
369 Edfa edfa = new EdfaBuilder()
370 .setOperational(operational).build();
371 return new ElementsBuilder().setUid(uidEdfa)
372 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Edfa.class)
373 .setMetadata(metadata1).setElementType(edfa).setTypeVariety(typeVariety).build();
377 * Method to create ROADM
379 private Elements createElementsRoadm(double latitude, double longitude, String region, String city,
380 double targetPchOutDb, String uidRoadm) {
381 Coordinate c1 = new Coordinate(BigDecimal.valueOf(latitude));
382 Coordinate c2 = new Coordinate(BigDecimal.valueOf(longitude));
383 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
385 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
386 Roadm roadm = new RoadmBuilder().setTargetPchOutDb(BigDecimal.valueOf(targetPchOutDb)).build();
387 Params params1 = new ParamsBuilder().setFiberroadmfused(roadm).build();
388 return new ElementsBuilder().setUid(uidRoadm)
389 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Roadm.class)
390 .setMetadata(metadata1).setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
394 * Method to create Transceiver
396 private Elements createElementsTransceiver(double latitude, double longitude, String region, String city,
398 Coordinate c1 = new Coordinate(BigDecimal.valueOf(latitude));
399 Coordinate c2 = new Coordinate(BigDecimal.valueOf(longitude));
400 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
402 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
403 Transceiver transceiver = new TransceiverBuilder().build();
404 return new ElementsBuilder().setUid(uidTrans)
405 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev220221.Transceiver.class)
406 .setMetadata(metadata1).setElementType(transceiver).build();
410 * Method to create Connection
412 private boolean createNewConnection(String fromNode, String toNode) throws GnpyException {
413 if (fromNode == null || toNode == null) {
414 throw new GnpyException("create new connection : null node IpAddress");
416 if (fromNode.equals(toNode)) {
419 Connections connection = new ConnectionsBuilder().setFromNode(fromNode).setToNode(toNode).build();
420 this.connections.add(connection);
424 public Map<ElementsKey, Elements> getElements() {
428 public void setElements(Map<ElementsKey, Elements> elements) {
429 this.elements = elements;
432 public List<Connections> getConnections() {
436 public void setConnections(List<Connections> connections) {
437 this.connections = connections;
440 public List<String> getElementsList() {
444 public void setElementsList(List<String> elementsList) {
445 this.elementsList = elementsList;
448 public Map<String, String> getMapDisgNodeRefNode() {
449 return mapDisgNodeRefNode;
452 public void setMapDisgNodeRefNode(Map<String, String> mapDisgNodeRefNode) {
453 this.mapDisgNodeRefNode = mapDisgNodeRefNode;
456 public Map<String, List<String>> getMapLinkFiber() {
460 public void setMapLinkFiber(Map<String, List<String>> mapLinkFiber) {
461 this.mapLinkFiber = mapLinkFiber;
464 public List<String> getTrxList() {
468 public void setTrxList(List<String> trxList) {
469 this.trxList = trxList;