Abort power setup if setting gainloss fails
[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 static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_1_2_1;
11 import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_2_2_1;
12 import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_7_1;
13
14 import java.util.Collection;
15 import java.util.Optional;
16 import java.util.concurrent.ExecutionException;
17 import java.util.stream.Collectors;
18 import java.util.stream.Stream;
19 import org.opendaylight.mdsal.binding.api.DataBroker;
20 import org.opendaylight.mdsal.binding.api.MountPoint;
21 import org.opendaylight.mdsal.binding.api.ReadTransaction;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.transportpce.common.Timeouts;
24 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
25 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
26 import org.opendaylight.transportpce.networkmodel.util.TopologyUtils;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.InitRoadmNodesInputBuilder;
28 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.Network;
29 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.cp.to.degree.CpToDegree;
30 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.mapping.Mapping;
31 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.network.Nodes;
32 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.network.NodesKey;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceData;
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.http.org.transportpce.common.types.rev220926.Direction;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.common.Uint8;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 public class R2RLinkDiscovery {
47
48     private static final Logger LOG = LoggerFactory.getLogger(R2RLinkDiscovery.class);
49
50     private final DataBroker dataBroker;
51     private final NetworkTransactionService networkTransactionService;
52     private final DeviceTransactionManager deviceTransactionManager;
53
54     public R2RLinkDiscovery(final DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager,
55         NetworkTransactionService networkTransactionService) {
56         this.dataBroker = dataBroker;
57         this.deviceTransactionManager = deviceTransactionManager;
58         this.networkTransactionService = networkTransactionService;
59     }
60
61     public boolean readLLDP(NodeId nodeId, String nodeVersion) {
62         switch (nodeVersion) {
63             case OPENROADM_DEVICE_VERSION_1_2_1:
64                 InstanceIdentifier<Protocols> protocols121IID = InstanceIdentifier
65                     .builderOfInherited(OrgOpenroadmDeviceData.class, OrgOpenroadmDevice.class)
66                     .child(Protocols.class)
67                     .build();
68                 Optional<Protocols> protocol121Object = this.deviceTransactionManager.getDataFromDevice(
69                     nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT,
70                     Timeouts.DEVICE_READ_TIMEOUT_UNIT);
71                 if (hasNoNeighbor121(protocol121Object)) {
72                     LOG.warn("LLDP subtree is missing or incomplete: isolated openroadm device");
73                     return false;
74                 }
75                 // get neighbor list
76                 NbrList nbr121List = protocol121Object.orElseThrow().augmentation(Protocols1.class).getLldp()
77                     .getNbrList();
78                 LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size());
79                 // try to create rdm2rdm link
80                 return rdm2rdmLinkCreatedv121(nodeId, nbr121List);
81             case OPENROADM_DEVICE_VERSION_2_2_1:
82                 InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
83                         .container.org.openroadm.device.Protocols> protocols221IID = InstanceIdentifier
84                     .builderOfInherited(
85                         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.OrgOpenroadmDeviceData.class,
86                         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container
87                             .OrgOpenroadmDevice.class)
88                     .child(
89                         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container
90                             .org.openroadm.device.Protocols.class)
91                     .build();
92                 var protocol221Object = this.deviceTransactionManager
93                     .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID,
94                         Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
95                 if (hasNoNeighbor221(protocol221Object)) {
96                     LOG.warn("LLDP subtree is missing or incomplete: isolated openroadm device");
97                     return false;
98                 }
99                 var nbr221List = protocol221Object.orElseThrow().augmentation(
100                         org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class)
101                     .getLldp().getNbrList();
102                 LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size());
103                 return rdm2rdmLinkCreatedv221(nodeId, nbr221List);
104             case OPENROADM_DEVICE_VERSION_7_1:
105                 LOG.info("Not yet implemented?");
106                 return false;
107             default:
108                 LOG.error("Unable to read LLDP data for unmanaged openroadm device version");
109                 return false;
110         }
111     }
112
113     private boolean hasNoNeighbor121(Optional<Protocols> protocol121Object) {
114         return protocol121Object.isEmpty()
115                 || protocol121Object.orElseThrow().augmentation(Protocols1.class) == null
116                 || protocol121Object.orElseThrow().augmentation(Protocols1.class).getLldp() == null
117                 || protocol121Object.orElseThrow().augmentation(Protocols1.class).getLldp().getNbrList() == null;
118     }
119
120     private boolean hasNoNeighbor221(Optional<
121             org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org
122                     .openroadm.device.Protocols> protocol221Object) {
123         return protocol221Object.isEmpty()
124                 || protocol221Object.orElseThrow().augmentation(
125                         org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null
126                 || protocol221Object.orElseThrow().augmentation(
127                         org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class)
128                     .getLldp() == null
129                 || protocol221Object.orElseThrow().augmentation(
130                         org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class)
131                     .getLldp().getNbrList() == null;
132     }
133
134     private boolean rdm2rdmLinkCreatedv221(NodeId nodeId,
135             org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) {
136         boolean success = true;
137         for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName
138             ifName : nbrList.nonnullIfName().values()) {
139             if (ifName.getRemoteSysName() == null) {
140                 LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
141                     nodeId.getValue(),ifName.getIfName());
142             } else {
143                 Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
144                     .getRemoteSysName());
145                 if (!mps.isPresent()) {
146                     LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
147                     // The controller raises a warning rather than an error because the first node to
148                     // mount cannot see its neighbors yet. The link will be detected when processing
149                     // the neighbor node.
150                 } else {
151                     if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
152                         ifName.getRemotePortId())) {
153                         LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName
154                             .getRemoteSysName());
155                         success = false;
156                     }
157                 }
158             }
159         }
160         return success;
161     }
162
163     private boolean rdm2rdmLinkCreatedv121(NodeId nodeId, NbrList nbrList) {
164         boolean success = true;
165         for (IfName ifName : nbrList.nonnullIfName().values()) {
166             if (ifName.getRemoteSysName() == null) {
167                 LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
168                     nodeId.getValue(),ifName.getIfName());
169             } else {
170                 Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
171                     .getRemoteSysName());
172                 if (!mps.isPresent()) {
173                     LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
174                     // The controller raises a warning rather than an error because the first node to
175                     // mount cannot see its neighbors yet. The link will be detected when processing
176                     // the neighbor node.
177                 } else {
178                     if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
179                         ifName.getRemotePortId())) {
180                         LOG.error("Link Creation failed between {} and {} nodes.", nodeId.getValue(),
181                             ifName.getRemoteSysName());
182                         success = false;
183                     }
184                 }
185             }
186         }
187         return success;
188     }
189
190     public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
191         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
192             .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
193         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
194             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
195             if (nodesObject.isPresent() && (nodesObject.orElseThrow().getMapping() != null)) {
196                 Collection<Mapping> mappingList = nodesObject.orElseThrow().nonnullMapping().values();
197                 mappingList = mappingList.stream().filter(mp -> mp.getLogicalConnectionPoint().contains("DEG"
198                     + degreeCounter)).collect(Collectors.toList());
199                 if (mappingList.size() == 1) {
200                     return Direction.Bidirectional;
201                 } else if (mappingList.size() > 1) {
202                     return Direction.Tx;
203                 } else {
204                     return Direction.NotApplicable;
205                 }
206             }
207         } catch (InterruptedException | ExecutionException e) {
208             LOG.error("Failed getting Mapping data from portMapping",e);
209         }
210         return Direction.NotApplicable;
211     }
212
213     public boolean createR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
214                                  String remoteInterfaceName) {
215         String srcTpTx = null;
216         String srcTpRx = null;
217         String destTpTx = null;
218         String destTpRx = null;
219         // Find which degree is associated with ethernet interface
220         Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
221         if (srcDegId == null) {
222             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
223             return false;
224         }
225         // Check whether degree is Unidirectional or Bidirectional by counting
226         // number of
227         // circuit-packs under degree subtree
228         Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
229         if (Direction.NotApplicable == sourceDirection) {
230             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
231             return false;
232         } else if (Direction.Bidirectional == sourceDirection) {
233             srcTpTx = "DEG" + srcDegId + "-TTP-TXRX";
234             srcTpRx = "DEG" + srcDegId + "-TTP-TXRX";
235         } else {
236             srcTpTx = "DEG" + srcDegId + "-TTP-TX";
237             srcTpRx = "DEG" + srcDegId + "-TTP-RX";
238         }
239         // Find degree for which Ethernet interface is created on other end
240         NodeId destNodeId = new NodeId(remoteSystemName);
241         Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
242         if (destDegId == null) {
243             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
244             return false;
245         }
246         // Check whether degree is Unidirectional or Bidirectional by counting
247         // number of
248         // circuit-packs under degree subtree
249         Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
250         if (Direction.NotApplicable == destinationDirection) {
251             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
252             return false;
253         } else if (Direction.Bidirectional == destinationDirection) {
254             destTpTx = "DEG" + destDegId + "-TTP-TXRX";
255             destTpRx = "DEG" + destDegId + "-TTP-TXRX";
256         } else {
257             destTpTx = "DEG" + destDegId + "-TTP-TX";
258             destTpRx = "DEG" + destDegId + "-TTP-RX";
259         }
260         // A->Z
261         LOG.debug(
262             "Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
263             nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx);
264         InitRoadmNodesInputBuilder r2rlinkBuilderAToZ = new InitRoadmNodesInputBuilder();
265         r2rlinkBuilderAToZ.setRdmANode(nodeId.getValue()).setDegANum(Uint8.valueOf(srcDegId))
266             .setTerminationPointA(srcTpTx).setRdmZNode(destNodeId.getValue()).setDegZNum(Uint8.valueOf(destDegId))
267             .setTerminationPointZ(destTpRx);
268         if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderAToZ.build(), this.dataBroker)) {
269             LOG.error("OMS Link creation failed between node: {} and nodeId: {} in A->Z direction", nodeId.getValue(),
270                 destNodeId.getValue());
271             return false;
272         }
273         // Z->A
274         LOG.debug(
275             "Found a neighbor SrcNodeId: {} , SrcDegId: {}"
276                 + ", SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
277             destNodeId, destDegId, destTpTx, nodeId.getValue(), srcDegId, srcTpRx);
278
279         InitRoadmNodesInputBuilder r2rlinkBuilderZToA = new InitRoadmNodesInputBuilder()
280             .setRdmANode(destNodeId.getValue())
281             .setDegANum(Uint8.valueOf(destDegId))
282             .setTerminationPointA(destTpTx)
283             .setRdmZNode(nodeId.getValue())
284             .setDegZNum(Uint8.valueOf(srcDegId))
285             .setTerminationPointZ(srcTpRx);
286         if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderZToA.build(), this.dataBroker)) {
287             LOG.error("OMS Link creation failed between node: {} and nodeId: {} in Z->A direction",
288                 destNodeId.getValue(), nodeId.getValue());
289             return false;
290         }
291         return true;
292     }
293
294     public boolean deleteR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
295                                  String remoteInterfaceName) {
296         String srcTpTx = null;
297         String srcTpRx = null;
298         String destTpTx = null;
299         String destTpRx = null;
300         // Find which degree is associated with ethernet interface
301         Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
302         if (srcDegId == null) {
303             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
304             return false;
305         }
306         // Check whether degree is Unidirectional or Bidirectional by counting number of
307         // circuit-packs under degree subtree
308         Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
309         if (Direction.NotApplicable == sourceDirection) {
310             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
311             return false;
312         } else if (Direction.Bidirectional == sourceDirection) {
313             srcTpTx = "DEG" + srcDegId + "-TTP-TXRX";
314             srcTpRx = "DEG" + srcDegId + "-TTP-TXRX";
315         } else {
316             srcTpTx = "DEG" + srcDegId + "-TTP-TX";
317             srcTpRx = "DEG" + srcDegId + "-TTP-RX";
318         }
319         // Find degree for which Ethernet interface is created on other end
320         NodeId destNodeId = new NodeId(remoteSystemName);
321         Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
322         if (destDegId == null) {
323             LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
324             return false;
325         }
326         // Check whether degree is Unidirectional or Bidirectional by counting number of
327         // circuit-packs under degree subtree
328         Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
329         if (Direction.NotApplicable == destinationDirection) {
330             LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
331             return false;
332         } else if (Direction.Bidirectional == destinationDirection) {
333             destTpTx = "DEG" + destDegId + "-TTP-TXRX";
334             destTpRx = "DEG" + destDegId + "-TTP-TXRX";
335         } else {
336             destTpTx = "DEG" + destDegId + "-TTP-TX";
337             destTpRx = "DEG" + destDegId + "-TTP-RX";
338         }
339         return TopologyUtils.deleteLink(nodeId.getValue() + "-" + srcDegId, destNodeId.getValue() + "-" + destDegId,
340             srcTpTx, destTpRx, networkTransactionService)
341             && TopologyUtils.deleteLink(destNodeId.getValue() + "-" + destDegId, nodeId.getValue() + "-" + srcDegId,
342                 destTpTx, srcTpRx, networkTransactionService);
343     }
344
345     private Integer getDegFromInterface(NodeId nodeId, String interfaceName) {
346         InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
347             .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
348         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
349             Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
350             if (nodesObject.isPresent() && (nodesObject.orElseThrow().getCpToDegree() != null)) {
351                 Collection<CpToDegree> cpToDeg = nodesObject.orElseThrow().nonnullCpToDegree().values();
352                 Stream<CpToDegree> cpToDegStream = cpToDeg.stream().filter(cp -> cp.getInterfaceName() != null)
353                     .filter(cp -> cp.getInterfaceName().equals(interfaceName));
354                 if (cpToDegStream != null) {
355                     @SuppressWarnings("unchecked") Optional<CpToDegree> firstCpToDegree = cpToDegStream.findFirst();
356                     if (firstCpToDegree.isPresent() && (firstCpToDegree != null)) {
357                         LOG.debug("Found and returning {}",firstCpToDegree.orElseThrow().getDegreeNumber().intValue());
358                         return firstCpToDegree.orElseThrow().getDegreeNumber().intValue();
359                     } else {
360                         LOG.debug("Not found so returning nothing");
361                         return null;
362                     }
363                 } else {
364                     LOG.warn("CircuitPack stream couldnt find anything for nodeId: {} and interfaceName: {}",
365                         nodeId.getValue(),interfaceName);
366                 }
367             } else {
368                 LOG.warn("Could not find mapping for Interface {} for nodeId {}", interfaceName,
369                     nodeId.getValue());
370             }
371         } catch (InterruptedException | ExecutionException ex) {
372             LOG.error("Unable to read mapping for Interface : {} for nodeId {}", interfaceName, nodeId, ex);
373         }
374         return null;
375     }
376 }