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.HashMap;
14 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import java.util.stream.IntStream;
19 import org.eclipse.jdt.annotation.Nullable;
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.rev181214.Coordinate;
24 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Km;
25 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.edfa.params.Operational;
26 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.edfa.params.OperationalBuilder;
27 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.Edfa;
28 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.EdfaBuilder;
29 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.FiberRoadmBuilder;
30 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.Transceiver;
31 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.TransceiverBuilder;
32 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.Params;
33 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.ParamsBuilder;
34 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.Fiber;
35 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.FiberBuilder;
36 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.Roadm;
37 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.RoadmBuilder;
38 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.location.attributes.Location;
39 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.location.attributes.LocationBuilder;
40 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Connections;
41 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.ConnectionsBuilder;
42 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Elements;
43 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.ElementsBuilder;
44 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.elements.Metadata;
45 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.elements.MetadataBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Link1;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.AmplifiedLink;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.amplified.link.section.element.section.element.Span;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.amplified.link.section.element.section.element.ila.Ila;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.span.attributes.LinkConcatenation;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev181130.Node1;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.networks.network.link.OMSAttributes;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
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;
77 private List<Elements> elements = new ArrayList<>();
78 private List<Connections> connections = new ArrayList<>();
80 //Mapping between the ord-topo and ord-ntw node
81 private Map<String, String> mapDisgNodeRefNode = new HashMap<String, String>();
82 //Mapping between the ord-ntw and node ip
83 private Map<String, IpAddress> mapNodeRefIp = new HashMap<String, IpAddress>();
84 //Mapping between link id and clfi
85 private Map<String, String> mapLinkFiber = new HashMap<String, String>();
86 //Mapping between fiber clfi and ipAddress
87 private Map<String, IpAddress> mapFiberIp = new HashMap<String, IpAddress>();
88 private static int convertKmM = 1000;
91 * Construct the ExtractTopoDataStoreImpl.
93 @SuppressWarnings("unchecked")
94 public GnpyTopoImpl(final NetworkTransactionService networkTransactionService) {
95 this.networkTransactionService = networkTransactionService;
96 Map<String, List<?>> map = extractTopo();
97 if (map.containsKey("Elements")) {
98 elements = (List<Elements>) map.get("Elements");
102 if (map.containsKey("Connections")) {
103 connections = (List<Connections>) map.get("Connections");
110 * extract the topology: all the elements have ipAddress as uid and maintain
111 * a mapping structure to map between the nodeId and the ipAddress (uid)
114 public Map<String, List<?>> extractTopo() {
115 Map<String, List<?>> map = new HashMap<String, List<?>>();
116 // Define the elements
117 List<Elements> topoElements = new ArrayList<>();
118 // Define the connections
119 List<Connections> topoConnections = new ArrayList<>();
120 // Define the instance identifier of the OpenRoadm topology
121 InstanceIdentifier<Network> insIdOpenRoadmTopo = InstanceIdentifier
122 .builder(Networks.class)
123 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
124 // Define the instance identifier of the OpenRoadm network
125 InstanceIdentifier<Network> insIdrOpenRoadmNet = InstanceIdentifier
126 .builder(Networks.class)
127 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))).build();
129 // Initialize the reading of the networkTransactionService
130 // read the configuration part of the data broker that concerns
131 // the openRoadm topology and get all the nodes
132 java.util.Optional<Network> openRoadmTopo = this.networkTransactionService
133 .read(LogicalDatastoreType.CONFIGURATION, insIdOpenRoadmTopo).get();
134 java.util.Optional<Network> openRoadmNet = this.networkTransactionService
135 .read(LogicalDatastoreType.CONFIGURATION, insIdrOpenRoadmNet).get();
136 if (openRoadmNet.isPresent()) {
137 List<Node> openRoadmNetNodeList = openRoadmNet.get().getNode();
138 if (openRoadmTopo.isPresent()) {
139 List<Node> openRoadmTopoNodeList = openRoadmTopo.get().getNode();
140 List<String> nodesList = new ArrayList<>();
141 // Create the list of nodes
142 if (!openRoadmTopoNodeList.isEmpty()) {
144 for (Node openRoadmTopoNode : openRoadmTopoNodeList) {
145 // Retrieve the supporting node and the type of the
146 // node in openRoadm network
147 List<SupportingNode> supportingNodeList = openRoadmTopoNode.getSupportingNode();
148 for (SupportingNode supportingNode : supportingNodeList) {
149 String nodeRef = supportingNode.getNodeRef().getValue();
150 IpAddress ipAddress = null;
151 // Retrieve the mapping between the openRoadm
152 // topology and openRoadm network
153 mapDisgNodeRefNode.put(openRoadmTopoNode.getNodeId().getValue(), nodeRef);
154 Node1 openRoadmNetNode1 = null;
155 org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130
156 .Node1 commonNetworkNode1 = null;
157 for (Node openRoadmNetNode : openRoadmNetNodeList) {
158 if (openRoadmNetNode.getNodeId().getValue().equals(nodeRef)) {
159 openRoadmNetNode1 = openRoadmNetNode.augmentation(Node1.class);
160 commonNetworkNode1 = openRoadmNetNode.augmentation(org.opendaylight.yang.gen.v1
161 .http.org.openroadm.common.network.rev181130.Node1.class);
162 ipAddress = openRoadmNetNode1.getIp();
163 mapNodeRefIp.put(nodeRef, ipAddress);
167 if (commonNetworkNode1.getNodeType().getName().equals("ROADM")) {
168 //if (((org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Node1)
169 // openRoadmNetNode1).getNodeType().getName().equals("ROADM")) {
170 if (!nodesList.contains(nodeRef)) {
171 Elements element = addElementsRoadm(2, 0, nodeRef, openRoadmNetNode1.getShelf(),
172 -20, ipAddress.getIpv4Address().getValue().toString());
173 topoElements.add(element);
174 nodesList.add(nodeRef);
176 } else if (commonNetworkNode1.getNodeType().getName().equals("XPONDER")) {
177 //} else if (((org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130
178 // .Node1) openRoadmNetNode1).getNodeType().getName().equals("XPONDER")) {
179 if (!nodesList.contains(nodeRef)) {
180 Elements element = addElementsTransceiver(2, 0, nodeRef,
181 openRoadmNetNode1.getShelf(),
182 ipAddress.getIpv4Address().getValue().toString());
183 topoElements.add(element);
184 nodesList.add(nodeRef);
187 LOG.warn("the type is not implemented");
192 LOG.warn("no nodes in the network");
195 // Create the list of connections
196 Network1 nw1 = openRoadmTopo.get().augmentation(Network1.class);
197 List<Link> linksList = nw1.getLink();
198 // 1:EXPRESS-LINK 2:ADD-LINK 3:DROP-LINK
199 // 4:ROADM-To-ROADM 5:XPONDER-INPUT 6:XPONDER-OUTPUT
200 int[] externalLink = {4,5,6};
203 if (!linksList.isEmpty()) {
204 LOG.debug("The link list is not empty");
205 for (Link link : linksList) {
206 Link1 link1 = link.augmentation(Link1.class);
207 org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130
208 .Link1 openroadmNetworkLink1 = link.augmentation(org.opendaylight.yang.gen.v1.http.org
209 .openroadm.network.topology.rev181130.Link1.class);
210 int linkType = link1.getLinkType().getIntValue();
211 // the previous line generates a warning
212 // but the following cast in comment makes the gnpy tox test fail
213 // ((org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Link1) link1)
214 if (IntStream.of(externalLink).anyMatch(x -> x == linkType)) {
215 // Verify if the node is a ROADM
216 String srcId = mapDisgNodeRefNode.get(link.getSource().getSourceNode().getValue());
217 IpAddress srcIp = mapNodeRefIp.get(srcId);
218 String clfi = link1.getClfi();
219 String destId = null;
220 IpAddress destIp = null;
221 // Add the links between amplifiers
222 OMSAttributes omsAttributes = null;
224 omsAttributes = openroadmNetworkLink1.getOMSAttributes();
226 if (omsAttributes != null) {
227 if (omsAttributes.getAmplifiedLink() != null) {
228 List<AmplifiedLink> amplifiedLinkList = omsAttributes.getAmplifiedLink()
230 if (!amplifiedLinkList.isEmpty()) {
231 for (AmplifiedLink amplifiedLink : amplifiedLinkList) {
232 Elements element1 = null;
233 if (amplifiedLink.getSectionElement()
234 .getSectionElement() instanceof Ila) {
235 Ila ila = (Ila) amplifiedLink.getSectionElement()
236 .getSectionElement();
237 String nodeId = ila.getNodeId().getValue();
238 IpAddress ipEdfa = new IpAddress(
239 new Ipv4Address("1.1.1." + nbEDFA));
241 mapDisgNodeRefNode.put(nodeId, nodeId);
242 mapNodeRefIp.put(nodeId, ipEdfa);
243 element1 = addElementsEdfa(2, 0, "RLD", "Lannion_CAS",
244 ila.getGain().getValue(), ila.getTilt().getValue(),
245 ila.getOutVoaAtt().getValue(), "std_medium_gain",
246 ipEdfa.getIpv4Address().getValue().toString());
247 } else if (amplifiedLink.getSectionElement()
248 .getSectionElement() instanceof Span) {
249 // Create the location
250 IpAddress ipFiber = new IpAddress(
251 new Ipv4Address("2.2.2." + idFiber));
252 mapLinkFiber.put(link.getLinkId().getValue(), clfi);
253 mapFiberIp.put(clfi, ipFiber);
255 element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS",
256 ipFiber.getIpv4Address().getValue(), 20, 0, 0.2, 0, 0,
259 if (element1 != null) {
260 topoElements.add(element1);
261 destId = element1.getUid();
264 if (srcId != destId) {
265 Connections connection = createNewConnection(srcId, srcIp,
267 topoConnections.add(connection);
274 } else if (omsAttributes.getSpan() != null) {
275 IpAddress ipFiber = new IpAddress(new Ipv4Address("2.2.2." + idFiber));
276 mapLinkFiber.put(link.getLinkId().getValue(), clfi);
277 mapFiberIp.put(clfi, ipFiber);
282 String typeVariety = "SSMF";
284 // Compute the length of the link
285 org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130
286 .networks.network.link.oms.attributes.@Nullable Span span =
287 omsAttributes.getSpan();
288 List<LinkConcatenation> linkConcatenationList = span.getLinkConcatenation();
289 for (LinkConcatenation linkConcatenation : linkConcatenationList) {
290 double srlgLength = linkConcatenation.getSRLGLength();
291 //convert to kilometer
292 length += srlgLength / convertKmM;
294 double lossCoef = span.getSpanlossCurrent().getValue().doubleValue() / length;
295 Elements element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS",
296 ipFiber.getIpv4Address().getValue(), length, attIn, lossCoef, connIn,
297 connOut, typeVariety);
298 topoElements.add(element1);
300 destId = element1.getUid();
302 if (srcId != destId) {
303 Connections connection = createNewConnection(srcId, srcIp, destId, destIp);
304 topoConnections.add(connection);
310 clfi = "Fiber" + idFiber;
311 IpAddress ipFiber = new IpAddress(new Ipv4Address("2.2.2." + idFiber));
312 mapLinkFiber.put(link.getLinkId().getValue(), clfi);
313 mapFiberIp.put(clfi, ipFiber);
315 // Create a new element
316 Elements element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS",
317 ipFiber.getIpv4Address().getValue(), 20, 0, 0.2, 0, 0, "SSMF");
318 topoElements.add(element1);
320 destId = element1.getUid();
322 if (srcId != destId) {
323 Connections connection = createNewConnection(srcId, srcIp, destId, destIp);
324 topoConnections.add(connection);
330 LOG.warn("The oms attributes is null {} !",link1.getLinkType().getName());
333 destId = mapDisgNodeRefNode.get(link.getDestination().getDestNode().getValue());
334 destIp = mapNodeRefIp.get(destId);
335 Connections connection = createNewConnection(srcId, srcIp, destId, destIp);
336 topoConnections.add(connection);
340 LOG.warn("no links in the network");
343 LOG.warn("No nodes in the selected network ...");
346 } catch (InterruptedException | ExecutionException e) {
347 LOG.error("Error reading the topology", e);
348 this.networkTransactionService.close();
350 this.networkTransactionService.close();
351 map.put("Elements", topoElements);
352 map.put("Connections", topoConnections);
357 * Method to add Fiber
359 private Elements addElementsFiber(double latitude, double longitude, String region, String city, String clfi,
360 double length, double attIn, double lossCoef, double connIn, double connOut, String typeVariety) {
361 // Create an amplifier after the roadm
362 Coordinate c1 = new Coordinate(new BigDecimal(latitude));
363 Coordinate c2 = new Coordinate(new BigDecimal(longitude));
364 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
366 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
367 Fiber fiber = new FiberBuilder().setLength(new BigDecimal(length)).setLengthUnits(Km.class)
368 .setAttIn(new BigDecimal(attIn)).setLossCoef(new BigDecimal(lossCoef)).setConIn(new BigDecimal(connIn))
369 .setConOut(new BigDecimal(connOut)).build();
370 Params params1 = new ParamsBuilder().setFiberroadm(fiber).build();
371 Elements element1 = new ElementsBuilder().setUid(clfi)
372 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Fiber.class)
373 .setTypeVariety(typeVariety).setMetadata(metadata1)
374 .setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
381 private Elements addElementsEdfa(double latitude, double longitude, String region, String city,
382 BigDecimal gainTarget, BigDecimal tiltTarget, BigDecimal outVoa, String typeVariety, String uidEdfa) {
383 // Create an amplifier after the roadm
384 Coordinate c1 = new Coordinate(new BigDecimal(latitude));
385 Coordinate c2 = new Coordinate(new BigDecimal(longitude));
386 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
388 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
389 Operational operational = new OperationalBuilder().setGainTarget(gainTarget).setTiltTarget(tiltTarget)
390 .setOutVoa(outVoa).build();
391 Edfa edfa = new EdfaBuilder()
392 .setOperational(operational).build();
393 Elements element1 = new ElementsBuilder().setUid(uidEdfa)
394 // Choose an ip address
395 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Edfa.class)
396 .setMetadata(metadata1).setElementType(edfa).setTypeVariety(typeVariety).build();
401 * Method to add ROADM
403 private Elements addElementsRoadm(double latitude, double longitude, String region, String city,
404 double targetPchOutDb, String uidRoadm) {
406 Coordinate c1 = new Coordinate(new BigDecimal(latitude));
407 Coordinate c2 = new Coordinate(new BigDecimal(longitude));
408 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
410 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
412 Roadm roadm = new RoadmBuilder().setTargetPchOutDb(new BigDecimal(targetPchOutDb)).build();
413 Params params1 = new ParamsBuilder().setFiberroadm(roadm).build();
414 Elements element1 = new ElementsBuilder().setUid(uidRoadm)
415 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Roadm.class)
416 .setMetadata(metadata1).setElementType(new FiberRoadmBuilder().setParams(params1).build()).build();
421 * Method to add Transceiver
423 private Elements addElementsTransceiver(double latitude, double longitude, String region, String city,
425 Coordinate c1 = new Coordinate(new BigDecimal(latitude));
426 Coordinate c2 = new Coordinate(new BigDecimal(longitude));
427 Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2)
429 Metadata metadata1 = new MetadataBuilder().setLocation(location1).build();
430 Transceiver transceiver = new TransceiverBuilder().build();
431 Elements element1 = new ElementsBuilder().setUid(uidTrans)
432 .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Transceiver.class)
433 .setMetadata(metadata1).setElementType(transceiver).build();
437 private Connections createNewConnection(String srcId, IpAddress srcIp, String destId, IpAddress destIp) {
438 String fromNode = srcId;
439 String toNode = destId;
441 fromNode = srcIp.getIpv4Address().getValue().toString();
443 if (destIp != null) {
444 toNode = destIp.getIpv4Address().getValue().toString();
446 Connections connection1 = new ConnectionsBuilder().setFromNode(fromNode).setToNode(toNode).build();
447 return (connection1);
450 public List<Elements> getElements() {
454 public void setElements(List<Elements> elements) {
455 this.elements = elements;
458 public List<Connections> getConnections() {
462 public void setConnections(List<Connections> connections) {
463 this.connections = connections;
466 public Map<String, String> getMapDisgNodeRefNode() {
467 return mapDisgNodeRefNode;
470 public void setMapDisgNodeRefNode(Map<String, String> mapDisgNodeRefNode) {
471 this.mapDisgNodeRefNode = mapDisgNodeRefNode;
474 public Map<String, IpAddress> getMapNodeRefIp() {
478 public void setMapNodeRefIp(Map<String, IpAddress> mapNodeRefIp) {
479 this.mapNodeRefIp = mapNodeRefIp;
482 public Map<String, String> getMapLinkFiber() {
486 public void setMapLinkFiber(Map<String, String> mapLinkFiber) {
487 this.mapLinkFiber = mapLinkFiber;
490 public Map<String, IpAddress> getMapFiberIp() {
494 public void setMapFiberIp(Map<String, IpAddress> mapFiberIp) {
495 this.mapFiberIp = mapFiberIp;