From e999f1d6d03d98e48ac7d47554699ec270bdf33f Mon Sep 17 00:00:00 2001 From: Gilles Thouenon Date: Tue, 16 Mar 2021 11:35:58 +0100 Subject: [PATCH] Update node-tp and link states on topologies When a mapping is updated after reception of an administrative state or operational state change from a device port, update associated node TP and links in openroadm-topology and otn-topology. - add in networkmodel a portmapping listener that listens to mapping updates - add a new updateOpenRoadmTopologies method in NetworkModelService to manage topology updates from a given mapping - remove updateOpenRoadmNetworkTopology that handled a change on a circuit-pack (not present as it in port-mapping) - implement the new updateTopologyShard method in TopologyUtils to update tp and if need be links (usable for both openroadm and otn topologies) JIRA: TRNSPRTPCE-420 Signed-off-by: Gilles Thouenon Co-authored-by: Christophe Betoule Change-Id: I8de09921e5a938676348e83e4883d953c47c13cb --- .../networkmodel/NetworkModelProvider.java | 15 +- .../listeners/PortMappingListener.java | 55 +++ .../service/NetworkModelService.java | 15 +- .../service/NetworkModelServiceImpl.java | 422 ++++-------------- .../networkmodel/util/TopologyUtils.java | 78 ++++ .../blueprint/networkmodel-blueprint.xml | 5 + .../NetworkModelProviderTest.java | 5 +- 7 files changed, 253 insertions(+), 342 deletions(-) create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/PortMappingListener.java diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java index 4dcf192af..5b406b148 100644 --- a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java @@ -15,6 +15,7 @@ import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.transportpce.common.InstanceIdentifiers; import org.opendaylight.transportpce.common.NetworkUtils; import org.opendaylight.transportpce.common.network.NetworkTransactionService; +import org.opendaylight.transportpce.networkmodel.listeners.PortMappingListener; import org.opendaylight.transportpce.networkmodel.listeners.ServiceHandlerListener; import org.opendaylight.transportpce.networkmodel.service.FrequenciesService; import org.opendaylight.transportpce.networkmodel.util.TpceNetwork; @@ -42,16 +43,18 @@ public class NetworkModelProvider { private final TransportpceNetworkutilsService networkutilsService; private final NetConfTopologyListener topologyListener; private ListenerRegistration dataTreeChangeListenerRegistration; + private ListenerRegistration mappingListenerRegistration; private ObjectRegistration networkutilsServiceRpcRegistration; private TpceNetwork tpceNetwork; private ListenerRegistration serviceHandlerListenerRegistration; private NotificationService notificationService; private FrequenciesService frequenciesService; + private PortMappingListener portMappingListener; public NetworkModelProvider(NetworkTransactionService networkTransactionService, final DataBroker dataBroker, final RpcProviderService rpcProviderService, final TransportpceNetworkutilsService networkutilsService, final NetConfTopologyListener topologyListener, NotificationService notificationService, - FrequenciesService frequenciesService) { + FrequenciesService frequenciesService, PortMappingListener portMappingListener) { this.dataBroker = dataBroker; this.rpcProviderService = rpcProviderService; this.networkutilsService = networkutilsService; @@ -59,6 +62,7 @@ public class NetworkModelProvider { this.tpceNetwork = new TpceNetwork(networkTransactionService); this.notificationService = notificationService; this.frequenciesService = frequenciesService; + this.portMappingListener = portMappingListener; } /** @@ -70,9 +74,11 @@ public class NetworkModelProvider { tpceNetwork.createLayer(NetworkUtils.UNDERLAY_NETWORK_ID); tpceNetwork.createLayer(NetworkUtils.OVERLAY_NETWORK_ID); tpceNetwork.createLayer(NetworkUtils.OTN_NETWORK_ID); - dataTreeChangeListenerRegistration = - dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, + dataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener( + DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), topologyListener); + mappingListenerRegistration = dataBroker.registerDataTreeChangeListener( + DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, MAPPING_II), portMappingListener); networkutilsServiceRpcRegistration = rpcProviderService.registerRpcImplementation(TransportpceNetworkutilsService.class, networkutilsService); TransportpceServicehandlerListener serviceHandlerListner = @@ -88,6 +94,9 @@ public class NetworkModelProvider { if (dataTreeChangeListenerRegistration != null) { dataTreeChangeListenerRegistration.close(); } + if (mappingListenerRegistration != null) { + mappingListenerRegistration.close(); + } if (networkutilsServiceRpcRegistration != null) { networkutilsServiceRpcRegistration.close(); } diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/PortMappingListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/PortMappingListener.java new file mode 100644 index 000000000..60a260d0d --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/PortMappingListener.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2021 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.transportpce.networkmodel.listeners; + +import java.util.Collection; +import java.util.LinkedList; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataTreeModification; +import org.opendaylight.transportpce.networkmodel.service.NetworkModelService; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PortMappingListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(PortMappingListener.class); + + private final NetworkModelService networkModelService; + + public PortMappingListener(NetworkModelService networkModelService) { + this.networkModelService = networkModelService; + } + + @Override + public void onDataTreeChanged(@NonNull Collection> changes) { + for (DataTreeModification change : changes) { + if (change.getRootNode().getDataBefore() != null && change.getRootNode().getDataAfter() != null) { + Mapping oldMapping = change.getRootNode().getDataBefore(); + Mapping newMapping = change.getRootNode().getDataAfter(); + if (oldMapping.getPortAdminState().equals(newMapping.getPortAdminState()) + || oldMapping.getPortOperState().equals(newMapping.getPortOperState())) { + return; + } else { + LinkedList path = new LinkedList<>(); + path.addAll((Collection) change.getRootPath().getRootIdentifier() + .getPathArguments()); + path.removeLast(); + InstanceIdentifier portmappintNodeID = (InstanceIdentifier) InstanceIdentifier + .create(path); + String nodeId = InstanceIdentifier.keyOf(portmappintNodeID).getNodeId(); + networkModelService.updateOpenRoadmTopologies(nodeId, newMapping); + } + } + } + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java index 74a249928..6505b11a5 100644 --- a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java @@ -8,7 +8,7 @@ package org.opendaylight.transportpce.networkmodel.service; import java.util.List; -import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping; import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev201019.OtnLinkType; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; @@ -37,15 +37,16 @@ public interface NetworkModelService { void deleteOpenRoadmnode(String nodeId); /** - * Update OpenROADM network topology. TODO: update all topologies + * Update termination point, and if need, be associated links, of + * openroadm-topology and otn-topology after a change on a given mapping. * * @param nodeId - * unique node ID of OpenROADM node that sent the NETCONF notification. - * @param changedCpack - * circuit pack modified from the NETCONF notification. - * + * unique node ID of OpenROADM node at the origin of the NETCONF + * notification change. + * @param mapping + * updated mapping following the device notification change. */ - void updateOpenRoadmNetworkTopology(String nodeId, CircuitPacks changedCpack); + void updateOpenRoadmTopologies(String nodeId, Mapping mapping); /** * Set/update connection status of OpenROADM node. diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java index 1a1e456f7..66e5460d1 100644 --- a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java @@ -8,12 +8,10 @@ package org.opendaylight.transportpce.networkmodel.service; import com.google.common.util.concurrent.ListenableFuture; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -22,6 +20,7 @@ import java.util.stream.Collectors; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.binding.api.NotificationPublishService; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.transportpce.common.InstanceIdentifiers; import org.opendaylight.transportpce.common.NetworkUtils; import org.opendaylight.transportpce.common.mapping.PortMapping; import org.opendaylight.transportpce.common.network.NetworkTransactionService; @@ -32,23 +31,13 @@ import org.opendaylight.transportpce.networkmodel.util.LinkIdUtil; import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork; import org.opendaylight.transportpce.networkmodel.util.OpenRoadmOtnTopology; import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; -import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult; -import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResultBuilder; -import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChanges; -import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChangesBuilder; -import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChangesKey; +import org.opendaylight.transportpce.networkmodel.util.TopologyUtils; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.OpenroadmNodeVersion; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.nodes.NodeInfo; -import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1Builder; -import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1Builder; -import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State; -import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.Ports; -import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes; -import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates; import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.Link1; import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.TerminationPoint1; -import org.opendaylight.yang.gen.v1.http.org.transportpce.d._interface.ord.topology.types.rev201116.TopologyNotificationTypes; import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev201019.OtnLinkType; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks; @@ -56,18 +45,14 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.termination.point.SupportingTerminationPoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; @@ -85,13 +70,6 @@ public class NetworkModelServiceImpl implements NetworkModelService { private final PortMapping portMapping; private Map topologyShardMountedDevice; private Map otnTopologyShardMountedDevice; - // Maps that include topology component changed with its new operational state - private Map linksChanged; - private Map terminationPointsChanged; - // Variables for creating and sending topology update notification - private final NotificationPublishService notificationPublishService; - private Map topologyChanges; - private TopologyUpdateResult notification = null; public NetworkModelServiceImpl(final NetworkTransactionService networkTransactionService, final R2RLinkDiscovery linkDiscovery, PortMapping portMapping, @@ -102,10 +80,6 @@ public class NetworkModelServiceImpl implements NetworkModelService { this.portMapping = portMapping; this.topologyShardMountedDevice = new HashMap(); this.otnTopologyShardMountedDevice = new HashMap(); - this.linksChanged = new HashMap(); - this.terminationPointsChanged = new HashMap(); - this.notificationPublishService = notificationPublishService; - this.topologyChanges = new HashMap(); } public void init() { @@ -279,68 +253,97 @@ public class NetworkModelServiceImpl implements NetworkModelService { } @Override - public void updateOpenRoadmNetworkTopology(String nodeId, CircuitPacks changedCpack) { - // Clear maps for each NETCONF notification received - this.linksChanged.clear(); - this.terminationPointsChanged.clear(); - this.topologyChanges.clear(); - // 1. Get the list links and nodes of the current openroadm network topology - List linkList = null; - List nodesList = null; + public void updateOpenRoadmTopologies(String nodeId, Mapping mapping) { + LOG.info("update OpenRoadm topologies after change update from: {} ", nodeId); + Network openroadmTopology = null; + Network otnTopology = null; + Map openroadmTopologyLinks = null; + Map otnTopologyLinks = null; try { - InstanceIdentifier.InstanceIdentifierBuilder network1IID = - InstanceIdentifier.builder(Networks.class) - .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) - .augmentation(Network1.class); - InstanceIdentifier.InstanceIdentifierBuilder networkIID = - InstanceIdentifier.builder(Networks.class) - .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))); - Optional networkOptional = this.networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, - networkIID.build()).get(); - Optional network1Optional = - this.networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, network1IID.build()).get(); - if (network1Optional.isPresent()) { - // Links list - linkList = new ArrayList<>(Objects.requireNonNull(network1Optional.get().getLink()).values()); + openroadmTopology = this.networkTransactionService + .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OVERLAY_NETWORK_II) + .get().get(); + if (openroadmTopology.augmentation(Network1.class) != null) { + openroadmTopologyLinks = openroadmTopology.augmentation(Network1.class).getLink(); } - if (networkOptional.isPresent()) { - // Nodes list - nodesList = new ArrayList<>(Objects.requireNonNull(networkOptional.get().getNode()).values()); + otnTopology = this.networkTransactionService + .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OTN_NETWORK_II) + .get().get(); + if (otnTopology.augmentation(Network1.class) != null) { + otnTopologyLinks = otnTopology.augmentation(Network1.class).getLink(); } - } catch (InterruptedException e) { - LOG.error("Couldn't get list of links in the network. Error={}", e.getMessage()); - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - LOG.error("Couldn't get list of links in the network. Error={}", e.getMessage()); - } - /* 2. For simplicity the update is only considered in the case of a WSSDEG circuit pack change where client and - line ports (external ports) of a node are included and there is a 1-to-1 port mapping to the nodes TPs. The - mapping between ports and TPs internal of a node is a bit different as the is a 1-to-many port mapping */ - String cpackType = changedCpack.getCircuitPackType(); - switch (cpackType) { - case "ADDROP": - LOG.info("ADDROP circuit pack modified"); - setTerminationPointsChangedMap(changedCpack, nodeId); - // setTpStateHashmap(changedCpack); - break; - case "WSSDEG": - LOG.info("WSSDEG circuit pack modified"); - setTerminationPointsChangedMap(changedCpack, nodeId); - // 3. Update the termination points of the node that sent a NETCONF notification - updateOpenRoadmNetworkTopologyTPs(nodesList, nodeId); - // 4. Update the links of the topology affected by the changes on TPs (if any) - updateOpenRoadmNetworkTopologyLinks(linkList, nodesList); - // Send notification to service handler - sendNotification(TopologyNotificationTypes.OpenroadmTopologyUpdate, this.topologyChanges); - break; - case "port": - LOG.info("port circuit pack modified"); - break; - case "pluggable": - LOG.info("pluggable circuit pack modified"); - break; - default: - LOG.warn("Circuitp pack of type {} not recognized", cpackType); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error when trying to update node : {}", nodeId, e); + } + if (openroadmTopology == null || otnTopology == null) { + LOG.warn("Error getting topologies from datastore"); + return; + } + String abstractNodeid = String.join("-", nodeId, mapping.getLogicalConnectionPoint().split("-")[0]); + // nodes/links update in openroadm-topology + if (openroadmTopology.getNode() != null) { + TopologyShard topologyShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping, + openroadmTopology.getNode(), openroadmTopologyLinks); + if (topologyShard.getLinks() != null) { + for (Link link : topologyShard.getLinks()) { + LOG.info("updating links {} in {}", link.getLinkId().getValue(), + NetworkUtils.OVERLAY_NETWORK_ID); + InstanceIdentifier iiTopologyLink = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .augmentation(Network1.class) + .child(Link.class, link.key()) + .build(); + networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link); + } + } + if (topologyShard.getTps() != null) { + for (TerminationPoint tp : topologyShard.getTps()) { + LOG.info("updating TP {} in openroadm-topology", tp.getTpId().getValue()); + InstanceIdentifier iiTopologyTp = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .child(Node.class, new NodeKey(new NodeId(abstractNodeid))) + .augmentation(Node1.class) + .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId())) + .build(); + networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp); + } + } + } + // nodes/links update in otn-topology + if (otnTopology.getNode() != null + && otnTopology.getNode().containsKey(new NodeKey(new NodeId(abstractNodeid)))) { + TopologyShard otnShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping, + otnTopology.getNode(), otnTopologyLinks); + if (otnShard.getLinks() != null) { + for (Link link : otnShard.getLinks()) { + LOG.info("updating links {} in {}", link.getLinkId().getValue(), + NetworkUtils.OVERLAY_NETWORK_ID); + InstanceIdentifier iiTopologyLink = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID))) + .augmentation(Network1.class) + .child(Link.class, link.key()) + .build(); + networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link); + } + } + if (otnShard.getTps() != null) { + for (TerminationPoint tp : otnShard.getTps()) { + LOG.info("updating TP {} in otn-topology", tp.getTpId().getValue()); + InstanceIdentifier iiTopologyTp = InstanceIdentifier.builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID))) + .child(Node.class, new NodeKey(new NodeId(abstractNodeid))) + .augmentation(Node1.class) + .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId())) + .build(); + networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp); + } + } + } + // commit datastore updates + try { + networkTransactionService.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error updating openroadm-topology", e); } } @@ -736,248 +739,5 @@ public class NetworkModelServiceImpl implements NetworkModelService { } else { LOG.error("Unable to create OTN topology shard for node {}!", nodeId); } - - } - - private void setTerminationPointsChangedMap(CircuitPacks changedCpack, String nodeId) { - List portsList = new ArrayList<>(Objects.requireNonNull(changedCpack.getPorts()).values()); - for (Ports port : portsList) { - String lcp = port.getLogicalConnectionPoint(); - if (lcp != null) { - String abstractNodeid = nodeId + "-" + lcp.split("-")[0]; - if (!this.terminationPointsChanged.containsKey(abstractNodeid + "-" + lcp)) { - LOG.info("Node id {}, LCP {}", abstractNodeid, lcp); - this.terminationPointsChanged.put(abstractNodeid + "-" + lcp, - State.forValue(port.getOperationalState().getIntValue())); - } - } - } - } - - private void updateOpenRoadmNetworkTopologyTPs(List nodesList, String nodeId) { - /* 1. The nodes in nodesList are abstract nodes (i.e. ROADMA01-DEG1) and we have the id of the node that has - a change (i.e. ROADMA01). So we only need to look for the abstract nodes that belong to the physical node. */ - String abstractNodeId; - for (Node node : nodesList) { - abstractNodeId = Objects.requireNonNull(node.getNodeId()).getValue(); - // Checking if the node is operationally inService - if (abstractNodeId.contains(nodeId) && node.augmentation(org.opendaylight.yang.gen.v1.http - .org.openroadm.common.network.rev200529.Node1.class) - .getOperationalState().equals(State.InService)) { - /* 2. Check if the state of the termination points from the topology shard are equal to the state of - the termination points in the previously created map. */ - List tpList = new ArrayList<>(Objects.requireNonNull(node.augmentation(Node1.class)) - .getTerminationPoint().values()); - Map updatedTpMap = new HashMap<>(); - for (TerminationPoint tp : tpList) { - String tpId = Objects.requireNonNull(tp.getTpId()).getValue(); - State tpState = Objects.requireNonNull(tp.augmentation(org.opendaylight.yang.gen.v1.http - .org.openroadm.common.network.rev200529.TerminationPoint1.class)).getOperationalState(); - String key = abstractNodeId + "-" + tpId; - if (this.terminationPointsChanged.containsKey(key) - && !this.terminationPointsChanged.get(key).equals(tpState)) { - // The state of a termination point has changed... updating - State newTpOperationalState = null; - AdminStates newTpAdminState = null; - /* 3. If the TP has changed its state, it has to be added to the links Map, as a Link state - is defined by the state of the TPs that model the link. */ - switch (this.terminationPointsChanged.get(key)) { - case InService: - newTpAdminState = AdminStates.InService; - newTpOperationalState = State.InService; - // Add TP and state inService to the links Map - this.linksChanged.put(key, State.InService); - // Update topology change list for service handler notification - this.topologyChanges.put( - new OrdTopologyChangesKey(node.getNodeId().getValue() + "-" + tpId), - new OrdTopologyChangesBuilder() - .setId(node.getNodeId().getValue() + "-" + tpId) - .setState(newTpOperationalState) - .build()); - break; - case OutOfService: - newTpAdminState = AdminStates.OutOfService; - newTpOperationalState = State.OutOfService; - // Add TP and state outOfService to the links Map - this.linksChanged.put(key, State.OutOfService); - // Update topology change list for service handler notification - this.topologyChanges.put( - new OrdTopologyChangesKey(node.getNodeId().getValue() + "-" + tpId), - new OrdTopologyChangesBuilder() - .setId(node.getNodeId().getValue() + "-" + tpId) - .setState(newTpOperationalState) - .build()); - break; - case Degraded: - LOG.warn("Operational state Degraded not handled"); - break; - default: - LOG.warn("Unrecognized state!"); - } - // 4. Add modified TP to the updated List. - TerminationPoint updTp = new TerminationPointBuilder().withKey(tp.key()) - .setTpId(tp.getTpId()) - .addAugmentation(new TerminationPoint1Builder() - .setAdministrativeState(newTpAdminState) - .setOperationalState(newTpOperationalState) - .build()) - .build(); - updatedTpMap.put(tp.key(), updTp); - } - // 5. Update the list of termination points of the corresponding node and merge to the datastore. - if (!updatedTpMap.isEmpty()) { - Node updNode = new NodeBuilder().setNodeId(node.getNodeId()).addAugmentation(new Node1Builder() - .setTerminationPoint(updatedTpMap).build()).build(); - InstanceIdentifier iiOpenRoadmTopologyNode = InstanceIdentifier.builder( - Networks.class).child(Network.class, new NetworkKey( - new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).child(Node.class, node.key()) - .build(); - networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode, - updNode); - try { - networkTransactionService.commit().get(); - } catch (InterruptedException e) { - LOG.error("Couldnt commit change to openroadm topology.", e); - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - LOG.error("Couldnt commit change to openroadm topology.", e); - } - } - } - } - } - } - - private void updateOpenRoadmNetworkTopologyLinks(List linkList, List nodesList) { - for (Link link : linkList) { - String srcTp = link.getSource().getSourceTp().toString(); - String dstTp = link.getDestination().getDestTp().toString(); - String srcNode = link.getSource().getSourceNode().getValue(); - String dstNode = link.getDestination().getDestNode().getValue(); - State linkState = link.augmentation(org.opendaylight.yang.gen.v1.http - .org.openroadm.common.network.rev200529.Link1.class).getOperationalState(); - String srcKey = srcNode + "-" + srcTp; - String dstKey = dstNode + "-" + dstTp; - /* 1. Check the current state of the source and dest tps of the link. If these tps exist on the links Map - and the states are different, then we need to update the link state accordingly. - There are several cases depending on the current link state: - - TPs were both inService and one of them (or both) is (are) now outOfService --> link to outOfService - - TPs were both outOfService and both of them are now inService --> link to inService - However, if only one TP exists on the Link map, we will need to check the state of the other end in order to - make a decision: i.e. we cannot assume that if a TP has changed from outOfService to inService the link will - become inService, as this can only happen if both TPs are inService, therefore we need to check the other - end. */ - switch (linkState) { - case InService: - if (this.linksChanged.containsKey(srcKey) && this.linksChanged.containsKey(dstKey)) { - // Both TPs of the link have been updated. If one of them is outOfService --> link outOfService - if (State.OutOfService.equals(this.linksChanged.get(srcKey)) || State.OutOfService.equals(this - .linksChanged.get(dstKey))) { - updateLinkStates(link, State.OutOfService, AdminStates.OutOfService); - } - } else if (this.linksChanged.containsKey(srcKey) && State.OutOfService.equals(this.linksChanged - .get(srcKey))) { - // Source TP has been changed to outOfService --> link outOfService - updateLinkStates(link, State.OutOfService, AdminStates.OutOfService); - } else if (this.linksChanged.containsKey(dstKey) && State.OutOfService.equals(this.linksChanged - .get(dstKey))) { - // Destination TP has been changed to outOfService --> link outOfService - updateLinkStates(link, State.OutOfService, AdminStates.OutOfService); - } - break; - case OutOfService: - if (this.linksChanged.containsKey(srcKey) && this.linksChanged.containsKey(dstKey)) { - // Both TPs of the link have been updated. If both of them are inService --> link inService - if (State.InService.equals(this.linksChanged.get(srcKey)) || State.InService.equals(this - .linksChanged.get(dstKey))) { - updateLinkStates(link, State.InService, AdminStates.InService); - } - } else if (this.linksChanged.containsKey(srcKey) && State.InService.equals(this.linksChanged - .get(srcKey))) { - // Source TP has been changed to inService --> check the second TP and update link to inService - // only if both TPs are inService - if (tpInService(dstNode, dstTp, nodesList)) { - updateLinkStates(link, State.InService, AdminStates.InService); - } - } else if (this.linksChanged.containsKey(dstKey) && State.InService.equals(this.linksChanged - .get(dstKey))) { - // Destination TP has been changed to to inService --> check the second TP and update link to - // inService only if both TPs are inService - if (tpInService(srcNode, srcTp, nodesList)) { - updateLinkStates(link, State.InService, AdminStates.InService); - } - } - break; - case Degraded: - LOG.warn("Link state degraded not handled"); - break; - default: - LOG.warn("Unrecognized state!"); - } - } - } - - private boolean tpInService(String nodeId, String tpId, List nodesList) { - // Check the node with dstNode id and check the state of the TP with id dstTP id - for (Node node : nodesList) { - if (Objects.requireNonNull(node.getNodeId()).getValue().equals(nodeId)) { - List tpList = new ArrayList<>(Objects.requireNonNull(Objects.requireNonNull(node - .augmentation(Node1.class)).getTerminationPoint()).values()); - for (TerminationPoint tp : tpList) { - if (Objects.requireNonNull(tp.getTpId()).getValue().equals(tpId)) { - if (State.InService.equals(tp.augmentation(org.opendaylight.yang.gen.v1.http - .org.openroadm.common.network.rev200529.TerminationPoint1.class) - .getOperationalState())) { - // The second TP is also inService - return true; - } - break; - } - } - break; - } - } - return false; - } - - private void updateLinkStates(Link link, State state, AdminStates adminStates) { - // TODO: add change to list of changes - // Update topology change list - this.topologyChanges.put(new OrdTopologyChangesKey(link.getLinkId().getValue()), - new OrdTopologyChangesBuilder().setId(link.getLinkId().getValue()).setState(state).build()); - org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1 link1 = new Link1Builder() - .setOperationalState(state).setAdministrativeState(adminStates).build(); - Link updLink = new LinkBuilder().withKey(link.key()).addAugmentation(link1).build(); - InstanceIdentifier.InstanceIdentifierBuilder linkIID = InstanceIdentifier.builder(Networks.class) - .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) - .augmentation(Network1.class).child(Link.class, link.key()); - networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, linkIID.build(), updLink); - try { - networkTransactionService.commit().get(); - } catch (InterruptedException e) { - LOG.error("Couldnt commit changed to openroadm topology. Error={}", e.getMessage()); - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - LOG.error("Couldnt commit changed to openroadm topology. Error={}", e.getMessage()); - } - } - - @SuppressFBWarnings( - value = "UPM_UNCALLED_PRIVATE_METHOD", - justification = "false positive, this method is used by public updateOpenRoadmNetworkTopology") - private void sendNotification(TopologyNotificationTypes notificationType, - Map topologyChangesMap) { - if (topologyChangesMap.isEmpty()) { - LOG.warn("Empty Topology Change map. No updates in topology"); - return; - } - TopologyUpdateResultBuilder topologyUpdateResultBuilder = new TopologyUpdateResultBuilder() - .setNotificationType(notificationType).setOrdTopologyChanges(topologyChangesMap); - this.notification = topologyUpdateResultBuilder.build(); - try { - notificationPublishService.putNotification(this.notification); - } catch (InterruptedException e) { - LOG.error("Notification offer rejected. Error={}", e.getMessage()); - } } } diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/TopologyUtils.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/TopologyUtils.java index 6fd972c31..dd3838585 100644 --- a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/TopologyUtils.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/TopologyUtils.java @@ -7,14 +7,22 @@ */ package org.opendaylight.transportpce.networkmodel.util; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.transportpce.common.NetworkUtils; import org.opendaylight.transportpce.common.network.NetworkTransactionService; +import org.opendaylight.transportpce.networkmodel.dto.TopologyShard; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1Builder; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State; import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId; @@ -22,13 +30,20 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.link.DestinationBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.link.SourceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -151,4 +166,67 @@ public final class TopologyUtils { return null; } } + + public static TopologyShard updateTopologyShard(String abstractNodeid, Mapping mapping, Map nodes, + Map links) { + // update termination-point corresponding to the mapping + List topoTps = new ArrayList<>(); + TerminationPoint tp = nodes.get(new NodeKey(new NodeId(abstractNodeid))).augmentation(Node1.class) + .getTerminationPoint().get(new TerminationPointKey(new TpId(mapping.getLogicalConnectionPoint()))); + TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder(tp.augmentation(TerminationPoint1.class)); + if (!tp1Bldr.getAdministrativeState().getName().equals(mapping.getPortAdminState())) { + tp1Bldr.setAdministrativeState(AdminStates.valueOf(mapping.getPortAdminState())); + } + if (!tp1Bldr.getOperationalState().getName().equals(mapping.getPortOperState())) { + tp1Bldr.setOperationalState(State.valueOf(mapping.getPortOperState())); + } + TerminationPointBuilder tpBldr = new TerminationPointBuilder(tp).addAugmentation(tp1Bldr.build()); + topoTps.add(tpBldr.build()); + + if (links == null) { + return new TopologyShard(null, null, topoTps); + } + String tpId = tpBldr.getTpId().getValue(); + // update links terminating on the given termination-point + List filteredTopoLinks = links.values().stream() + .filter(l1 -> (l1.getSource().getSourceNode().getValue().equals(abstractNodeid) + && l1.getSource().getSourceTp().toString().equals(tpId)) + || (l1.getDestination().getDestNode().getValue().equals(abstractNodeid) + && l1.getDestination().getDestTp().toString().equals(tpId))) + .collect(Collectors.toList()); + List topoLinks = new ArrayList<>(); + for (Link link : filteredTopoLinks) { + TerminationPoint otherLinkTp; + if (link.getSource().getSourceNode().getValue().equals(abstractNodeid)) { + otherLinkTp = nodes + .get(new NodeKey(new NodeId(link.getDestination().getDestNode().getValue()))) + .augmentation(Node1.class) + .getTerminationPoint() + .get(new TerminationPointKey(new TpId(link.getDestination().getDestTp().toString()))); + } else { + otherLinkTp = nodes + .get(new NodeKey(new NodeId(link.getSource().getSourceNode().getValue()))) + .augmentation(Node1.class) + .getTerminationPoint() + .get(new TerminationPointKey(new TpId(link.getSource().getSourceTp().toString()))); + } + Link1Builder link1Bldr = new Link1Builder(link.augmentation(Link1.class)); + if (tpBldr.augmentation(TerminationPoint1.class).getAdministrativeState().equals(AdminStates.InService) + && otherLinkTp.augmentation(TerminationPoint1.class) + .getAdministrativeState().equals(AdminStates.InService)) { + link1Bldr.setAdministrativeState(AdminStates.InService); + } else { + link1Bldr.setAdministrativeState(AdminStates.OutOfService); + } + if (tpBldr.augmentation(TerminationPoint1.class).getOperationalState().equals(State.InService) + && otherLinkTp.augmentation(TerminationPoint1.class) + .getOperationalState().equals(State.InService)) { + link1Bldr.setOperationalState(State.InService); + } else { + link1Bldr.setOperationalState(State.OutOfService); + } + topoLinks.add(new LinkBuilder(link).addAugmentation(link1Bldr.build()).build()); + } + return new TopologyShard(null, topoLinks, topoTps); + } } diff --git a/networkmodel/src/main/resources/OSGI-INF/blueprint/networkmodel-blueprint.xml b/networkmodel/src/main/resources/OSGI-INF/blueprint/networkmodel-blueprint.xml index e4e772c10..9dc2d699d 100644 --- a/networkmodel/src/main/resources/OSGI-INF/blueprint/networkmodel-blueprint.xml +++ b/networkmodel/src/main/resources/OSGI-INF/blueprint/networkmodel-blueprint.xml @@ -31,6 +31,11 @@ + + + + + diff --git a/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelProviderTest.java b/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelProviderTest.java index ce4d1fafb..2db827b4c 100644 --- a/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelProviderTest.java +++ b/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelProviderTest.java @@ -23,6 +23,7 @@ import org.opendaylight.mdsal.binding.api.NotificationService; import org.opendaylight.mdsal.binding.api.RpcProviderService; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.transportpce.common.network.NetworkTransactionService; +import org.opendaylight.transportpce.networkmodel.listeners.PortMappingListener; import org.opendaylight.transportpce.networkmodel.service.FrequenciesService; import org.opendaylight.transportpce.test.AbstractTest; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev170818.TransportpceNetworkutilsService; @@ -41,13 +42,15 @@ public class NetworkModelProviderTest extends AbstractTest { private NotificationService notificationService; @Mock private FrequenciesService frequenciesService; + @Mock + private PortMappingListener portMappingListener; @Test public void networkmodelProviderInitTest() { NetworkModelProvider provider = new NetworkModelProvider(networkTransactionService, getDataBroker(), rpcProviderService, networkutilsService, topologyListener, notificationService, - frequenciesService); + frequenciesService, portMappingListener); Answer> answer = new Answer>() { @Override -- 2.36.6