Fix R2R link deletion problem
[transportpce.git] / networkmodel / src / main / java / org / opendaylight / transportpce / networkmodel / R2RLinkDiscovery.java
1 /*
2  * Copyright © 2016 AT&T and others.  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.networkmodel;
9
10 import java.util.List;
11 import java.util.Optional;
12 import java.util.concurrent.ExecutionException;
13 import java.util.stream.Collectors;
14 import java.util.stream.Stream;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.MountPoint;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.transportpce.common.Timeouts;
21 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
22 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces;
23 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
24 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Protocols;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.Protocols1;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.NbrList;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.nbr.list.IfName;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.Network;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.Nodes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegree;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class R2RLinkDiscovery {
42
43     private static final Logger LOG = LoggerFactory.getLogger(R2RLinkDiscovery.class);
44
45     private final DataBroker dataBroker;
46     private final DeviceTransactionManager deviceTransactionManager;
47     private final OpenRoadmTopology openRoadmTopology;
48     private final OpenRoadmInterfaces openRoadmInterfaces;
49
50     public R2RLinkDiscovery(final DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager,
51                             OpenRoadmTopology openRoadmTopology, OpenRoadmInterfaces openRoadmInterfaces) {
52         this.dataBroker = dataBroker;
53         this.deviceTransactionManager = deviceTransactionManager;
54         this.openRoadmTopology = openRoadmTopology;
55         this.openRoadmInterfaces = openRoadmInterfaces;
56     }
57
58     public boolean readLLDP(NodeId nodeId) {
59         InstanceIdentifier<Protocols> protocolsIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
60                 .child(Protocols.class);
61         Optional<Protocols> protocolObject = this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(),
62                 LogicalDatastoreType.OPERATIONAL, protocolsIID, Timeouts.DEVICE_READ_TIMEOUT,
63                 Timeouts.DEVICE_READ_TIMEOUT_UNIT);
64         if (!protocolObject.isPresent() || (protocolObject.get().augmentation(Protocols1.class) == null)) {
65             LOG.warn("LLDP subtree is missing : isolated openroadm device");
66             return false;
67         }
68         NbrList nbrList = protocolObject.get().augmentation(Protocols1.class).getLldp().getNbrList();
69         LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size());
70         for (IfName ifName : nbrList.getIfName()) {
71             if (ifName.getRemoteSysName() == null) {
72                 LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
73                         nodeId.getValue(),ifName.getIfName());
74             } else {
75                 Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName());
76                 if (!mps.isPresent()) {
77                     LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
78                     // The controller raises a warning rather than an error because the first node to
79                     // mount cannot see its neighbors yet. The link will be detected when processing
80                     // the neighbor node.
81                 } else {
82                     if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
83                             ifName.getRemotePortId())) {
84                         LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName.getRemoteSysName());
85                         return false;
86                     }
87                 }
88             }
89         }
90         return true;
91     }
92
93     public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
94         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
95                 .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
96         try (ReadOnlyTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
97             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID)
98                     .get().toJavaUtil();
99             if (nodesObject.isPresent() && nodesObject.get().getMapping() != null) {
100                 List<Mapping> mappingList = nodesObject.get().getMapping();
101                 mappingList = mappingList.stream().filter(mp -> mp.getLogicalConnectionPoint().contains("DEG"
102                         + degreeCounter)).collect(Collectors.toList());
103                 if (mappingList.size() == 1) {
104                     return Direction.Bidirectional;
105                 } else if (mappingList.size() > 1) {
106                     return Direction.Tx;
107                 } else {
108                     return Direction.NotApplicable;
109                 }
110             }
111         } catch (InterruptedException | ExecutionException e) {
112             LOG.error("Failed getting Mapping data from portMapping",e);
113         }
114         return Direction.NotApplicable;
115     }
116
117     public boolean createR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
118                                  String remoteInterfaceName) {
119         String srcTpTx = null;
120         String srcTpRx = null;
121         String destTpTx = null;
122         String destTpRx = null;
123         // Find which degree is associated with ethernet interface
124         Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
125         if (srcDegId == null) {
126             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
127             return false;
128         }
129         // Check whether degree is Unidirectional or Bidirectional by counting
130         // number of
131         // circuit-packs under degree subtree
132         Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
133         if (Direction.NotApplicable == sourceDirection) {
134             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
135             return false;
136         } else if (Direction.Bidirectional == sourceDirection) {
137             srcTpTx = "DEG" + srcDegId + "-TTP-TXRX";
138             srcTpRx = "DEG" + srcDegId + "-TTP-TXRX";
139         } else {
140             srcTpTx = "DEG" + srcDegId + "-TTP-TX";
141             srcTpRx = "DEG" + srcDegId + "-TTP-RX";
142         }
143         // Find degree for which Ethernet interface is created on other end
144         NodeId destNodeId = new NodeId(remoteSystemName);
145         Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
146         if (destDegId == null) {
147             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
148             return false;
149         }
150         // Check whether degree is Unidirectional or Bidirectional by counting
151         // number of
152         // circuit-packs under degree subtree
153         Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
154         if (Direction.NotApplicable == destinationDirection) {
155             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
156             return false;
157         } else if (Direction.Bidirectional == destinationDirection) {
158             destTpTx = "DEG" + destDegId + "-TTP-TXRX";
159             destTpRx = "DEG" + destDegId + "-TTP-TXRX";
160         } else {
161             destTpTx = "DEG" + destDegId + "-TTP-TX";
162             destTpRx = "DEG" + destDegId + "-TTP-RX";
163         }
164         // A->Z
165         LOG.debug(
166             "Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
167             nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx);
168         InitRoadmNodesInputBuilder r2rlinkBuilderAToZ = new InitRoadmNodesInputBuilder();
169         r2rlinkBuilderAToZ.setRdmANode(nodeId.getValue()).setDegANum(srcDegId.shortValue())
170                 .setTerminationPointA(srcTpTx).setRdmZNode(destNodeId.getValue()).setDegZNum(destDegId.shortValue())
171                 .setTerminationPointZ(destTpRx);
172         if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderAToZ.build(), this.openRoadmTopology, this.dataBroker)) {
173             LOG.error("OMS Link creation failed between node: {} and nodeId: {} in A->Z direction", nodeId.getValue(),
174                     destNodeId.getValue());
175             return false;
176         }
177         // Z->A
178         LOG.debug(
179                 "Found a neighbor SrcNodeId: {} , SrcDegId: {}"
180                         + ", SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
181                 destNodeId, destDegId, destTpTx, nodeId.getValue(), srcDegId, srcTpRx);
182
183         InitRoadmNodesInputBuilder r2rlinkBuilderZToA = new InitRoadmNodesInputBuilder();
184         r2rlinkBuilderZToA.setRdmANode(destNodeId.getValue()).setDegANum(destDegId.shortValue())
185                 .setTerminationPointA(destTpTx).setRdmZNode(nodeId.getValue()).setDegZNum(srcDegId.shortValue())
186                 .setTerminationPointZ(srcTpRx);
187         if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderZToA.build(), this.openRoadmTopology, this.dataBroker)) {
188             LOG.error("OMS Link creation failed between node: {} and nodeId: {} in Z->A direction",
189                     destNodeId.getValue(), nodeId.getValue());
190             return false;
191         }
192         return true;
193     }
194
195     public boolean deleteR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
196                                  String remoteInterfaceName) {
197         String srcTpTx = null;
198         String srcTpRx = null;
199         String destTpTx = null;
200         String destTpRx = null;
201         // Find which degree is associated with ethernet interface
202         Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
203         if (srcDegId == null) {
204             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
205             return false;
206         }
207         // Check whether degree is Unidirectional or Bidirectional by counting number of
208         // circuit-packs under degree subtree
209         Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
210         if (Direction.NotApplicable == sourceDirection) {
211             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
212             return false;
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         // Find degree for which Ethernet interface is created on other end
221         NodeId destNodeId = new NodeId(remoteSystemName);
222         Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
223         if (destDegId == null) {
224             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
225             return false;
226         }
227         // Check whether degree is Unidirectional or Bidirectional by counting number of
228         // circuit-packs under degree subtree
229         Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
230         if (Direction.NotApplicable == destinationDirection) {
231             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
232             return false;
233         } else if (Direction.Bidirectional == destinationDirection) {
234             destTpTx = "DEG" + destDegId + "-TTP-TXRX";
235             destTpRx = "DEG" + destDegId + "-TTP-TXRX";
236         } else {
237             destTpTx = "DEG" + destDegId + "-TTP-TX";
238             destTpRx = "DEG" + destDegId + "-TTP-RX";
239         }
240         return this.openRoadmTopology.deleteLink(nodeId.getValue(), destNodeId.getValue(),
241                 srcDegId, destDegId, srcTpTx, destTpRx)
242                 && this.openRoadmTopology.deleteLink(destNodeId.getValue(), nodeId.getValue(),
243                 destDegId, srcDegId, destTpTx, srcTpRx);
244     }
245
246     private Integer getDegFromInterface(NodeId nodeId, String interfaceName) {
247         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
248                 .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
249         try (ReadOnlyTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
250             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID)
251                     .get().toJavaUtil();
252             if (nodesObject.isPresent() && nodesObject.get().getCpToDegree() != null) {
253                 List<CpToDegree> cpToDeg = nodesObject.get().getCpToDegree();
254                 Stream cpToDegStream = cpToDeg.stream().filter(cp -> cp.getInterfaceName() != null)
255                         .filter(cp -> cp.getInterfaceName().equals(interfaceName));
256                 if (cpToDegStream != null) {
257                     Optional<CpToDegree> firstCpToDegree = cpToDegStream.findFirst();
258                     if (firstCpToDegree.isPresent() && firstCpToDegree != null) {
259                         LOG.debug("Found and returning {}",firstCpToDegree.get().getDegreeNumber().intValue());
260                         return firstCpToDegree.get().getDegreeNumber().intValue();
261                     } else {
262                         LOG.debug("Not found so returning nothing");
263                         return null;
264                     }
265                 } else {
266                     LOG.warn("CircuitPack stream couldnt find anything for nodeId: {} and interfaceName: {}",
267                             nodeId.getValue(),interfaceName);
268                 }
269             } else {
270                 LOG.warn("Could not find mapping for Interface {} for nodeId {}", interfaceName,
271                             nodeId.getValue());
272             }
273         } catch (InterruptedException | ExecutionException ex) {
274             LOG.error("Unable to read mapping for Interface : {} for nodeId {}", interfaceName, nodeId, ex);
275         }
276         return null;
277     }
278 }