2 * Copyright © 2017 AT&T, Inc. and others. All rights reserved.
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
8 package org.opendaylight.transportpce.pce;
10 import com.google.common.base.Optional;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.stream.Collectors;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.transportpce.common.NetworkUtils;
24 import org.opendaylight.transportpce.common.ResponseCodes;
25 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestInput;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.Node1;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev181130.OpenroadmNodeType;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 public class PceCalculation {
43 private static final Logger LOG = LoggerFactory.getLogger(PceCalculation.class);
44 private DataBroker dataBroker = null;
45 ///////////// data parsed from Input/////////////////
46 private PathComputationRequestInput input;
47 private String anodeId = "";
48 private String znodeId = "";
49 private PceConstraints pceHardConstraints;
50 private PceConstraints pceSoftConstraints;
51 ///////////// Intermediate data/////////////////
52 private List<PceLink> addLinks = new ArrayList<PceLink>();
53 private List<PceLink> dropLinks = new ArrayList<PceLink>();
54 private HashSet<NodeId> azSrgs = new HashSet<NodeId>();
55 private PceNode aendPceNode = null;
56 private PceNode zendPceNode = null;
57 private List<Link> allLinks = null;
58 private List<Node> allNodes = null;
59 // this List serves graph calculation
60 private Map<NodeId, PceNode> allPceNodes = new HashMap<NodeId, PceNode>();
61 // this List serves calculation of ZtoA path descritopn
62 // TODO maybe better solution is possible
63 private Map<LinkId, PceLink> allPceLinks = new HashMap<LinkId, PceLink>();
64 private PceResult returnStructure;
66 public PceResult getReturnStructure() {
67 return this.returnStructure;
70 public enum NodeConstraint {
71 NONE, HARD_EXCLUDE, HARD_INCLUDE, HARD_DIVERSITY, SOFT_EXCLUDE, SOFT_INCLUDE, SOFT_DIVERSITY;
74 // private static final String NETWORK_ID = "Transport Overlay";
75 public PceCalculation(PathComputationRequestInput input, DataBroker dataBroker, PceConstraints pceHardConstraints,
76 PceConstraints pceSoftConstraints, PceResult rc) {
78 this.dataBroker = dataBroker;
79 this.returnStructure = rc;
80 this.pceHardConstraints = pceHardConstraints;
81 this.pceSoftConstraints = pceSoftConstraints;
85 // apply constraints to get applicable result
86 public void calcPath() {
87 LOG.info("In PceCalculation calcPath: ");
89 this.returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
93 this.returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
96 this.returnStructure.setRC(ResponseCodes.RESPONSE_OK);
100 private boolean parseInput() {
101 this.anodeId = this.input.getServiceAEnd().getNodeId();
102 this.znodeId = this.input.getServiceZEnd().getNodeId();
103 LOG.info("parseInput: A and Z :[{}] and [{}]", this.anodeId, this.znodeId);
104 this.returnStructure.setRate(this.input.getServiceAEnd().getServiceRate());
108 private boolean readMdSal() {
109 LOG.info("readMdSal: network {}", NetworkUtils.OVERLAY_NETWORK_ID);
110 InstanceIdentifier<Network> nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
111 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
112 ReadOnlyTransaction readOnlyTransaction = this.dataBroker.newReadOnlyTransaction();
115 Optional<Network> nwOptional =
116 readOnlyTransaction.read(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier).get();
117 if (nwOptional.isPresent()) {
118 nw = nwOptional.get();
119 LOG.debug("readMdSal: network nodes: nwOptional.isPresent = true {}", nw.toString());
121 } catch (ExecutionException | InterruptedException e) {
122 LOG.error("readMdSal: Error reading topology {}", nwInstanceIdentifier);
123 readOnlyTransaction.close();
124 this.returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
125 throw new RuntimeException(
126 "readMdSal: Error reading from operational store, topology : " + nwInstanceIdentifier + " :" + e);
128 readOnlyTransaction.close();
130 LOG.error("readMdSal: network is null: {}", nwInstanceIdentifier);
133 this.allNodes = nw.getNode().stream()
134 .sorted((node1, node2) -> node1.getNodeId().getValue().compareTo(node2.getNodeId().getValue()))
135 .collect(Collectors.toList());
136 Network1 nw1 = nw.augmentation(Network1.class);
137 this.allLinks = nw1.getLink();
138 if ((this.allNodes == null) || this.allNodes.isEmpty()) {
139 LOG.error("readMdSal: no nodes ");
142 LOG.info("readMdSal: network nodes: {} nodes added", this.allNodes.size());
143 if ((this.allLinks == null) || this.allLinks.isEmpty()) {
144 LOG.error("readMdSal: no links ");
147 LOG.info("readMdSal: network links: {} links added", this.allLinks.size());
151 private boolean analyzeNw() {
152 LOG.debug("analyzeNw: allNodes size {}, allLinks size {}", this.allNodes.size(), this.allLinks.size());
153 for (Node node : this.allNodes) {
156 LOG.debug("analyzeNw: allPceNodes size {} : {}", this.allPceNodes.size(), this.allPceNodes.toString());
157 if ((this.aendPceNode == null) || (this.zendPceNode == null)) {
158 LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network");
161 for (Link link : this.allLinks) {
164 LOG.debug("analyzeNw: AddLinks size {}, DropLinks size {}", this.addLinks.size(), this.dropLinks.size());
166 LOG.info("analyzeNw: AZSrgs size = {}", this.azSrgs.size());
167 for (NodeId srg : this.azSrgs) {
168 LOG.info("analyzeNw: A/Z Srgs SRG = {}", srg.getValue());
171 for (PceLink link : this.addLinks) {
172 filterAddLinks(link);
174 for (PceLink link : this.dropLinks) {
175 filterDropLinks(link);
177 LOG.info("analyzeNw: allPceNodes size {}, allPceLinks size {}", this.allPceNodes.size(), this.allPceLinks
182 private boolean filterAddLinks(PceLink pcelink) {
183 NodeId nodeId = pcelink.getSourceId();
184 if (this.azSrgs.contains(nodeId)) {
185 this.allPceLinks.put(pcelink.getLinkId(), pcelink);
186 this.allPceNodes.get(nodeId).addOutgoingLink(pcelink);
187 LOG.info("analyzeNw: Add_LINK added to source and to allPceLinks {}", pcelink.getLinkId().toString());
190 // remove the SRG from PceNodes, as it is not directly connected to A/Z
191 this.allPceNodes.remove(nodeId);
192 LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
196 private boolean filterDropLinks(PceLink pcelink) {
197 NodeId nodeId = pcelink.getDestId();
198 if (this.azSrgs.contains(nodeId)) {
199 this.allPceLinks.put(pcelink.getLinkId(), pcelink);
200 this.allPceNodes.get(nodeId).addOutgoingLink(pcelink);
201 LOG.info("analyzeNw: Drop_LINK added to dest and to allPceLinks {}", pcelink.getLinkId().toString());
204 // remove the SRG from PceNodes, as it is not directly connected to A/Z
205 this.allPceNodes.remove(pcelink.getDestId());
206 LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
210 private boolean validateLink(Link link) {
211 LOG.info("validateLink: link {} ", link.toString());
212 NodeId sourceId = link.getSource().getSourceNode();
213 NodeId destId = link.getDestination().getDestNode();
214 PceNode source = this.allPceNodes.get(sourceId);
215 PceNode dest = this.allPceNodes.get(destId);
216 if (source == null) {
217 LOG.warn("validateLink: source node is rejected by node validation - {}", link.getSource().getSourceNode()
222 LOG.warn("validateLink: dest node is rejected by node validation - {}", link.getDestination().getDestNode()
226 PceLink pcelink = new PceLink(link);
227 if (!pcelink.isValid()) {
228 LOG.error(" validateLink: Link is ignored due errors in network data ");
231 LinkId linkId = pcelink.getLinkId();
232 switch (pcelink.getLinkType()) {
234 this.allPceLinks.put(linkId, pcelink);
235 source.addOutgoingLink(pcelink);
236 LOG.info("validateLink: ROADMTOROADM-LINK added to allPceLinks {}", pcelink.toString());
239 this.allPceLinks.put(linkId, pcelink);
240 source.addOutgoingLink(pcelink);
241 LOG.info("validateLink: EXPRESS-LINK added to allPceLinks {}", pcelink.toString());
244 pcelink.setClient(source.getRdmSrgClient(pcelink.getSourceTP().toString(), true));
245 this.addLinks.add(pcelink);
246 LOG.info("validateLink: ADD-LINK saved {}", pcelink.toString());
249 pcelink.setClient(dest.getRdmSrgClient(pcelink.getDestTP().toString(), false));
250 this.dropLinks.add(pcelink);
251 LOG.info("validateLink: DROP-LINK saved {}", pcelink.toString());
254 this.azSrgs.add(sourceId);
255 // store separately all SRG links directly connected to A/Z
256 if (!dest.checkTP(pcelink.getDestTP().toString())) {
257 LOG.debug("validateLink: XPONDER-INPUT is rejected as NW port is busy - {} ", pcelink.toString());
260 pcelink.setClient(dest.getXpdrClient(pcelink.getDestTP().toString()));
261 this.allPceLinks.put(linkId, pcelink);
262 source.addOutgoingLink(pcelink);
263 LOG.info("validateLink: XPONDER-INPUT link added to allPceLinks {}", pcelink.toString());
266 // does it mean XPONDER==>>SRG ?
267 this.azSrgs.add(destId);
268 // store separately all SRG links directly connected to A/Z
269 if (!source.checkTP(pcelink.getSourceTP().toString())) {
270 LOG.debug("validateLink: XPONDER-OUTPUT is rejected as NW port is busy - {} ", pcelink.toString());
273 pcelink.setClient(source.getXpdrClient(pcelink.getSourceTP().toString()));
274 this.allPceLinks.put(linkId, pcelink);
275 source.addOutgoingLink(pcelink);
276 LOG.info("validateLink: XPONDER-OUTPUT link added to allPceLinks {}", pcelink.toString());
279 LOG.warn("validateLink: link type is not supported {}", pcelink.toString());
284 private boolean validateNode(Node node) {
285 String supNodeId = "";
286 OpenroadmNodeType nodeType = null;
287 NodeId nodeId = null;
289 LOG.error("validateNode: node is null, ignored ");
293 // TODO: supporting IDs exist as a List. this code takes just the first element
294 nodeId = node.getNodeId();
295 supNodeId = node.getSupportingNode().get(0).getNodeRef().getValue();
296 if (supNodeId.equals("")) {
297 LOG.error("validateNode: Supporting node for node: [{}]. Node is ignored", nodeId.getValue());
301 Node1 node1 = node.augmentation(Node1.class);
303 LOG.error("validateNode: no Node1 (type) Augmentation for node: [{}]. Node is ignored", nodeId
307 nodeType = node1.getNodeType();
308 /** Catch exception 'RuntimeException' is not allowed. [IllegalCatch]. */
309 } catch (NullPointerException e) {
310 LOG.error("validateNode: Error reading supporting node or node type for node '{}'", nodeId, e);
313 if (nodeType == OpenroadmNodeType.XPONDER) {
315 if (supNodeId.equals(this.anodeId) || (supNodeId.equals(this.znodeId))) {
316 LOG.info("validateNode: A or Z node detected == {}", node.getNodeId().getValue());
318 LOG.warn("validateNode: XPONDER is ignored == {}", node.getNodeId().getValue());
322 switch (validateNodeConstraints(nodeId.getValue(), supNodeId)) {
324 LOG.info("validateNode: constraints : node is ignored == {}", nodeId.getValue());
329 PceNode pceNode = new PceNode(node, nodeType, nodeId);
330 if (!pceNode.isValid()) {
331 LOG.error(" validateNode: Node is ignored due errors in network data ");
334 if (supNodeId.equals(this.anodeId)) {
335 if (this.aendPceNode == null) {
336 if (endPceNode(nodeType, nodeId, pceNode, true)) {
337 if (!pceNode.isValid()) {
338 LOG.error("validateNode: There are no available wavelengths in node {}", nodeId.getValue());
341 this.aendPceNode = pceNode;
344 LOG.warn("aendPceNode already gets: {}", this.aendPceNode);
347 if (supNodeId.equals(this.znodeId)) {
348 if (this.zendPceNode == null) {
349 if (endPceNode(nodeType, nodeId, pceNode, false)) {
350 if (!pceNode.isValid()) {
351 LOG.error("validateNode: There are no available wavelengths in node {}", nodeId.getValue());
354 this.zendPceNode = pceNode;
357 LOG.warn("zendPceNode already gets: {}", this.zendPceNode);
360 pceNode.initWLlist();
361 if (!pceNode.isValid()) {
362 LOG.error("validateNode: There are no available wavelengths in node {}", nodeId.getValue());
365 this.allPceNodes.put(nodeId, pceNode);
366 LOG.debug("validateNode: node is saved {}", nodeId.getValue());
370 private Boolean endPceNode(OpenroadmNodeType openroadmNodeType, NodeId nodeId, PceNode pceNode, Boolean aend) {
372 switch (openroadmNodeType) {
374 pceNode.initSrgTps();
375 this.azSrgs.add(nodeId);
378 pceNode.initXndrTps();
382 LOG.warn("endPceNode: Node {} is not SRG or XPONDER !", nodeId);
388 private NodeConstraint validateNodeConstraints(String nodeId, String supNodeId) {
389 if (this.pceHardConstraints.getExcludeNodes().contains(nodeId)) {
390 return NodeConstraint.HARD_EXCLUDE;
392 if (this.pceHardConstraints.getExcludeNodes().contains(supNodeId)) {
393 return NodeConstraint.HARD_EXCLUDE;
395 if (this.pceHardConstraints.getIncludeNodes().contains(nodeId)) {
396 return NodeConstraint.HARD_INCLUDE;
398 if (this.pceHardConstraints.getIncludeNodes().contains(supNodeId)) {
399 return NodeConstraint.HARD_INCLUDE;
401 return NodeConstraint.NONE;
404 public PceNode getaPceNode() {
405 return this.aendPceNode;
408 public PceNode getzPceNode() {
409 return this.zendPceNode;
412 public Map<NodeId, PceNode> getAllPceNodes() {
413 return this.allPceNodes;
416 public Map<LinkId, PceLink> getAllPceLinks() {
417 return this.allPceLinks;