fix deprecated openroadm interfaces/objects
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / networkanalyzer / PceCalculation.java
1 /*
2  * Copyright © 2017 AT&T, Inc. 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
9 package org.opendaylight.transportpce.pce.networkanalyzer;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import java.util.concurrent.ExecutionException;
20 import java.util.stream.Collectors;
21
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.transportpce.common.NetworkUtils;
24 import org.opendaylight.transportpce.common.ResponseCodes;
25 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
26 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev190624.PathComputationRequestInput;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev181130.Node1;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmLinkType;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmNodeType;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 public class PceCalculation {
45     /* Logging. */
46     private static final Logger LOG = LoggerFactory.getLogger(PceCalculation.class);
47     private NetworkTransactionService networkTransactionService = null;
48
49     ///////////// data parsed from Input/////////////////
50     private PathComputationRequestInput input;
51     private String anodeId = "";
52     private String znodeId = "";
53
54     private PceConstraints pceHardConstraints;
55
56     ///////////// Intermediate data/////////////////
57     private List<PceLink> addLinks = new ArrayList<PceLink>();
58     private List<PceLink> dropLinks = new ArrayList<PceLink>();
59     private HashSet<NodeId> azSrgs = new HashSet<NodeId>();
60
61     private PceNode aendPceNode = null;
62     private PceNode zendPceNode = null;
63
64     private List<Link> allLinks = null;
65     private List<Node> allNodes = null;
66
67     // this List serves graph calculation
68     private Map<NodeId, PceNode> allPceNodes = new HashMap<NodeId, PceNode>();
69     // this List serves calculation of ZtoA path description
70     // TODO maybe better solution is possible
71     private Map<LinkId, PceLink> allPceLinks = new HashMap<LinkId, PceLink>();
72     private Set<LinkId> linksToExclude = new HashSet<LinkId>();
73     private PceResult returnStructure;
74
75     private enum ConstraintTypes {
76         NONE, HARD_EXCLUDE, HARD_INCLUDE, HARD_DIVERSITY, SOFT_EXCLUDE, SOFT_INCLUDE, SOFT_DIVERSITY;
77     }
78
79     public PceCalculation(PathComputationRequestInput input, NetworkTransactionService networkTransactionService,
80             PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints, PceResult rc) {
81         this.input = input;
82         this.networkTransactionService = networkTransactionService;
83         this.returnStructure = rc;
84
85         this.pceHardConstraints = pceHardConstraints;
86         parseInput();
87     }
88
89     public void calcPath() {
90
91         LOG.info("In PceCalculation calcPath: ");
92
93         if (!readMdSal()) {
94             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
95             return;
96         }
97
98         MapUtils.mapDiversityConstraints(allNodes, allLinks, pceHardConstraints);
99
100         if (!analyzeNw()) {
101             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
102             return;
103         }
104         printNodesInfo(allPceNodes);
105
106         returnStructure.setRC(ResponseCodes.RESPONSE_OK);
107         return;
108     }
109
110     private boolean parseInput() {
111         anodeId = input.getServiceAEnd().getNodeId();
112         znodeId = input.getServiceZEnd().getNodeId();
113         LOG.info("parseInput: A and Z :[{}] and [{}]", anodeId, znodeId);
114         returnStructure.setRate(input.getServiceAEnd().getServiceRate());
115         return true;
116     }
117
118     private boolean readMdSal() {
119         LOG.info("readMdSal: network {}", NetworkUtils.OVERLAY_NETWORK_ID);
120         InstanceIdentifier<Network> nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
121             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
122         Network nw = null;
123         try {
124             Optional<Network> nwOptional =
125                 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier).get();
126             if (nwOptional.isPresent()) {
127                 nw = nwOptional.get();
128                 LOG.debug("readMdSal: network nodes: nwOptional.isPresent = true {}", nw.toString());
129             }
130         } catch (InterruptedException | ExecutionException e) {
131             LOG.error("readMdSal: Error reading topology {}", nwInstanceIdentifier);
132             networkTransactionService.close();
133             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
134             throw new RuntimeException(
135                     "readMdSal: Error reading from operational store, topology : " + nwInstanceIdentifier + " :" + e);
136         }
137         networkTransactionService.close();
138
139         if (nw == null) {
140             LOG.error("readMdSal: network is null: {}", nwInstanceIdentifier);
141             return false;
142         }
143         allNodes = nw.getNode().stream().sorted((n1, n2) -> n1.getNodeId().getValue().compareTo(n2.getNodeId()
144             .getValue())).collect(Collectors.toList());
145         Network1 nw1 = nw.augmentation(Network1.class);
146
147         allLinks = nw1.getLink().stream().sorted((l1, l2) -> l1.getSource().getSourceTp().toString().compareTo(l2
148             .getSource().getSourceTp().toString())).collect(Collectors.toList());
149         if (allNodes == null || allNodes.isEmpty()) {
150             LOG.error("readMdSal: no nodes ");
151             return false;
152         }
153         LOG.info("readMdSal: network nodes: {} nodes added", allNodes.size());
154         LOG.debug("readMdSal: network nodes: {} nodes added", allNodes.toString());
155
156         if (allLinks == null || allLinks.isEmpty()) {
157             LOG.error("readMdSal: no links ");
158             return false;
159         }
160         LOG.info("readMdSal: network links: {} links added", allLinks.size());
161         LOG.debug("readMdSal: network links: {} links added", allLinks.toString());
162
163         return true;
164     }
165
166     private boolean analyzeNw() {
167
168         LOG.debug("analyzeNw: allNodes size {}, allLinks size {}", allNodes.size(), allLinks.size());
169
170         for (Node node : allNodes) {
171             validateNode(node);
172         }
173         LOG.debug("analyzeNw: allPceNodes size {}", allPceNodes.size());
174
175         if (aendPceNode == null || zendPceNode == null) {
176             LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network");
177             return false;
178         }
179
180         for (Link link : allLinks) {
181             validateLink(link);
182         }
183
184         LOG.debug("analyzeNw: addLinks size {}, dropLinks size {}", addLinks.size(), dropLinks.size());
185
186         // debug prints
187         LOG.debug("analyzeNw: azSrgs size = {}", azSrgs.size());
188         for (NodeId srg : azSrgs) {
189             LOG.debug("analyzeNw: A/Z Srgs SRG = {}", srg.getValue());
190         }
191         // debug prints
192
193         for (PceLink link : addLinks) {
194             filteraddLinks(link);
195         }
196         for (PceLink link : dropLinks) {
197             filterdropLinks(link);
198         }
199
200         LOG.info("analyzeNw: allPceNodes size {}, allPceLinks size {}", allPceNodes.size(), allPceLinks.size());
201
202         if ((allPceNodes.size() == 0) || (allPceLinks.size() == 0)) {
203             return false;
204         }
205
206         LOG.debug("analyzeNw: allPceNodes {}", allPceNodes.toString());
207         LOG.debug("analyzeNw: allPceLinks {}", allPceLinks.toString());
208
209         return true;
210     }
211
212     private boolean filteraddLinks(PceLink pcelink) {
213
214         NodeId nodeId = pcelink.getSourceId();
215
216         if (azSrgs.contains(nodeId)) {
217             allPceLinks.put(pcelink.getLinkId(), pcelink);
218             allPceNodes.get(nodeId).addOutgoingLink(pcelink);
219             LOG.debug("analyzeNw: Add_LINK added to source and to allPceLinks {}", pcelink.getLinkId().toString());
220             return true;
221         }
222
223         // remove the SRG from PceNodes, as it is not directly connected to A/Z
224         allPceNodes.remove(nodeId);
225         LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
226
227         return false;
228     }
229
230     private boolean filterdropLinks(PceLink pcelink) {
231
232         NodeId nodeId = pcelink.getDestId();
233
234         if (azSrgs.contains(nodeId)) {
235             allPceLinks.put(pcelink.getLinkId(), pcelink);
236             allPceNodes.get(nodeId).addOutgoingLink(pcelink);
237             LOG.debug("analyzeNw: Drop_LINK added to dest and to allPceLinks {}", pcelink.getLinkId().toString());
238             return true;
239         }
240
241         // remove the SRG from PceNodes, as it is not directly connected to A/Z
242         allPceNodes.remove(pcelink.getDestId());
243         LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
244
245         return false;
246     }
247
248     private boolean validateLink(Link link) {
249
250         LOG.debug("validateLink: link {} ", link.toString());
251
252         if (linksToExclude.contains(link.getLinkId())) {
253             LOG.info("validateLink: Link is ignored due opposite link problem - {}", link.getLinkId().getValue());
254             return false;
255         }
256
257         NodeId sourceId = link.getSource().getSourceNode();
258         NodeId destId = link.getDestination().getDestNode();
259         PceNode source = allPceNodes.get(sourceId);
260         PceNode dest = allPceNodes.get(destId);
261
262         if (source == null) {
263             LOG.debug("validateLink: Link is ignored due source node is rejected by node validation - {}",
264                     link.getSource().getSourceNode().getValue());
265             return false;
266         }
267         if (dest == null) {
268             LOG.debug("validateLink: Link is ignored due dest node is rejected by node validation - {}",
269                     link.getDestination().getDestNode().getValue());
270             return false;
271         }
272
273         PceLink pcelink = new PceLink(link, source, dest);
274         if (!pcelink.isValid()) {
275             dropOppositeLink(link);
276             LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link");
277             return false;
278         }
279
280         LinkId linkId = pcelink.getLinkId();
281
282         switch (validateLinkConstraints(pcelink)) {
283             case HARD_EXCLUDE :
284                 dropOppositeLink(link);
285                 LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue());
286                 return false;
287             default:
288                 break;
289         }
290
291         switch (pcelink.getlinkType()) {
292             case ROADMTOROADM :
293                 allPceLinks.put(linkId, pcelink);
294                 source.addOutgoingLink(pcelink);
295                 LOG.debug("validateLink: ROADMTOROADM-LINK added to allPceLinks {}", pcelink.toString());
296                 break;
297             case EXPRESSLINK :
298                 allPceLinks.put(linkId, pcelink);
299                 source.addOutgoingLink(pcelink);
300                 LOG.debug("validateLink: EXPRESS-LINK added to allPceLinks {}", pcelink.toString());
301                 break;
302             case ADDLINK :
303                 pcelink.setClient(source.getRdmSrgClient(pcelink.getSourceTP().toString(), true));
304                 addLinks.add(pcelink);
305                 LOG.debug("validateLink: ADD-LINK saved  {}", pcelink.toString());
306                 break;
307             case DROPLINK :
308                 pcelink.setClient(dest.getRdmSrgClient(pcelink.getDestTP().toString(), false));
309                 dropLinks.add(pcelink);
310                 LOG.debug("validateLink: DROP-LINK saved  {}", pcelink.toString());
311                 break;
312             case XPONDERINPUT :
313                 // store separately all SRG links directly
314                 azSrgs.add(sourceId);
315                 // connected to A/Z
316                 if (!dest.checkTP(pcelink.getDestTP().toString())) {
317                     LOG.debug("validateLink: XPONDER-INPUT is rejected as NW port is busy - {} ", pcelink.toString());
318                     return false;
319                 }
320                 pcelink.setClient(dest.getClient(pcelink.getDestTP().toString()));
321                 allPceLinks.put(linkId, pcelink);
322                 source.addOutgoingLink(pcelink);
323                 LOG.debug("validateLink: XPONDER-INPUT link added to allPceLinks {}", pcelink.toString());
324                 break;
325             // does it mean XPONDER==>>SRG ?
326             case XPONDEROUTPUT :
327                 // store separately all SRG links directly
328                 azSrgs.add(destId);
329                 // connected to A/Z
330                 if (!source.checkTP(pcelink.getSourceTP().toString())) {
331                     LOG.debug("validateLink: XPONDER-OUTPUT is rejected as NW port is busy - {} ", pcelink.toString());
332                     return false;
333                 }
334                 pcelink.setClient(source.getClient(pcelink.getSourceTP().toString()));
335                 allPceLinks.put(linkId, pcelink);
336                 source.addOutgoingLink(pcelink);
337                 LOG.debug("validateLink: XPONDER-OUTPUT link added to allPceLinks {}", pcelink.toString());
338                 break;
339             default:
340                 LOG.warn("validateLink: link type is not supported {}", pcelink.toString());
341
342         }
343
344         return true;
345     }
346
347     private boolean validateNode(Node node) {
348         LOG.debug("validateNode: node {} ", node.toString());
349
350         // PceNode will be used in Graph algorithm
351         Node1 node1 = node.augmentation(Node1.class);
352         if (node1 == null) {
353             LOG.error("getNodeType: no Node1 (type) Augmentation for node: [{}]. Node is ignored", node.getNodeId());
354         }
355         OpenroadmNodeType nodeType = node1.getNodeType();
356
357         PceNode pceNode = new PceNode(node,nodeType,node.getNodeId());
358         pceNode.validateAZxponder(anodeId, znodeId);
359         pceNode.initWLlist();
360
361         if (!pceNode.isValid()) {
362             LOG.warn(" validateNode: Node is ignored");
363             return false;
364         }
365
366         switch (validateNodeConstraints(pceNode)) {
367             case HARD_EXCLUDE :
368                 return false;
369
370             default :
371                 break;
372         }
373
374         if (pceNode.getSupNodeIdPceNode().equals(this.anodeId)) {
375             if (this.aendPceNode != null) {
376                 LOG.debug("aendPceNode already gets: {}", this.aendPceNode);
377             } else if (endPceNode(nodeType,pceNode.getNodeId(), pceNode)) {
378                 this.aendPceNode = pceNode;
379             }
380             // returning false otherwise would break E2E test
381         }
382         if (pceNode.getSupNodeIdPceNode().equals(this.znodeId)) {
383             if (this.zendPceNode != null) {
384                 LOG.debug("zendPceNode already gets: {}", this.zendPceNode);
385             } else if (endPceNode(nodeType,pceNode.getNodeId(), pceNode)) {
386                 this.zendPceNode = pceNode;
387             }
388             // returning false otherwise would break E2E test
389         }
390
391         allPceNodes.put(pceNode.getNodeId(), pceNode);
392         LOG.debug("validateNode: node is saved {}", pceNode.getNodeId().getValue());
393         return true;
394     }
395
396     private ConstraintTypes validateNodeConstraints(PceNode pcenode) {
397
398         if (pceHardConstraints.getExcludeSupNodes().isEmpty() && pceHardConstraints.getExcludeCLLI().isEmpty()) {
399             return ConstraintTypes.NONE;
400         }
401
402         if (pceHardConstraints.getExcludeSupNodes().contains(pcenode.getSupNodeIdPceNode())) {
403             LOG.info("validateNodeConstraints: {}", pcenode.getNodeId().getValue());
404             return ConstraintTypes.HARD_EXCLUDE;
405         }
406         if (pceHardConstraints.getExcludeCLLI().contains(pcenode.getCLLI())) {
407             LOG.info("validateNodeConstraints: {}", pcenode.getNodeId().getValue());
408             return ConstraintTypes.HARD_EXCLUDE;
409         }
410
411         return ConstraintTypes.NONE;
412     }
413
414     private ConstraintTypes validateLinkConstraints(PceLink link) {
415         if (pceHardConstraints.getExcludeSRLG().isEmpty()) {
416             return ConstraintTypes.NONE;
417         }
418
419         // for now SRLG is the only constraint for link
420         if (link.getlinkType() != OpenroadmLinkType.ROADMTOROADM) {
421             return ConstraintTypes.NONE;
422         }
423
424         List<Long> constraints = new ArrayList<Long>(pceHardConstraints.getExcludeSRLG());
425         constraints.retainAll(link.getsrlgList());
426         if (!constraints.isEmpty()) {
427             LOG.info("validateLinkConstraints: {}", link.getLinkId().getValue());
428             return ConstraintTypes.HARD_EXCLUDE;
429         }
430
431         return ConstraintTypes.NONE;
432     }
433
434     private void dropOppositeLink(Link link) {
435         LinkId opplink = MapUtils.extractOppositeLink(link);
436
437         PceLink oppPceLink = allPceLinks.get(opplink);
438         if (oppPceLink != null) {
439             allPceLinks.remove(oppPceLink);
440         } else {
441             linksToExclude.add(opplink);
442         }
443     }
444
445     private Boolean endPceNode(OpenroadmNodeType openroadmNodeType, NodeId nodeId, PceNode pceNode) {
446         switch (openroadmNodeType) {
447             case SRG :
448                 pceNode.initSrgTps();
449                 this.azSrgs.add(nodeId);
450                 break;
451             case XPONDER :
452                 pceNode.initXndrTps();
453                 break;
454             default:
455                 LOG.warn("endPceNode: Node {} is not SRG or XPONDER !", nodeId);
456                 return false;
457         }
458
459         if (!pceNode.isValid()) {
460             LOG.error("validateNode : there are no availaible wavelengths in node {}", pceNode.getNodeId().getValue());
461             return false;
462         }
463         return true;
464     }
465
466     public PceNode getaendPceNode() {
467         return aendPceNode;
468     }
469
470     public PceNode getzendPceNode() {
471         return zendPceNode;
472     }
473
474     public Map<NodeId, PceNode> getAllPceNodes() {
475         return this.allPceNodes;
476     }
477
478     public Map<LinkId, PceLink> getAllPceLinks() {
479         return this.allPceLinks;
480     }
481
482     public PceResult getReturnStructure() {
483         return returnStructure;
484     }
485
486     private static void printNodesInfo(Map<NodeId, PceNode> allpcenodes) {
487         Iterator<Map.Entry<NodeId, PceNode>> nodes = allpcenodes.entrySet().iterator();
488         while (nodes.hasNext()) {
489             PceNode pcenode = nodes.next().getValue();
490             List<PceLink> links = pcenode.getOutgoingLinks();
491             LOG.info("In printNodes in node {} : outgoing links {} ", pcenode.getNodeId().getValue(), links.toString());
492         }
493     }
494
495     /*private static void printLinksInfo(Map<LinkId, PceLink> allpcelinks) {
496         Iterator<Map.Entry<LinkId, PceLink>> links = allpcelinks.entrySet().iterator();
497         while (links.hasNext()) {
498             LOG.info("In printLinksInfo link {} : ", links.next().getValue().toString());
499         }
500     }*/
501
502 }