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