Fix ORDM device version in portmapping YANG model
[transportpce.git] / tapi / src / main / java / org / opendaylight / transportpce / tapi / R2RTapiLinkDiscovery.java
1 /*
2  * Copyright © 2021 Nokia.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.transportpce.tapi;
9
10 import java.nio.charset.Charset;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.UUID;
18 import java.util.concurrent.ExecutionException;
19 import java.util.stream.Collectors;
20 import java.util.stream.Stream;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.MountPoint;
24 import org.opendaylight.mdsal.binding.api.ReadTransaction;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.transportpce.common.Timeouts;
27 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210425.Network;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210425.cp.to.degree.CpToDegree;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210425.mapping.Mapping;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210425.network.Nodes;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210425.network.NodesKey;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Protocols;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.Protocols1;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.NbrList;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.nbr.list.IfName;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
40 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.AdministrativeState;
41 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.CapacityUnit;
42 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ForwardingDirection;
43 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName;
44 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LifecycleState;
45 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.OperationalState;
46 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid;
47 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.TotalSizeBuilder;
48 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.AvailableCapacityBuilder;
49 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.TotalPotentialCapacityBuilder;
50 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name;
51 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder;
52 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ProtectionType;
53 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RestorationPolicy;
54 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePoint;
55 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointBuilder;
56 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointKey;
57 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.ResilienceTypeBuilder;
58 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristic;
59 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristicBuilder;
60 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Link;
61 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkBuilder;
62 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkKey;
63 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristic;
64 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristicBuilder;
65 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristic;
66 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristicBuilder;
67 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanism;
68 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanismBuilder;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.common.Uint64;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 public class R2RTapiLinkDiscovery {
75
76     private static final Logger LOG = LoggerFactory.getLogger(R2RTapiLinkDiscovery.class);
77
78     private final DataBroker dataBroker;
79     private final DeviceTransactionManager deviceTransactionManager;
80     private static final String PHTNC_MEDIA = "PHOTONIC_MEDIA";
81
82     public R2RTapiLinkDiscovery(final DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager) {
83         this.dataBroker = dataBroker;
84         this.deviceTransactionManager = deviceTransactionManager;
85     }
86
87     public Map<LinkKey, Link> readLLDP(NodeId nodeId, int nodeVersion, Uuid tapiTopoUuid) {
88         LOG.info("Tapi R2R Link Node version = {}", nodeVersion);
89         // TODO -> waiting for device 7.1 in network model to change this to a switch statement and include
90         //  support for 7.1 devices
91         switch (nodeVersion) {
92             case 1:
93                 // 1.2.1
94                 InstanceIdentifier<Protocols> protocols121IID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
95                     .child(Protocols.class);
96                 Optional<Protocols> protocol121Object = this.deviceTransactionManager.getDataFromDevice(
97                     nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT,
98                     Timeouts.DEVICE_READ_TIMEOUT_UNIT);
99                 if (!protocol121Object.isPresent()
100                         || (protocol121Object.get().augmentation(Protocols1.class) == null)) {
101                     LOG.warn("LLDP subtree is missing : isolated openroadm device");
102                     return new HashMap<>();
103                 }
104                 // get neighbor list
105                 NbrList nbr121List = protocol121Object.get().augmentation(Protocols1.class).getLldp().getNbrList();
106                 LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size());
107                 // try to create rdm2rdm link
108                 return rdm2rdmLinkCreatev121(nodeId, tapiTopoUuid, nbr121List);
109             case 2:
110                 // 2.2.1
111                 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
112                     .container.org.openroadm.device.Protocols> protocols221IID =
113                         InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http
114                             .org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice.class)
115                             .child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
116                                 .org.openroadm.device.container.org.openroadm.device.Protocols.class);
117                 Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
118                     .container.org.openroadm.device.Protocols> protocol221Object = this.deviceTransactionManager
119                     .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID,
120                         Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
121                 if (!protocol221Object.isPresent() || (protocol221Object.get().augmentation(
122                         org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null)) {
123                     LOG.warn("LLDP subtree is missing : isolated openroadm device");
124                     return new HashMap<>();
125                 }
126                 org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList
127                     nbr221List = protocol221Object.get().augmentation(org.opendaylight.yang.gen.v1.http
128                         .org.openroadm.lldp.rev181019.Protocols1.class).getLldp().getNbrList();
129                 LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size());
130                 return rdm2rdmLinkCreatev221(nodeId, tapiTopoUuid, nbr221List);
131             case 3:
132                 // 7.1.0
133                 LOG.info("Not yet supported?");
134                 return new HashMap<>();
135             default:
136                 LOG.error("Unable to read LLDP data for unmanaged openroadm device version");
137                 return new HashMap<>();
138         }
139     }
140
141     private Map<LinkKey, Link> rdm2rdmLinkCreatev221(NodeId nodeId, Uuid tapiTopoUuid,
142             org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) {
143         Map<LinkKey, Link> linkMap = new HashMap<>();
144         for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName
145                 ifName : nbrList.nonnullIfName().values()) {
146             if (ifName.getRemoteSysName() == null) {
147                 LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
148                     nodeId.getValue(),ifName.getIfName());
149                 continue;
150             }
151             Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName());
152             if (!mps.isPresent()) {
153                 LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
154                 // The controller raises a warning rather than an error because the first node to
155                 // mount cannot see its neighbors yet. The link will be detected when processing
156                 // the neighbor node.
157                 continue;
158             }
159             Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
160                 ifName.getRemotePortId(), tapiTopoUuid);
161             if (omsLink != null) {
162                 linkMap.put(omsLink.key(), omsLink);
163             }
164         }
165         return linkMap;
166     }
167
168     private Map<LinkKey, Link> rdm2rdmLinkCreatev121(NodeId nodeId, Uuid tapiTopoUuid, NbrList nbrList) {
169         Map<LinkKey, Link> linkMap = new HashMap<>();
170         for (IfName ifName : nbrList.nonnullIfName().values()) {
171             if (ifName.getRemoteSysName() == null) {
172                 LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
173                     nodeId.getValue(),ifName.getIfName());
174                 continue;
175             }
176             Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
177                 .getRemoteSysName());
178             if (!mps.isPresent()) {
179                 LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
180                 // The controller raises a warning rather than an error because the first node to
181                 // mount cannot see its neighbors yet. The link will be detected when processing
182                 // the neighbor node.
183                 continue;
184             }
185             Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
186                 ifName.getRemotePortId(), tapiTopoUuid);
187             if (omsLink != null) {
188                 linkMap.put(omsLink.key(), omsLink);
189             }
190         }
191         return linkMap;
192     }
193
194     public Link createR2RTapiLink(NodeId nodeId, String interfaceName, String remoteSystemName,
195                                  String remoteInterfaceName, Uuid tapiTopoUuid) {
196         String srcTpTx = null;
197         String srcTpRx = null;
198         String destTpTx = null;
199         String destTpRx = null;
200         // Find which degree is associated with ethernet interface
201         Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
202         if (srcDegId == null) {
203             LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
204             return null;
205         }
206         // Check whether degree is Unidirectional or Bidirectional by counting
207         // number of
208         // circuit-packs under degree subtree
209         Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
210         if (Direction.NotApplicable == sourceDirection) {
211             LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
212             return null;
213         } else if (Direction.Bidirectional == sourceDirection) {
214             srcTpTx = "DEG" + srcDegId + "-TTP-TXRX";
215             srcTpRx = "DEG" + srcDegId + "-TTP-TXRX";
216         } else {
217             srcTpTx = "DEG" + srcDegId + "-TTP-TX";
218             srcTpRx = "DEG" + srcDegId + "-TTP-RX";
219         }
220         LOG.debug("Tapi R2R Link SrcTPTx {}, SrcTPRx {}", srcTpTx, srcTpRx);
221         // Find degree for which Ethernet interface is created on other end
222         NodeId destNodeId = new NodeId(remoteSystemName);
223         Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
224         if (destDegId == null) {
225             LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
226             return null;
227         }
228         // Check whether degree is Unidirectional or Bidirectional by counting
229         // number of
230         // circuit-packs under degree subtree
231         Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
232         if (Direction.NotApplicable == destinationDirection) {
233             LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}",
234                 destNodeId, destDegId);
235             return null;
236         } else if (Direction.Bidirectional == destinationDirection) {
237             destTpTx = "DEG" + destDegId + "-TTP-TXRX";
238             destTpRx = "DEG" + destDegId + "-TTP-TXRX";
239         } else {
240             destTpTx = "DEG" + destDegId + "-TTP-TX";
241             destTpRx = "DEG" + destDegId + "-TTP-RX";
242         }
243         // Todo -> only handling for the bidirectional case. I assume all tps are of the type bidirectional
244         LOG.debug("Tapi R2R Link DstTPTx {}, DstTPRx {}", destTpTx, srcTpRx);
245         // Create OMS Tapi Link
246         LOG.info("Tapi R2R Link Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , "
247             + "DestDegId: {}, DestTPId: {}", nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx);
248         Link omsLink = createTapiLink(nodeId.getValue(), srcTpTx, destNodeId.getValue(), destTpRx, tapiTopoUuid);
249         LOG.info("Tapi R2R Link OMS link created = {}", omsLink);
250         return omsLink;
251     }
252
253     private Link createTapiLink(String sourceNode, String sourceTp, String destNode, String destTp, Uuid tapiTopoUuid) {
254         Map<NodeEdgePointKey, NodeEdgePoint> nepList = new HashMap<>();
255         Uuid sourceUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode,
256             PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString());
257         Uuid sourceUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode, PHTNC_MEDIA, sourceTp))
258             .getBytes(Charset.forName("UTF-8"))).toString());
259         Uuid destUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode,
260             PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString());
261         Uuid destUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode, PHTNC_MEDIA, destTp))
262             .getBytes(Charset.forName("UTF-8"))).toString());
263         NodeEdgePoint sourceNep = new NodeEdgePointBuilder()
264             .setTopologyUuid(tapiTopoUuid)
265             .setNodeUuid(sourceUuidNode)
266             .setNodeEdgePointUuid(sourceUuidTp)
267             .build();
268         nepList.put(sourceNep.key(), sourceNep);
269         NodeEdgePoint destNep = new NodeEdgePointBuilder()
270             .setTopologyUuid(tapiTopoUuid)
271             .setNodeUuid(destUuidNode)
272             .setNodeEdgePointUuid(destUuidTp)
273             .build();
274         nepList.put(destNep.key(), destNep);
275         String linkNameValue = String.join("-", sourceNode, sourceTp.split("-")[0], sourceTp)
276             + "to" + String.join("-", destNode, destTp.split("-")[0], destTp);
277         Name linkName = new NameBuilder().setValueName("OMS link name")
278             .setValue(linkNameValue)
279             .build();
280         CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
281             .setCostAlgorithm("Restricted Shortest Path - RSP")
282             .setCostName("HOP_COUNT")
283             .setCostValue("12345678")
284             .build();
285         LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
286             .setFixedLatencyCharacteristic("12345678")
287             .setQueingLatencyCharacteristic("12345678")
288             .setJitterCharacteristic("12345678")
289             .setWanderCharacteristic("12345678")
290             .setTrafficPropertyName("FIXED_LATENCY")
291             .build();
292         RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder()
293             .setRiskCharacteristicName("risk characteristic")
294             .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2"))
295             .build();
296         ValidationMechanism validationMechanism = new ValidationMechanismBuilder()
297             .setValidationMechanism("validation mechanism")
298             .setValidationRobustness("validation robustness")
299             .setLayerProtocolAdjacencyValidated("layer protocol adjacency")
300             .build();
301         return new LinkBuilder()
302             .setUuid(new Uuid(
303                 UUID.nameUUIDFromBytes(linkNameValue.getBytes(Charset.forName("UTF-8")))
304                     .toString()))
305             .setName(Map.of(linkName.key(), linkName))
306             .setLayerProtocolName(List.of(LayerProtocolName.PHOTONICMEDIA))
307             .setTransitionedLayerProtocolName(new ArrayList<>())
308             .setNodeEdgePoint(nepList)
309             .setDirection(ForwardingDirection.BIDIRECTIONAL)
310             .setResilienceType(new ResilienceTypeBuilder().setProtectionType(ProtectionType.NOPROTECTON)
311                 .setRestorationPolicy(RestorationPolicy.NA)
312                 .build())
313             .setAdministrativeState(AdministrativeState.UNLOCKED)
314             .setOperationalState(OperationalState.ENABLED)
315             .setLifecycleState(LifecycleState.INSTALLED)
316             .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().setTotalSize(
317                 new TotalSizeBuilder().setUnit(CapacityUnit.GBPS)
318                     .setValue(Uint64.valueOf(100)).build()).build())
319             .setAvailableCapacity(new AvailableCapacityBuilder().setTotalSize(
320                 new TotalSizeBuilder().setUnit(CapacityUnit.MBPS)
321                     .setValue(Uint64.valueOf(100)).build())
322                 .build())
323             .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
324             .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
325             .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic))
326             .setErrorCharacteristic("error")
327             .setLossCharacteristic("loss")
328             .setRepeatDeliveryCharacteristic("repeat delivery")
329             .setDeliveryOrderCharacteristic("delivery order")
330             .setUnavailableTimeCharacteristic("unavailable time")
331             .setServerIntegrityProcessCharacteristic("server integrity process")
332             .setValidationMechanism(Map.of(validationMechanism.key(), validationMechanism))
333             .build();
334     }
335
336     private Integer getDegFromInterface(NodeId nodeId, String interfaceName) {
337         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
338             .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
339         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
340             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
341             if (nodesObject.isEmpty() || (nodesObject.get().getCpToDegree() == null)) {
342                 LOG.warn("Could not find mapping for Interface {} for nodeId {}", interfaceName,
343                     nodeId.getValue());
344                 return null;
345             }
346             Collection<CpToDegree> cpToDeg = nodesObject.get().nonnullCpToDegree().values();
347             Stream<CpToDegree> cpToDegStream = cpToDeg.stream().filter(cp -> cp.getInterfaceName() != null)
348                 .filter(cp -> cp.getInterfaceName().equals(interfaceName));
349             if (cpToDegStream != null) {
350                 @SuppressWarnings("unchecked") Optional<CpToDegree> firstCpToDegree = cpToDegStream.findFirst();
351                 if (firstCpToDegree.isEmpty() || (firstCpToDegree == null)) {
352                     LOG.debug("Not found so returning nothing");
353                     return null;
354                 }
355                 LOG.debug("Found and returning {}",firstCpToDegree.get().getDegreeNumber().intValue());
356                 return firstCpToDegree.get().getDegreeNumber().intValue();
357             } else {
358                 LOG.warn("CircuitPack stream couldnt find anything for nodeId: {} and interfaceName: {}",
359                     nodeId.getValue(),interfaceName);
360             }
361         } catch (InterruptedException | ExecutionException ex) {
362             LOG.error("Unable to read mapping for Interface : {} for nodeId {}", interfaceName, nodeId, ex);
363         }
364         return null;
365     }
366
367     public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
368         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
369             .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
370         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
371             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
372             if (nodesObject.isPresent() && (nodesObject.get().getMapping() != null)) {
373                 Collection<Mapping> mappingList = nodesObject.get().nonnullMapping().values();
374                 mappingList = mappingList.stream().filter(mp -> mp.getLogicalConnectionPoint().contains("DEG"
375                     + degreeCounter)).collect(Collectors.toList());
376                 if (mappingList.size() == 1) {
377                     return Direction.Bidirectional;
378                 } else if (mappingList.size() > 1) {
379                     return Direction.Tx;
380                 }
381             }
382         } catch (InterruptedException | ExecutionException e) {
383             LOG.error("Failed getting Mapping data from portMapping",e);
384         }
385         return Direction.NotApplicable;
386     }
387 }