From 9926712fc5b75f5220d579cd020e1d29a3acf73e Mon Sep 17 00:00:00 2001 From: Javier Errea Date: Wed, 3 Feb 2021 16:39:30 +0100 Subject: [PATCH] TAPI Netconf Topology Listener - TAPI network model service equiv. to Network Model module - TAPI blueprint modification. - Lighty module initializes TAPI accordingly - TAPI PortMappingListener implementation - TAPI topology context population: nodes and links - TAPI sip context population - TAPI rdm2rdm link creating with LLDP JIRA: TRNSPRTPCE-385 Change-Id: I70a68c0cd6156da53cb09ec84d25f600e4d31c87 Signed-off-by: errea --- .../tpce/module/TransportPCEImpl.java | 24 +- .../networkmodel/R2RLinkDiscovery.java | 165 +- tapi/pom.xml | 8 + .../tapi/R2RTapiLinkDiscovery.java | 387 +++++ .../transportpce/tapi/impl/TapiProvider.java | 31 +- .../topology/TapiNetconfTopologyListener.java | 78 + .../topology/TapiNetworkModelService.java | 34 + .../topology/TapiNetworkModelServiceImpl.java | 1394 +++++++++++++++++ .../topology/TapiPortMappingListener.java | 59 + .../OSGI-INF/blueprint/tapi-blueprint.xml | 25 + 10 files changed, 2126 insertions(+), 79 deletions(-) create mode 100644 tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java create mode 100644 tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java create mode 100644 tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java create mode 100644 tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java create mode 100644 tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java diff --git a/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java b/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java index 05992243d..179196f19 100644 --- a/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java +++ b/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java @@ -74,7 +74,12 @@ import org.opendaylight.transportpce.servicehandler.listeners.PceListenerImpl; import org.opendaylight.transportpce.servicehandler.listeners.RendererListenerImpl; import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations; import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperationsImpl; +import org.opendaylight.transportpce.tapi.R2RTapiLinkDiscovery; import org.opendaylight.transportpce.tapi.impl.TapiProvider; +import org.opendaylight.transportpce.tapi.topology.TapiNetconfTopologyListener; +import org.opendaylight.transportpce.tapi.topology.TapiNetworkModelService; +import org.opendaylight.transportpce.tapi.topology.TapiNetworkModelServiceImpl; +import org.opendaylight.transportpce.tapi.topology.TapiPortMappingListener; import org.opendaylight.transportpce.tapi.utils.TapiListener; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev170818.TransportpceNetworkutilsService; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService; @@ -189,7 +194,17 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP serviceDataStoreOperations, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl, servicehandler); - tapiProvider = initTapi(lightyServices, servicehandler, networkTransaction, serviceDataStoreOperations); + LOG.info("Creating tapi beans ..."); + R2RTapiLinkDiscovery tapilinkDiscoveryImpl = new R2RTapiLinkDiscovery(lightyServices.getBindingDataBroker(), + deviceTransactionManager); + TapiNetworkModelService tapiNetworkModelService = new TapiNetworkModelServiceImpl( + tapilinkDiscoveryImpl, networkTransaction); + TapiNetconfTopologyListener tapiNetConfTopologyListener = + new TapiNetconfTopologyListener(tapiNetworkModelService); + TapiPortMappingListener tapiPortMappingListener = + new TapiPortMappingListener(tapiNetworkModelService); + tapiProvider = initTapi(lightyServices, servicehandler, networkTransaction, serviceDataStoreOperations, + tapiNetConfTopologyListener, tapiPortMappingListener); if(activateNbiNotification) { LOG.info("Creating nbi-notifications beans ..."); nbiNotificationsProvider = new NbiNotificationsProvider( @@ -251,9 +266,12 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP */ private TapiProvider initTapi(LightyServices lightyServices, OrgOpenroadmServiceService servicehandler, NetworkTransactionService networkTransaction, - ServiceDataStoreOperations serviceDataStoreOperations) { + ServiceDataStoreOperations serviceDataStoreOperations, + TapiNetconfTopologyListener tapiNetConfTopologyListener, + TapiPortMappingListener tapiPortMappingListener) { return new TapiProvider(lightyServices.getBindingDataBroker(), lightyServices.getRpcProviderService(), - servicehandler, serviceDataStoreOperations, new TapiListener(), networkTransaction); + servicehandler, serviceDataStoreOperations, new TapiListener(), networkTransaction, + tapiNetConfTopologyListener, tapiPortMappingListener); } /** diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java index c120a38b2..427e22b95 100644 --- a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java @@ -9,6 +9,7 @@ package org.opendaylight.transportpce.networkmodel; import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_1_2_1; import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_2_2_1; +import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_7_1_0; import java.util.Collection; import java.util.Optional; @@ -58,93 +59,107 @@ public class R2RLinkDiscovery { } public boolean readLLDP(NodeId nodeId, String nodeVersion) { - - if (nodeVersion.equals(OPENROADM_DEVICE_VERSION_1_2_1)) { - InstanceIdentifier protocolsIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + switch (nodeVersion) { + case OPENROADM_DEVICE_VERSION_1_2_1: + InstanceIdentifier protocols121IID = InstanceIdentifier.create(OrgOpenroadmDevice.class) .child(Protocols.class); - Optional protocolObject = this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), - LogicalDatastoreType.OPERATIONAL, protocolsIID, Timeouts.DEVICE_READ_TIMEOUT, - Timeouts.DEVICE_READ_TIMEOUT_UNIT); - if (!protocolObject.isPresent() || (protocolObject.get().augmentation(Protocols1.class) == null)) { - LOG.warn("LLDP subtree is missing : isolated openroadm device"); + Optional protocol121Object = this.deviceTransactionManager.getDataFromDevice( + nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT, + Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!protocol121Object.isPresent() + || (protocol121Object.get().augmentation(Protocols1.class) == null)) { + LOG.warn("LLDP subtree is missing : isolated openroadm device"); + return false; + } + // get neighbor list + NbrList nbr121List = protocol121Object.get().augmentation(Protocols1.class).getLldp().getNbrList(); + LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size()); + // try to create rdm2rdm link + return rdm2rdmLinkCreatedv121(nodeId, nbr121List); + case OPENROADM_DEVICE_VERSION_2_2_1: + InstanceIdentifier protocols221IID = + InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http + .org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice.class) + .child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019 + .org.openroadm.device.container.org.openroadm.device.Protocols.class); + Optional protocol221Object = this.deviceTransactionManager + .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!protocol221Object.isPresent() || (protocol221Object.get().augmentation( + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null)) { + LOG.warn("LLDP subtree is missing : isolated openroadm device"); + return false; + } + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList + nbr221List = protocol221Object.get().augmentation(org.opendaylight.yang.gen.v1.http + .org.openroadm.lldp.rev181019.Protocols1.class).getLldp().getNbrList(); + LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size()); + return rdm2rdmLinkCreatedv221(nodeId, nbr221List); + case OPENROADM_DEVICE_VERSION_7_1_0: + LOG.info("Not yet implemented?"); return false; - } - NbrList nbrList = protocolObject.get().augmentation(Protocols1.class).getLldp().getNbrList(); - LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size()); - boolean success = true; - for (IfName ifName : nbrList.nonnullIfName().values()) { - if (ifName.getRemoteSysName() == null) { - LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", - nodeId.getValue(),ifName.getIfName()); + default: + LOG.error("Unable to read LLDP data for unmanaged openroadm device version"); + return false; + } + } + + private boolean rdm2rdmLinkCreatedv221(NodeId nodeId, + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) { + boolean success = true; + for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName + ifName : nbrList.nonnullIfName().values()) { + if (ifName.getRemoteSysName() == null) { + LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", + nodeId.getValue(),ifName.getIfName()); + } else { + Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName + .getRemoteSysName()); + if (!mps.isPresent()) { + LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); + // The controller raises a warning rather than an error because the first node to + // mount cannot see its neighbors yet. The link will be detected when processing + // the neighbor node. } else { - Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName - .getRemoteSysName()); - if (!mps.isPresent()) { - LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); - // The controller raises a warning rather than an error because the first node to - // mount cannot see its neighbors yet. The link will be detected when processing - // the neighbor node. - } else { - if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), - ifName.getRemotePortId())) { - LOG.error("Link Creation failed between {} and {} nodes.", nodeId.getValue(), - ifName.getRemoteSysName()); - success = false; - } + if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), + ifName.getRemotePortId())) { + LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName + .getRemoteSysName()); + success = false; } } } - return success; } - else if (nodeVersion.equals(OPENROADM_DEVICE_VERSION_2_2_1)) { - InstanceIdentifier protocolsIID = InstanceIdentifier.create(org.opendaylight - .yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container - .OrgOpenroadmDevice.class).child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019 - .org.openroadm.device.container.org.openroadm.device.Protocols.class); - Optional protocolObject = this.deviceTransactionManager - .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocolsIID, - Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); - if (!protocolObject.isPresent() || (protocolObject.get().augmentation(org.opendaylight.yang.gen.v1.http.org - .openroadm.lldp.rev181019.Protocols1.class) == null)) { - LOG.warn("LLDP subtree is missing : isolated openroadm device"); - return false; - } - org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList nbrList - = protocolObject.get().augmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019 - .Protocols1.class).getLldp().getNbrList(); - LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size()); - boolean success = true; - for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName - ifName : nbrList.nonnullIfName().values()) { - if (ifName.getRemoteSysName() == null) { - LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", - nodeId.getValue(),ifName.getIfName()); + return success; + } + + private boolean rdm2rdmLinkCreatedv121(NodeId nodeId, NbrList nbrList) { + boolean success = true; + for (IfName ifName : nbrList.nonnullIfName().values()) { + if (ifName.getRemoteSysName() == null) { + LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", + nodeId.getValue(),ifName.getIfName()); + } else { + Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName + .getRemoteSysName()); + if (!mps.isPresent()) { + LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); + // The controller raises a warning rather than an error because the first node to + // mount cannot see its neighbors yet. The link will be detected when processing + // the neighbor node. } else { - Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName - .getRemoteSysName()); - if (!mps.isPresent()) { - LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); - // The controller raises a warning rather than an error because the first node to - // mount cannot see its neighbors yet. The link will be detected when processing - // the neighbor node. - } else { - if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), - ifName.getRemotePortId())) { - LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName - .getRemoteSysName()); - success = false; - } + if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), + ifName.getRemotePortId())) { + LOG.error("Link Creation failed between {} and {} nodes.", nodeId.getValue(), + ifName.getRemoteSysName()); + success = false; } } } - return success; - } - else { - LOG.error("Unable to read LLDP data for unmanaged openroadm device version"); - return false; } + return success; } public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) { diff --git a/tapi/pom.xml b/tapi/pom.xml index 478be2601..b427c9813 100644 --- a/tapi/pom.xml +++ b/tapi/pom.xml @@ -78,6 +78,14 @@ Author: Martial Coulibaly on behalf of Orange ${project.version} + + + com.google.code.findbugs + jsr305 + 3.0.2 + true + + junit diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java new file mode 100644 index 000000000..89829189a --- /dev/null +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java @@ -0,0 +1,387 @@ +/* + * Copyright © 2021 Nokia. 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.tapi; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.Network; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.cp.to.degree.CpToDegree; +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.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.NodesKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Protocols; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.Protocols1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.NbrList; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.nbr.list.IfName; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.AdministrativeState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.CapacityUnit; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ForwardingDirection; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LifecycleState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.OperationalState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.TotalSizeBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.AvailableCapacityBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.TotalPotentialCapacityBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ProtectionType; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RestorationPolicy; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.ResilienceTypeBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Link; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanism; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanismBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class R2RTapiLinkDiscovery { + + private static final Logger LOG = LoggerFactory.getLogger(R2RTapiLinkDiscovery.class); + + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + private static final String PHTNC_MEDIA = "PHOTONIC_MEDIA"; + + public R2RTapiLinkDiscovery(final DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager) { + this.dataBroker = dataBroker; + this.deviceTransactionManager = deviceTransactionManager; + } + + public Map readLLDP(NodeId nodeId, int nodeVersion, Uuid tapiTopoUuid) { + LOG.info("Tapi R2R Link Node version = {}", nodeVersion); + // TODO -> waiting for device 7.1 in network model to change this to a switch statement and include + // support for 7.1 devices + switch (nodeVersion) { + case 1: + // 1.2.1 + InstanceIdentifier protocols121IID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(Protocols.class); + Optional protocol121Object = this.deviceTransactionManager.getDataFromDevice( + nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT, + Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!protocol121Object.isPresent() + || (protocol121Object.get().augmentation(Protocols1.class) == null)) { + LOG.warn("LLDP subtree is missing : isolated openroadm device"); + return new HashMap<>(); + } + // get neighbor list + NbrList nbr121List = protocol121Object.get().augmentation(Protocols1.class).getLldp().getNbrList(); + LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size()); + // try to create rdm2rdm link + return rdm2rdmLinkCreatev121(nodeId, tapiTopoUuid, nbr121List); + case 2: + // 2.2.1 + InstanceIdentifier protocols221IID = + InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http + .org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice.class) + .child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019 + .org.openroadm.device.container.org.openroadm.device.Protocols.class); + Optional protocol221Object = this.deviceTransactionManager + .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!protocol221Object.isPresent() || (protocol221Object.get().augmentation( + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null)) { + LOG.warn("LLDP subtree is missing : isolated openroadm device"); + return new HashMap<>(); + } + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList + nbr221List = protocol221Object.get().augmentation(org.opendaylight.yang.gen.v1.http + .org.openroadm.lldp.rev181019.Protocols1.class).getLldp().getNbrList(); + LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size()); + return rdm2rdmLinkCreatev221(nodeId, tapiTopoUuid, nbr221List); + case 3: + // 7.1.0 + LOG.info("Not yet supported?"); + return new HashMap<>(); + default: + LOG.error("Unable to read LLDP data for unmanaged openroadm device version"); + return new HashMap<>(); + } + } + + private Map rdm2rdmLinkCreatev221(NodeId nodeId, Uuid tapiTopoUuid, + org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) { + Map linkMap = new HashMap<>(); + for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName + ifName : nbrList.nonnullIfName().values()) { + if (ifName.getRemoteSysName() == null) { + LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", + nodeId.getValue(),ifName.getIfName()); + continue; + } + Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName()); + if (!mps.isPresent()) { + LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); + // The controller raises a warning rather than an error because the first node to + // mount cannot see its neighbors yet. The link will be detected when processing + // the neighbor node. + continue; + } + Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), + ifName.getRemotePortId(), tapiTopoUuid); + if (omsLink != null) { + linkMap.put(omsLink.key(), omsLink); + } + } + return linkMap; + } + + private Map rdm2rdmLinkCreatev121(NodeId nodeId, Uuid tapiTopoUuid, NbrList nbrList) { + Map linkMap = new HashMap<>(); + for (IfName ifName : nbrList.nonnullIfName().values()) { + if (ifName.getRemoteSysName() == null) { + LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}", + nodeId.getValue(),ifName.getIfName()); + continue; + } + Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName + .getRemoteSysName()); + if (!mps.isPresent()) { + LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); + // The controller raises a warning rather than an error because the first node to + // mount cannot see its neighbors yet. The link will be detected when processing + // the neighbor node. + continue; + } + Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), + ifName.getRemotePortId(), tapiTopoUuid); + if (omsLink != null) { + linkMap.put(omsLink.key(), omsLink); + } + } + return linkMap; + } + + public Link createR2RTapiLink(NodeId nodeId, String interfaceName, String remoteSystemName, + String remoteInterfaceName, Uuid tapiTopoUuid) { + String srcTpTx = null; + String srcTpRx = null; + String destTpTx = null; + String destTpRx = null; + // Find which degree is associated with ethernet interface + Integer srcDegId = getDegFromInterface(nodeId, interfaceName); + if (srcDegId == null) { + LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return null; + } + // Check whether degree is Unidirectional or Bidirectional by counting + // number of + // circuit-packs under degree subtree + Direction sourceDirection = getDegreeDirection(srcDegId, nodeId); + if (Direction.NotApplicable == sourceDirection) { + LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId); + return null; + } else if (Direction.Bidirectional == sourceDirection) { + srcTpTx = "DEG" + srcDegId + "-TTP-TXRX"; + srcTpRx = "DEG" + srcDegId + "-TTP-TXRX"; + } else { + srcTpTx = "DEG" + srcDegId + "-TTP-TX"; + srcTpRx = "DEG" + srcDegId + "-TTP-RX"; + } + LOG.debug("Tapi R2R Link SrcTPTx {}, SrcTPRx {}", srcTpTx, srcTpRx); + // Find degree for which Ethernet interface is created on other end + NodeId destNodeId = new NodeId(remoteSystemName); + Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName); + if (destDegId == null) { + LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return null; + } + // Check whether degree is Unidirectional or Bidirectional by counting + // number of + // circuit-packs under degree subtree + Direction destinationDirection = getDegreeDirection(destDegId, destNodeId); + if (Direction.NotApplicable == destinationDirection) { + LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}", + destNodeId, destDegId); + return null; + } else if (Direction.Bidirectional == destinationDirection) { + destTpTx = "DEG" + destDegId + "-TTP-TXRX"; + destTpRx = "DEG" + destDegId + "-TTP-TXRX"; + } else { + destTpTx = "DEG" + destDegId + "-TTP-TX"; + destTpRx = "DEG" + destDegId + "-TTP-RX"; + } + // Todo -> only handling for the bidirectional case. I assume all tps are of the type bidirectional + LOG.debug("Tapi R2R Link DstTPTx {}, DstTPRx {}", destTpTx, srcTpRx); + // Create OMS Tapi Link + LOG.info("Tapi R2R Link Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , " + + "DestDegId: {}, DestTPId: {}", nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx); + Link omsLink = createTapiLink(nodeId.getValue(), srcTpTx, destNodeId.getValue(), destTpRx, tapiTopoUuid); + LOG.info("Tapi R2R Link OMS link created = {}", omsLink); + return omsLink; + } + + private Link createTapiLink(String sourceNode, String sourceTp, String destNode, String destTp, Uuid tapiTopoUuid) { + Map nepList = new HashMap<>(); + Uuid sourceUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode, + PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString()); + Uuid sourceUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode, PHTNC_MEDIA, sourceTp)) + .getBytes(Charset.forName("UTF-8"))).toString()); + Uuid destUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode, + PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString()); + Uuid destUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode, PHTNC_MEDIA, destTp)) + .getBytes(Charset.forName("UTF-8"))).toString()); + NodeEdgePoint sourceNep = new NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(sourceUuidNode) + .setNodeEdgePointUuid(sourceUuidTp) + .build(); + nepList.put(sourceNep.key(), sourceNep); + NodeEdgePoint destNep = new NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(destUuidNode) + .setNodeEdgePointUuid(destUuidTp) + .build(); + nepList.put(destNep.key(), destNep); + String linkNameValue = String.join("-", sourceNode, sourceTp.split("-")[0], sourceTp) + + "to" + String.join("-", destNode, destTp.split("-")[0], destTp); + Name linkName = new NameBuilder().setValueName("OMS link name") + .setValue(linkNameValue) + .build(); + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder() + .setRiskCharacteristicName("risk characteristic") + .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2")) + .build(); + ValidationMechanism validationMechanism = new ValidationMechanismBuilder() + .setValidationMechanism("validation mechanism") + .setValidationRobustness("validation robustness") + .setLayerProtocolAdjacencyValidated("layer protocol adjacency") + .build(); + return new LinkBuilder() + .setUuid(new Uuid( + UUID.nameUUIDFromBytes(linkNameValue.getBytes(Charset.forName("UTF-8"))) + .toString())) + .setName(Map.of(linkName.key(), linkName)) + .setLayerProtocolName(List.of(LayerProtocolName.PHOTONICMEDIA)) + .setTransitionedLayerProtocolName(new ArrayList<>()) + .setNodeEdgePoint(nepList) + .setDirection(ForwardingDirection.BIDIRECTIONAL) + .setResilienceType(new ResilienceTypeBuilder().setProtectionType(ProtectionType.NOPROTECTON) + .setRestorationPolicy(RestorationPolicy.NA) + .build()) + .setAdministrativeState(AdministrativeState.UNLOCKED) + .setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED) + .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().setTotalSize( + new TotalSizeBuilder().setUnit(CapacityUnit.GBPS) + .setValue(Uint64.valueOf(100)).build()).build()) + .setAvailableCapacity(new AvailableCapacityBuilder().setTotalSize( + new TotalSizeBuilder().setUnit(CapacityUnit.MBPS) + .setValue(Uint64.valueOf(100)).build()) + .build()) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic)) + .setErrorCharacteristic("error") + .setLossCharacteristic("loss") + .setRepeatDeliveryCharacteristic("repeat delivery") + .setDeliveryOrderCharacteristic("delivery order") + .setUnavailableTimeCharacteristic("unavailable time") + .setServerIntegrityProcessCharacteristic("server integrity process") + .setValidationMechanism(Map.of(validationMechanism.key(), validationMechanism)) + .build(); + } + + private Integer getDegFromInterface(NodeId nodeId, String interfaceName) { + InstanceIdentifier nodesIID = InstanceIdentifier.builder(Network.class) + .child(Nodes.class, new NodesKey(nodeId.getValue())).build(); + try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) { + Optional nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get(); + if (nodesObject.isEmpty() || (nodesObject.get().getCpToDegree() == null)) { + LOG.warn("Could not find mapping for Interface {} for nodeId {}", interfaceName, + nodeId.getValue()); + return null; + } + Collection cpToDeg = nodesObject.get().nonnullCpToDegree().values(); + Stream cpToDegStream = cpToDeg.stream().filter(cp -> cp.getInterfaceName() != null) + .filter(cp -> cp.getInterfaceName().equals(interfaceName)); + if (cpToDegStream != null) { + @SuppressWarnings("unchecked") Optional firstCpToDegree = cpToDegStream.findFirst(); + if (firstCpToDegree.isEmpty() || (firstCpToDegree == null)) { + LOG.debug("Not found so returning nothing"); + return null; + } + LOG.debug("Found and returning {}",firstCpToDegree.get().getDegreeNumber().intValue()); + return firstCpToDegree.get().getDegreeNumber().intValue(); + } else { + LOG.warn("CircuitPack stream couldnt find anything for nodeId: {} and interfaceName: {}", + nodeId.getValue(),interfaceName); + } + } catch (InterruptedException | ExecutionException ex) { + LOG.error("Unable to read mapping for Interface : {} for nodeId {}", interfaceName, nodeId, ex); + } + return null; + } + + public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) { + InstanceIdentifier nodesIID = InstanceIdentifier.builder(Network.class) + .child(Nodes.class, new NodesKey(nodeId.getValue())).build(); + try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) { + Optional nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get(); + if (nodesObject.isPresent() && (nodesObject.get().getMapping() != null)) { + Collection mappingList = nodesObject.get().nonnullMapping().values(); + mappingList = mappingList.stream().filter(mp -> mp.getLogicalConnectionPoint().contains("DEG" + + degreeCounter)).collect(Collectors.toList()); + if (mappingList.size() == 1) { + return Direction.Bidirectional; + } else if (mappingList.size() > 1) { + return Direction.Tx; + } + } + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed getting Mapping data from portMapping",e); + } + return Direction.NotApplicable; + } +} diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/impl/TapiProvider.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/impl/TapiProvider.java index 68c9f0236..7beb695cb 100644 --- a/tapi/src/main/java/org/opendaylight/transportpce/tapi/impl/TapiProvider.java +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/impl/TapiProvider.java @@ -13,19 +13,26 @@ import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; import org.opendaylight.mdsal.binding.api.RpcProviderService; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.transportpce.common.InstanceIdentifiers; import org.opendaylight.transportpce.common.network.NetworkTransactionService; import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations; import org.opendaylight.transportpce.tapi.connectivity.ConnectivityUtils; import org.opendaylight.transportpce.tapi.connectivity.TapiConnectivityImpl; +import org.opendaylight.transportpce.tapi.topology.TapiNetconfTopologyListener; +import org.opendaylight.transportpce.tapi.topology.TapiPortMappingListener; import org.opendaylight.transportpce.tapi.topology.TapiTopologyImpl; import org.opendaylight.transportpce.tapi.topology.TopologyUtils; import org.opendaylight.transportpce.tapi.utils.TapiContext; import org.opendaylight.transportpce.tapi.utils.TapiInitialORMapping; import org.opendaylight.transportpce.tapi.utils.TapiListener; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.Network; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes; import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.OrgOpenroadmServiceService; import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.TapiConnectivityService; import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.TapiTopologyService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.tapi.rev180928.ServiceInterfacePoints; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; @@ -41,23 +48,33 @@ public class TapiProvider { private static final Logger LOG = LoggerFactory.getLogger(TapiProvider.class); + private static final InstanceIdentifier MAPPING_II = InstanceIdentifier.create(Network.class) + .child(org.opendaylight.yang.gen.v1.http + .org.opendaylight.transportpce.portmapping.rev210315.network.Nodes.class); private final DataBroker dataBroker; private final RpcProviderService rpcProviderService; private ObjectRegistration rpcRegistration; + private ListenerRegistration dataTreeChangeListenerRegistration; + private ListenerRegistration mappingListenerListenerRegistration; private final OrgOpenroadmServiceService serviceHandler; private final ServiceDataStoreOperations serviceDataStoreOperations; private final TapiListener tapiListener; + private final TapiNetconfTopologyListener topologyListener; + private TapiPortMappingListener tapiPortMappingListener; private final NetworkTransactionService networkTransactionService; public TapiProvider(DataBroker dataBroker, RpcProviderService rpcProviderService, OrgOpenroadmServiceService serviceHandler, ServiceDataStoreOperations serviceDataStoreOperations, - TapiListener tapiListener, NetworkTransactionService networkTransactionService) { + TapiListener tapiListener, NetworkTransactionService networkTransactionService, + TapiNetconfTopologyListener topologyListener, TapiPortMappingListener tapiPortMappingListener) { this.dataBroker = dataBroker; this.rpcProviderService = rpcProviderService; this.serviceHandler = serviceHandler; this.serviceDataStoreOperations = serviceDataStoreOperations; this.tapiListener = tapiListener; this.networkTransactionService = networkTransactionService; + this.topologyListener = topologyListener; + this.tapiPortMappingListener = tapiPortMappingListener; } /** @@ -80,6 +97,12 @@ public class TapiProvider { TapiTopologyImpl topo = new TapiTopologyImpl(this.dataBroker, tapiContext, topologyUtils); rpcRegistration = rpcProviderService.registerRpcImplementation(TapiConnectivityService.class, tapi); rpcProviderService.registerRpcImplementation(TapiTopologyService.class, topo); + dataTreeChangeListenerRegistration = + dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, + InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), topologyListener); + mappingListenerListenerRegistration = + dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, + MAPPING_II), tapiPortMappingListener); @NonNull InstanceIdentifier sipIID = InstanceIdentifier.create(ServiceInterfacePoints.class); dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create( @@ -91,6 +114,12 @@ public class TapiProvider { */ public void close() { LOG.info("TapiProvider Session Closed"); + if (dataTreeChangeListenerRegistration != null) { + dataTreeChangeListenerRegistration.close(); + } + if (mappingListenerListenerRegistration != null) { + mappingListenerListenerRegistration.close(); + } rpcRegistration.close(); } } diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java new file mode 100644 index 000000000..85c3e0a4d --- /dev/null +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2021 Nokia, Inc. and others. 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.tapi.topology; + +import java.util.Collection; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.mdsal.binding.api.DataObjectModification; +import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataTreeModification; +import org.opendaylight.transportpce.common.StringConstants; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapiNetconfTopologyListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(TapiNetconfTopologyListener.class); + private final TapiNetworkModelService tapiNetworkModelService; + + public TapiNetconfTopologyListener(final TapiNetworkModelService tapiNetworkModelService) { + this.tapiNetworkModelService = tapiNetworkModelService; + } + + public void onDataTreeChanged(@Nonnull Collection> changes) { + LOG.info("onDataTreeChanged - {}", this.getClass().getSimpleName()); + for (DataTreeModification change : changes) { + DataObjectModification rootNode = change.getRootNode(); + if (rootNode.getDataBefore() == null) { + continue; + } + String nodeId = rootNode.getDataBefore().key().getNodeId().getValue(); + NetconfNode netconfNodeBefore = rootNode.getDataBefore().augmentation(NetconfNode.class); + switch (rootNode.getModificationType()) { + case DELETE: + this.tapiNetworkModelService.deleteTapinode(nodeId); + // TODO -> unregistration to NETCONF stream not yet supported + // onDeviceDisConnected(nodeId); + LOG.info("Device {} correctly disconnected from controller", nodeId); + break; + case WRITE: + NetconfNode netconfNodeAfter = rootNode.getDataAfter().augmentation(NetconfNode.class); + if (ConnectionStatus.Connecting.equals(netconfNodeBefore.getConnectionStatus()) + && ConnectionStatus.Connected.equals(netconfNodeAfter.getConnectionStatus())) { + LOG.info("Connecting Node: {}", nodeId); + Optional deviceCapabilityOpt = netconfNodeAfter + .getAvailableCapabilities().getAvailableCapability().stream() + .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME)) + .sorted((c1, c2) -> c2.getCapability().compareTo(c1.getCapability())) + .findFirst(); + if (deviceCapabilityOpt.isEmpty()) { + LOG.error("Unable to get openroadm-device-capability"); + return; + } + // TODO -> subscription to NETCONF stream not yet supported... no listeners implementation + // onDeviceConnected(nodeId,deviceCapabilityOpt.get().getCapability()); + LOG.info("Device {} waiting for portmapping to be populated", nodeId); + } + if (ConnectionStatus.Connected.equals(netconfNodeBefore.getConnectionStatus()) + && ConnectionStatus.Connecting.equals(netconfNodeAfter.getConnectionStatus())) { + LOG.warn("Node: {} is being disconnected", nodeId); + } + break; + default: + LOG.debug("Unknown modification type {}", rootNode.getModificationType().name()); + break; + } + } + } +} diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java new file mode 100644 index 000000000..85df6053c --- /dev/null +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2021 Nokia, Inc. and others. 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.tapi.topology; + +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes; + +public interface TapiNetworkModelService { + + /** + * Create new TAPI node in tapi topologies. + * + * @param orNodeId + * unique node ID of new OpenROADM node + * @param orNodeVersion + * OpenROADM node version + * @param node + * OpenRoadm node + */ + void createTapiNode(String orNodeId, int orNodeVersion, Nodes node); + + /** + * Delete TAPI node in topologies and update corresponding TAPI context objects. + * + * @param nodeId + * unique node ID of OpenROADM node. + * + */ + void deleteTapinode(String nodeId); +} diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java new file mode 100644 index 000000000..863103c33 --- /dev/null +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java @@ -0,0 +1,1394 @@ +/* + * Copyright © 2021 Nokia, Inc. and others. 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.tapi.topology; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.transportpce.common.network.NetworkTransactionService; +import org.opendaylight.transportpce.tapi.R2RTapiLinkDiscovery; +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.yang.gen.v1.http.org.openroadm.common.types.rev181019.NodeTypes; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.XpdrNodeTypes; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.OduSwitchingPools; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.OduSwitchingPoolsBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingList; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingListBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingListKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.OpenroadmNodeType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapability; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If100GE; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If100GEODU4; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GE; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GEODU2; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GEODU2e; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If1GE; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If1GEODU0; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.IfOCH; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.IfOCHOTU4ODU4; +import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.SupportedIfCapability; +import org.opendaylight.yang.gen.v1.http.org.openroadm.switching.pool.types.rev191129.SwitchingPoolTypes; +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.topology.rev180226.TpId; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.AdministrativeState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.CapacityUnit; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Context; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ContextBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ForwardingDirection; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LAYERPROTOCOLQUALIFIER; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LifecycleState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.OperationalState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.PortDirection; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.PortRole; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.TerminationDirection; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.TerminationState; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.TotalSizeBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.AvailableCapacityBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.TotalPotentialCapacityBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePointBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.Connection; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityService; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityServiceBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityServiceKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.EndPoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.EndPointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.dsr.rev181210.DIGITALSIGNALTYPE100GigE; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.dsr.rev181210.DIGITALSIGNALTYPE10GigELAN; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU2; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU2E; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU4; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.photonic.media.rev181210.PHOTONICLAYERQUALIFIEROMS; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.photonic.media.rev181210.PHOTONICLAYERQUALIFIEROTSi; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ForwardingRule; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ProtectionType; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RestorationPolicy; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RuleType; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.ResilienceTypeBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroup; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroupBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroupKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePointBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePoint; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePointBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePointKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.Rule; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.RuleBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.RuleKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Link; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.NodeKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.Topology; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristic; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristicBuilder; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanism; +import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanismBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint16; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapiNetworkModelServiceImpl implements TapiNetworkModelService { + + private static final Logger LOG = LoggerFactory.getLogger(TapiNetworkModelServiceImpl.class); + private static final String DSR = "DSR"; + private static final String I_ODU = "iODU"; + private static final String E_ODU = "eODU"; + private static final String OTSI = "OTSi"; + private static final String E_OTSI = "eOTSi"; + private static final String I_OTSI = "iOTSi"; + private static final String PHTNC_MEDIA = "PHOTONIC_MEDIA"; + private static final String MC = "MEDIA_CHANNEL"; + private static final String OTSI_MC = "OTSi_MEDIA_CHANNEL"; + private static final String CLIENT = "-CLIENT"; + private static final String NETWORK = "-NETWORK"; + private static final String XPDR = "-XPDR"; + private final Uuid tapiTopoUuid = new Uuid(UUID.nameUUIDFromBytes(TopologyUtils.T0_FULL_MULTILAYER + .getBytes(Charset.forName("UTF-8"))).toString()); + private final NetworkTransactionService networkTransactionService; + private Map sipMap; + private final R2RTapiLinkDiscovery linkDiscovery; + + public TapiNetworkModelServiceImpl(final R2RTapiLinkDiscovery linkDiscovery, + NetworkTransactionService networkTransactionService) { + this.networkTransactionService = networkTransactionService; + this.sipMap = new HashMap<>(); + this.linkDiscovery = linkDiscovery; + } + + @Override + public void createTapiNode(String orNodeId, int orNodeVersion, Nodes node) { + // TODO -> Implementation with PortMappingListener + // check if port mapping exists or not... + if (node.getMapping() == null) { + LOG.warn("Could not generate port mapping for {} skipping network model creation", orNodeId); + return; + } + this.sipMap.clear(); + LOG.info("Mapping of node {}: {}", orNodeId, node.getMapping().values()); + + // check type of device, check version and create node mapping + if (NodeTypes.Rdm.getIntValue() == node.getNodeInfo().getNodeType().getIntValue()) { + // ROADM device + // transform flat mapping list to per degree and per srg mapping lists + Map> mapDeg = new HashMap<>(); + Map> mapSrg = new HashMap<>(); + List mappingList = new ArrayList<>(node.nonnullMapping().values()); + mappingList.sort(Comparator.comparing(Mapping::getLogicalConnectionPoint)); + + List nodeShardList = getRoadmNodelist(mappingList); + + // populate degree and srg LCP map + for (String str : nodeShardList) { + List interList = mappingList.stream().filter(x -> x.getLogicalConnectionPoint().contains(str)) + .collect(Collectors.toList()); + if (str.contains("DEG")) { + mapDeg.put(str, interList); + } else if (str.contains("SRG")) { + mapSrg.put(str, interList); + } else { + LOG.error("unknown element"); + } + } + // Transform LCPs into ONEP + Map onepMap = + new HashMap<>(transformDegToOnep(orNodeId, mapDeg)); + onepMap.putAll(transformSrgToOnep(orNodeId, mapSrg)); + + // create tapi Node + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node roadmNode = + createRoadmTapiNode(orNodeId, onepMap); + // TODO add states corresponding to device config -> based on mapping. + // This should be possible after Gilles work is merged + + // rdm to rdm link creation if neighbour roadm is mounted + LOG.info("checking if neighbor roadm exists"); + Map rdm2rdmLinks = this.linkDiscovery.readLLDP(new NodeId(orNodeId), orNodeVersion, + this.tapiTopoUuid); + mergeNodeinTopology(Map.of(roadmNode.key(), roadmNode)); + mergeSipsinContext(this.sipMap); + if (!rdm2rdmLinks.isEmpty()) { + mergeLinkinTopology(rdm2rdmLinks); + } + + } else if (NodeTypes.Xpdr.getIntValue() == node.getNodeInfo().getNodeType().getIntValue()) { + List networkMappings = node.nonnullMapping().values() + .stream().filter(k -> k.getLogicalConnectionPoint() + .contains("NETWORK")).collect(Collectors.toList()); + Map xpdrMap = new HashMap<>(); + for (Mapping mapping : networkMappings) { + Integer xpdrNb = Integer.parseInt(mapping.getLogicalConnectionPoint().split("XPDR")[1].split("-")[0]); + String nodeId = node.getNodeId() + XPDR + xpdrNb; + if (!xpdrMap.containsKey(xpdrNb)) { + List xpdrNetMaps = node.nonnullMapping().values() + .stream().filter(k -> k.getLogicalConnectionPoint() + .contains("XPDR" + xpdrNb + NETWORK)).collect(Collectors.toList()); + List xpdrClMaps = node.nonnullMapping().values() + .stream().filter(k -> k.getLogicalConnectionPoint() + .contains("XPDR" + xpdrNb + CLIENT)).collect(Collectors.toList()); + xpdrMap.put(xpdrNb, node.getNodeId()); + + // create switching pool + OduSwitchingPools oorOduSwitchingPool = createSwitchPoolForXpdr( + mapping.getXponderType().getIntValue(), xpdrClMaps, xpdrNetMaps, xpdrNb); + + // node transformation + Map nodeMap = new HashMap<>(transformXpdrToTapiNode( + nodeId, xpdrClMaps, xpdrNetMaps, mapping.getXponderType(), oorOduSwitchingPool, + mapping.getSupportedInterfaceCapability())); + + // add nodes and sips to tapi context + mergeNodeinTopology(nodeMap); + mergeSipsinContext(this.sipMap); + } + } + } + // Device not managed yet + } + + private Map transformXpdrToTapiNode(String nodeId, List xpdrClMaps, + List xpdrNetMaps, XpdrNodeTypes xponderType, + OduSwitchingPools oorOduSwitchingPool, + List> + supportedInterfaceCapability) { + Map nodeMap = new HashMap<>(); + LOG.info("creation of a DSR/ODU node for {}", nodeId); + Uuid nodeUuidDsr = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, DSR)) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name nameDsr = new NameBuilder().setValueName("dsr/odu node name").setValue( + String.join("+", nodeId, DSR)).build(); + List dsrLayerProtocols = Arrays.asList(LayerProtocolName.DSR, + LayerProtocolName.ODU); + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology + .Node dsrNode = createTapiXpdrNode(Map.of(nameDsr.key(), nameDsr), dsrLayerProtocols, + nodeId, nodeUuidDsr, xpdrClMaps, xpdrNetMaps, xponderType, oorOduSwitchingPool, + supportedInterfaceCapability); + + nodeMap.put(dsrNode.key(), dsrNode); + + // node creation [otsi] + LOG.info("creation of an OTSi node for {}", nodeId); + Uuid nodeUuidOtsi = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, OTSI)) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name nameOtsi = new NameBuilder().setValueName("otsi node name").setValue( + String.join("+", nodeId, OTSI)).build(); + List otsiLayerProtocols = Arrays.asList(LayerProtocolName.PHOTONICMEDIA); + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology + .Node otsiNode = createTapiXpdrNode(Map.of(nameOtsi.key(), nameOtsi), otsiLayerProtocols, + nodeId, nodeUuidOtsi, xpdrClMaps, xpdrNetMaps, xponderType, null, + supportedInterfaceCapability); + + nodeMap.put(otsiNode.key(), otsiNode); + + // transitional link cration between network nep of DSR/ODU node and iNep of otsi node + LOG.info("creation of transitional links between DSR/ODU and OTSi nodes"); + Map linkMap = createTapiTransitionalLinks(nodeId, xpdrNetMaps, nodeUuidDsr, + nodeUuidOtsi); + mergeLinkinTopology(linkMap); + + return nodeMap; + } + + private OduSwitchingPools createSwitchPoolForXpdr(int xpdrType, List xpdrClMaps, List xpdrNetMaps, + Integer xpdrNb) { + // todo: are switching pool correct here?? + switch (xpdrType) { + case 1: + // Tpdr + return createTpdrSwitchPool(); + case 2: + // Mux + return createMuxSwitchPool(xpdrClMaps, xpdrNetMaps, xpdrNb); + case 3: + // Switch + return createSwtchSwitchPool(xpdrClMaps, xpdrNetMaps, xpdrNb); + default: + LOG.warn("Xpdr type {} not supported", xpdrType); + } + return null; + } + + private Map transformSrgToOnep(String orNodeId, + Map> mapSrg) { + Map onepMap = new HashMap<>(); + for (Map.Entry> entry : mapSrg.entrySet()) { + // For each srg node. Loop through the LCPs and create neps and sips for PP + for (Mapping m:entry.getValue()) { + if (!m.getLogicalConnectionPoint().contains("PP")) { + LOG.info("LCP {} is not an external TP of SRG node", m.getLogicalConnectionPoint()); + continue; + } + Map srgNeps = + createRoadmNeps(orNodeId, m.getLogicalConnectionPoint(), true); + onepMap.putAll(srgNeps); + } + } + return onepMap; + } + + private Map transformDegToOnep(String orNodeId, + Map> mapDeg) { + Map onepMap = new HashMap<>(); + for (Map.Entry> entry : mapDeg.entrySet()) { + // For each degree node. Loop through the LCPs and create neps and sips for TTP + for (Mapping m:entry.getValue()) { + if (!m.getLogicalConnectionPoint().contains("TTP")) { + LOG.info("LCP {} is not an external TP of DEGREE node", m.getLogicalConnectionPoint()); + continue; + } + Map degNeps = + createRoadmNeps(orNodeId, m.getLogicalConnectionPoint(), false); + onepMap.putAll(degNeps); + } + } + return onepMap; + } + + private List getRoadmNodelist(List mappingList) { + List nodeShardList = new ArrayList<>(); + for (Mapping mapping : mappingList) { + // TODO -> maybe we need to check the id based on the version + String str = mapping.getLogicalConnectionPoint().split("-")[0]; + LOG.info("LCP = {}", str); + if (!nodeShardList.contains(str)) { + nodeShardList.add(str); + } + } + return nodeShardList; + } + + @Override + public void deleteTapinode(String nodeId) { + // TODO: check for null objects + // Check if it is ROADM or XPDR --> create the uuids of the node and delete from topology the node. + // This will delete NEPs. Then check for links that have this node and delete them. + // Then check SIPs and delete them. Then services and connections with SIPs and put them to another state. + LOG.info("Deleting node {} from TAPI topology", nodeId); + InstanceIdentifier topologyIID = InstanceIdentifier.builder(Context.class) + .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class, + new TopologyKey(tapiTopoUuid)).build(); + Topology topology = null; + try { + Optional optTopology = + this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, topologyIID).get(); + if (!optTopology.isPresent()) { + LOG.error("No topology object present. Error deleting node {}", nodeId); + return; + } + topology = optTopology.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Couldnt read tapi topology from datastore", e); + } + if (topology == null) { + LOG.error("Topology is null, nothing to delete"); + return; + } + if (topology.getNode() == null) { + LOG.error("No nodes in topology"); + return; + } + if (nodeId.contains("ROADM")) { + // Node is in photonic media layer and UUID can be built from nodeId + PHTN_MEDIA + Uuid nodeUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, PHTNC_MEDIA)) + .getBytes(Charset.forName("UTF-8"))).toString()); + deleteNodeFromTopo(nodeUuid); + } + if (nodeId.contains("XPDR") || nodeId.contains("SPDR") || nodeId.contains("MXPDR")) { + // Node is either XPDR, MXPDR or SPDR. Retrieve nodes from topology and check names + for (Node tapiNode:topology.getNode().values()) { + if (tapiNode.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) { + // Found node we need to delete + deleteNodeFromTopo(tapiNode.getUuid()); + } + } + } + // Delete links of topology + Map linkMap = topology.getLink(); + if (linkMap != null) { + for (Link link:linkMap.values()) { + if (link.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) { + deleteLinkFromTopo(link.getUuid()); + } + } + } + // Delete sips of sip map + InstanceIdentifier contextIID = InstanceIdentifier.builder(Context.class).build(); + Context context = null; + try { + Optional optContext = this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, + contextIID).get(); + if (!optContext.isPresent()) { + LOG.error("No context object present in datastore."); + return; + } + context = optContext.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Couldnt read tapi context from datastore", e); + } + if (context == null) { + LOG.error("Context is null, nothing to delete"); + return; + } + Map sips = context.getServiceInterfacePoint(); + if (sips != null) { + for (ServiceInterfacePoint sip:sips.values()) { + if (sip.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) { + // Update state of services that have this sip as an endpoint and also connections + updateConnectivityServicesState(sip.getUuid(), nodeId); + deleteSipFromTopo(sip.getUuid()); + } + } + } + } + + private Node createTapiXpdrNode(Map nameMap, List layerProtocols, + String nodeId, Uuid nodeUuid, List xpdrClMaps, List xpdrNetMaps, + XpdrNodeTypes xponderType, OduSwitchingPools oorOduSwitchingPool, + List> supportedInterfaceCapability) { + Map onepl = new HashMap<>(); + Map nodeRuleGroupList = new HashMap<>(); + Map ruleList = new HashMap<>(); + Rule rule = new RuleBuilder() + .setLocalId("forward") + .setForwardingRule(ForwardingRule.MAYFORWARDACROSSGROUP) + .setRuleType(RuleType.FORWARDING) + .build(); + ruleList.put(rule.key(), rule); + if (layerProtocols.contains(LayerProtocolName.DSR)) { + // neps for dsr/odu layer + Map dsroduNeps = + createXpdrDsrOduNeps(nodeId, xpdrClMaps, xpdrNetMaps, xponderType, supportedInterfaceCapability); + onepl.putAll(dsroduNeps); + nodeRuleGroupList = createNodeRuleGroupForDsrNode(nodeId, oorOduSwitchingPool, ruleList, onepl); + } else if (layerProtocols.contains(LayerProtocolName.PHOTONICMEDIA)) { + // neps for photonic layer + Map phtmdNeps = + createXpdrPhtnMdNeps(nodeId, xpdrNetMaps, supportedInterfaceCapability); + onepl.putAll(phtmdNeps); + nodeRuleGroupList = createNodeRuleGroupForOtsiNode(nodeId, xpdrNetMaps, ruleList); + } else { + LOG.error("Undefined LayerProtocolName for {} node {}", nameMap.get(nameMap.keySet().iterator().next()) + .getValueName(), nameMap.get(nameMap.keySet().iterator().next()).getValue()); + } + // Empty random creation of mandatory fields for avoiding errors.... + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + return new NodeBuilder() + .setUuid(nodeUuid) + .setName(nameMap) + .setLayerProtocolName(layerProtocols) + .setAdministrativeState(AdministrativeState.UNLOCKED) + .setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED) + .setOwnedNodeEdgePoint(onepl) + .setNodeRuleGroup(nodeRuleGroupList) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .setErrorCharacteristic("error") + .setLossCharacteristic("loss") + .setRepeatDeliveryCharacteristic("repeat delivery") + .setDeliveryOrderCharacteristic("delivery order") + .setUnavailableTimeCharacteristic("unavailable time") + .setServerIntegrityProcessCharacteristic("server integrity process") + .build(); + } + + private Map createXpdrPhtnMdNeps(String nodeId, + List xpdrNetMaps, List> supportedInterfaceCapability) { + Map onepl = new HashMap<>(); + + // iNep creation on otsi node + for (int i = 0; i < xpdrNetMaps.size(); i++) { + Uuid nepUuid1 = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, I_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))) + .toString()); + Name onedName = new NameBuilder() + .setValueName("iNodeEdgePoint") + .setValue(String.join("+", nodeId, I_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .build(); + + OwnedNodeEdgePoint onep = createNep(nepUuid1, xpdrNetMaps.get(i).getLogicalConnectionPoint(), + Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA, + true, String.join("+", nodeId, I_OTSI), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + // eNep creation on otsi node + for (int i = 0; i < xpdrNetMaps.size(); i++) { + Uuid nepUuid2 = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, E_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name onedName = new NameBuilder() + .setValueName("eNodeEdgePoint") + .setValue(String.join("+", nodeId, E_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .build(); + + OwnedNodeEdgePoint onep = createNep(nepUuid2, xpdrNetMaps.get(i).getLogicalConnectionPoint(), + Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA, + false, String.join("+", nodeId, E_OTSI), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + // Photonic Media Nep creation on otsi node + for (int i = 0; i < xpdrNetMaps.size(); i++) { + Uuid nepUuid3 = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, PHTNC_MEDIA, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name onedName = new NameBuilder() + .setValueName("PhotMedNodeEdgePoint") + .setValue(String.join("+", nodeId, PHTNC_MEDIA, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .build(); + + OwnedNodeEdgePoint onep = createNep(nepUuid3, xpdrNetMaps.get(i).getLogicalConnectionPoint(), + Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA, + false, String.join("+", nodeId, PHTNC_MEDIA), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + return onepl; + } + + private Map createXpdrDsrOduNeps(String nodeId, List xpdrClMaps, + List xpdrNetMaps, XpdrNodeTypes xponderType, + List> supportedInterfaceCapability) { + Map onepl = new HashMap<>(); + // client nep creation on DSR node + for (int i = 0; i < xpdrClMaps.size(); i++) { + LOG.info("Client NEP = {}", String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint())); + Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + NameBuilder nameBldr = new NameBuilder().setValue( + String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint())); + Name name; + if (OpenroadmNodeType.TPDR.getName().equalsIgnoreCase(xponderType.getName())) { + name = nameBldr.setValueName("100G-tpdr").build(); + } else { + name = nameBldr.setValueName("NodeEdgePoint_C").build(); + } + + OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrClMaps.get(i).getLogicalConnectionPoint(), + Map.of(name.key(), name), LayerProtocolName.DSR, LayerProtocolName.DSR, true, + String.join("+", nodeId, DSR), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + // network nep creation on I_ODU node + for (int i = 0; i < xpdrNetMaps.size(); i++) { + LOG.info("iODU NEP = {}", String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())); + Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name onedName = new NameBuilder() + .setValueName("iNodeEdgePoint_N") + .setValue(String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .build(); + + OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrNetMaps.get(i).getLogicalConnectionPoint(), + Map.of(onedName.key(), onedName), + LayerProtocolName.ODU, LayerProtocolName.DSR, false, + String.join("+", nodeId, I_ODU), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + // network nep creation on E_ODU node + for (int i = 0; i < xpdrNetMaps.size(); i++) { + LOG.info("eODU NEP = {}", String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())); + Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + Name onedName = new NameBuilder() + .setValueName("eNodeEdgePoint_N") + .setValue(String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint())) + .build(); + + OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrNetMaps.get(i).getLogicalConnectionPoint(), + Map.of(onedName.key(), onedName), + LayerProtocolName.ODU, LayerProtocolName.DSR, true, + String.join("+", nodeId, E_ODU), supportedInterfaceCapability); + onepl.put(onep.key(), onep); + } + return onepl; + } + + private OwnedNodeEdgePoint createNep(Uuid nepUuid, String tpid, Map nepNames, + LayerProtocolName nepProtocol, LayerProtocolName nodeProtocol, boolean withSip, + String keyword, + List> supportedInterfaceCapability) { + OwnedNodeEdgePointBuilder onepBldr = new OwnedNodeEdgePointBuilder() + .setUuid(nepUuid) + .setLayerProtocolName(nepProtocol) + .setName(nepNames); + if (withSip) { + onepBldr.setMappedServiceInterfacePoint(createMSIP(1, nepProtocol, tpid, keyword, + supportedInterfaceCapability)); + } + LOG.debug("Node layer {}", nodeProtocol.getName()); + onepBldr.setSupportedCepLayerProtocolQualifier(createSupportedLayerProtocolQualifier( + supportedInterfaceCapability, nodeProtocol)); + onepBldr.setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC) + .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL) + .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL); + return onepBldr.build(); + } + + private Map createRoadmNeps(String orNodeId, String tpId, + boolean withSip) { + Map onepMap = new HashMap<>(); + // PHOTONIC MEDIA nep + Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, PHTNC_MEDIA, tpId)) + .getBytes(Charset.forName("UTF-8"))) + .toString()); + Name nepName = new NameBuilder() + .setValueName("NodeEdgePoint name") + .setValue(String.join("+", orNodeId, PHTNC_MEDIA, tpId)) + .build(); + OwnedNodeEdgePointBuilder onepBldr = new OwnedNodeEdgePointBuilder() + .setUuid(nepUuid) + .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA) + .setName(Map.of(nepName.key(), nepName)) + .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class)) + .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC) + .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL) + .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL); + OwnedNodeEdgePoint onep = onepBldr.build(); + onepMap.put(onep.key(), onep); + + // MC nep + Uuid nepUuid1 = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, MC, tpId)) + .getBytes(Charset.forName("UTF-8"))) + .toString()); + Name nepName1 = new NameBuilder() + .setValueName("NodeEdgePoint name") + .setValue(String.join("+", orNodeId, MC, tpId)) + .build(); + OwnedNodeEdgePointBuilder onepBldr1 = new OwnedNodeEdgePointBuilder() + .setUuid(nepUuid1) + .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA) + .setName(Map.of(nepName1.key(), nepName1)) + .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class)) + .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC) + .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL) + .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL); + if (withSip) { + onepBldr1.setMappedServiceInterfacePoint(createMSIP(1, LayerProtocolName.PHOTONICMEDIA, + tpId, String.join("+", orNodeId, MC), null)); + } + OwnedNodeEdgePoint onep1 = onepBldr1.build(); + onepMap.put(onep1.key(), onep1); + + // OTSiMC nep + Uuid nepUuid2 = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, OTSI_MC, tpId)) + .getBytes(Charset.forName("UTF-8"))) + .toString()); + Name nepName2 = new NameBuilder() + .setValueName("NodeEdgePoint name") + .setValue(String.join("+", orNodeId, OTSI_MC, tpId)) + .build(); + OwnedNodeEdgePointBuilder onepBldr2 = new OwnedNodeEdgePointBuilder() + .setUuid(nepUuid2) + .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA) + .setName(Map.of(nepName2.key(), nepName2)) + .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class)) + .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC) + .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL) + .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL); + OwnedNodeEdgePoint onep2 = onepBldr2.build(); + onepMap.put(onep2.key(), onep2); + return onepMap; + } + + private Map createMSIP(int nb, + LayerProtocolName layerProtocol, String tpid, String nodeid, + List> supportedInterfaceCapability) { + Map msipl = new HashMap<>(); + for (int i = 0; i < nb; i++) { + Uuid sipUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", "SIP", nodeid, + tpid)).getBytes(Charset.forName("UTF-8"))).toString()); + MappedServiceInterfacePoint msip = new MappedServiceInterfacePointBuilder() + .setServiceInterfacePointUuid(sipUuid).build(); + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePoint sip + = createSIP(sipUuid, layerProtocol, tpid, nodeid, supportedInterfaceCapability); + this.sipMap.put(sip.key(), sip); + LOG.info("SIP created {}", sip.getUuid()); + // this.tapiSips.put(sip.key(), sip); + msipl.put(msip.key(), msip); + } + return msipl; + } + + private ServiceInterfacePoint createSIP(Uuid sipUuid, LayerProtocolName layerProtocol, String tpid, String nodeid, + List> supportedInterfaceCapability) { + // TODO: what value should be set in total capacity and available capacity + LOG.info("SIP name = {}", String.join("+", nodeid, tpid)); + Name sipName = new NameBuilder() + .setValueName("SIP name") + .setValue(String.join("+", nodeid, tpid)) + .build(); + return new ServiceInterfacePointBuilder() + .setUuid(sipUuid) + .setName(Map.of(sipName.key(), sipName)) + .setLayerProtocolName(layerProtocol) + .setAdministrativeState(AdministrativeState.UNLOCKED) + .setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED) + .setAvailableCapacity(new AvailableCapacityBuilder().build()) + .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().build()) + .setSupportedLayerProtocolQualifier(createSupportedLayerProtocolQualifier(supportedInterfaceCapability, + layerProtocol)) + .build(); + } + + private org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node + createRoadmTapiNode(String orNodeId, Map oneplist) { + // UUID + Uuid nodeUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, + PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString()); + // Names + Name nodeNames = new NameBuilder().setValueName("roadm node name") + .setValue(String.join("+", orNodeId, PHTNC_MEDIA)).build(); + // Protocol Layer + List layerProtocols = Arrays.asList(LayerProtocolName.PHOTONICMEDIA); + // Empty random creation of mandatory fields for avoiding errors.... + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + return new NodeBuilder() + .setUuid(nodeUuid) + .setName(Map.of(nodeNames.key(), nodeNames)) + .setLayerProtocolName(layerProtocols) + .setAdministrativeState(AdministrativeState.UNLOCKED) + .setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED) + .setOwnedNodeEdgePoint(oneplist) + .setNodeRuleGroup(createNodeRuleGroupForRdmNode(nodeUuid, oneplist.values())) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .setErrorCharacteristic("error") + .setLossCharacteristic("loss") + .setRepeatDeliveryCharacteristic("repeat delivery") + .setDeliveryOrderCharacteristic("delivery order") + .setUnavailableTimeCharacteristic("unavailable time") + .setServerIntegrityProcessCharacteristic("server integrity process") + .build(); + } + + private Map createNodeRuleGroupForRdmNode(Uuid nodeUuid, + Collection onepl) { + Map + nepMap = new HashMap<>(); + for (OwnedNodeEdgePoint onep : onepl) { + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint + nep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group + .NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(nodeUuid) + .setNodeEdgePointUuid(onep.key().getUuid()) + .build(); + nepMap.put(nep.key(), nep); + } + Map nodeRuleGroupMap = new HashMap<>(); + Map ruleList = new HashMap<>(); + Rule rule = new RuleBuilder() + .setLocalId("forward") + .setForwardingRule(ForwardingRule.MAYFORWARDACROSSGROUP) + .setRuleType(RuleType.FORWARDING) + .build(); + ruleList.put(rule.key(), rule); + NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder() + .setUuid(new Uuid(UUID.nameUUIDFromBytes(("rdm infra node rule group") + .getBytes(Charset.forName("UTF-8"))).toString())) + .setRule(ruleList) + .setNodeEdgePoint(nepMap) + .build(); + nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup); + return nodeRuleGroupMap; + } + + private Map createTapiTransitionalLinks(String nodeId, List xpdrNetMaps, Uuid nodeUuidDsr, + Uuid nodeUuidOtsi) { + Map linkMap = new HashMap<>(); + for (Mapping mapping : xpdrNetMaps) { + Map nepList = new HashMap<>(); + String sourceKey = String.join("+", nodeId, I_ODU, mapping.getLogicalConnectionPoint()); + Uuid sourceUuidTp = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, I_ODU, mapping.getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + String destKey = String.join("+", nodeId, I_OTSI, mapping.getLogicalConnectionPoint()); + Uuid destUuidTp = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, I_OTSI, mapping.getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString()); + NodeEdgePoint sourceNep = new NodeEdgePointBuilder() + .setTopologyUuid(this.tapiTopoUuid) + .setNodeUuid(nodeUuidDsr) + .setNodeEdgePointUuid(sourceUuidTp) + .build(); + nepList.put(sourceNep.key(), sourceNep); + NodeEdgePoint destNep = new NodeEdgePointBuilder() + .setTopologyUuid(this.tapiTopoUuid) + .setNodeUuid(nodeUuidOtsi) + .setNodeEdgePointUuid(destUuidTp) + .build(); + nepList.put(destNep.key(), destNep); + Name linkName = new NameBuilder().setValueName("transitional link name") + .setValue(String.join("--",nodeId, sourceKey, destKey)) + .build(); + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder() + .setRiskCharacteristicName("risk characteristic") + .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2")) + .build(); + ValidationMechanism validationMechanism = new ValidationMechanismBuilder() + .setValidationMechanism("validation mechanism") + .setValidationRobustness("validation robustness") + .setLayerProtocolAdjacencyValidated("layer protocol adjacency") + .build(); + Link transiLink = new LinkBuilder() + .setUuid(new Uuid( + UUID.nameUUIDFromBytes((String.join("--", nodeId, sourceKey, destKey)) + .getBytes(Charset.forName("UTF-8"))) + .toString())) + .setName(Map.of(linkName.key(), linkName)) + .setTransitionedLayerProtocolName(Arrays.asList(LayerProtocolName.ODU.getName(), + LayerProtocolName.PHOTONICMEDIA.getName())) + .setNodeEdgePoint(nepList) + .setLayerProtocolName(Arrays.asList(LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.ODU)) + .setDirection(ForwardingDirection.BIDIRECTIONAL) + .setAvailableCapacity(new AvailableCapacityBuilder().setTotalSize( + new TotalSizeBuilder().setUnit(CapacityUnit.GBPS).setValue(Uint64.valueOf(100)).build()) + .build()) + .setResilienceType(new ResilienceTypeBuilder().setProtectionType(ProtectionType.NOPROTECTON) + .setRestorationPolicy(RestorationPolicy.NA) + .build()) + .setAdministrativeState(AdministrativeState.UNLOCKED) + .setOperationalState(OperationalState.ENABLED) + .setLifecycleState(LifecycleState.INSTALLED) + .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().setTotalSize( + new TotalSizeBuilder().setUnit(CapacityUnit.GBPS).setValue(Uint64.valueOf(100)).build()) + .build()) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic)) + .setErrorCharacteristic("error") + .setLossCharacteristic("loss") + .setRepeatDeliveryCharacteristic("repeat delivery") + .setDeliveryOrderCharacteristic("delivery order") + .setUnavailableTimeCharacteristic("unavailable time") + .setServerIntegrityProcessCharacteristic("server integrity process") + .setValidationMechanism(Map.of(validationMechanism.key(), validationMechanism)) + .build(); + linkMap.put(transiLink.key(), transiLink); + } + // return a map of links and then we can do merge the corresponding link map into the topology context + return linkMap; + } + + private OduSwitchingPools createTpdrSwitchPool() { + return new OduSwitchingPoolsBuilder().build(); + } + + private OduSwitchingPools createSwtchSwitchPool(List xpdrClMaps, List xpdrNetMaps, + Integer xpdrNb) { + List tpl = new ArrayList<>(); + TpId tpId = null; + for (int i = 1; i <= xpdrClMaps.size(); i++) { + tpId = new TpId("XPDR" + xpdrNb + CLIENT + i); + tpl.add(tpId); + } + for (int i = 1; i <= xpdrNetMaps.size(); i++) { + tpId = new TpId("XPDR" + xpdrNb + NETWORK + i); + tpl.add(tpId); + } + Map nbMap = new HashMap<>(); + NonBlockingList nbl = new NonBlockingListBuilder() + .setNblNumber(Uint16.valueOf(1)) + .setTpList(tpl) + .build(); + nbMap.put(nbl.key(),nbl); + + return new OduSwitchingPoolsBuilder() + .setSwitchingPoolNumber(Uint16.valueOf(1)) + .setSwitchingPoolType(SwitchingPoolTypes.NonBlocking) + .setNonBlockingList(nbMap) + .build(); + } + + private OduSwitchingPools createMuxSwitchPool(List xpdrClMaps, List xpdrNetMaps, Integer xpdrNb) { + Map nbMap = new HashMap<>(); + for (int i = 1; i <= xpdrClMaps.size(); i++) { + List tpList = new ArrayList<>(); + TpId tpId = new TpId("XPDR" + xpdrNb + CLIENT + i); + tpList.add(tpId); + tpId = new TpId("XPDR" + xpdrNb + "-NETWORK1"); + tpList.add(tpId); + NonBlockingList nbl = new NonBlockingListBuilder() + .setNblNumber(Uint16.valueOf(i)) + .setTpList(tpList) + .setAvailableInterconnectBandwidth(Uint32.valueOf(xpdrNetMaps.size() * 10L)) + .setInterconnectBandwidthUnit(Uint32.valueOf(1000000000)) + .build(); + nbMap.put(nbl.key(),nbl); + } + return new OduSwitchingPoolsBuilder() + .setSwitchingPoolNumber(Uint16.valueOf(1)) + .setSwitchingPoolType(SwitchingPoolTypes.NonBlocking) + .setNonBlockingList(nbMap) + .build(); + } + + private Map createNodeRuleGroupForOtsiNode(String nodeId, + List xpdrNetMaps, + Map ruleList) { + Map nodeRuleGroupMap = new HashMap<>(); + // create NodeRuleGroup + int count = 1; + for (Mapping tpMapping : xpdrNetMaps) { + Map + nepList = new HashMap<>(); + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group + .NodeEdgePoint inep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210 + .node.rule.group.NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, OTSI)).getBytes(Charset.forName("UTF-8"))) + .toString())) + .setNodeEdgePointUuid(new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, I_OTSI, tpMapping.getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString())) + .build(); + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group + .NodeEdgePoint enep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210 + .node.rule.group.NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, OTSI)).getBytes(Charset.forName("UTF-8"))) + .toString())) + .setNodeEdgePointUuid(new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, E_OTSI, tpMapping.getLogicalConnectionPoint())) + .getBytes(Charset.forName("UTF-8"))).toString())) + .build(); + nepList.put(inep.key(), inep); + nepList.put(enep.key(), enep); + // Empty random creation of mandatory fields for avoiding errors.... + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder() + .setRiskCharacteristicName("risk characteristic") + .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2")) + .build(); + NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder() + .setUuid(new Uuid( + UUID.nameUUIDFromBytes(("otsi node rule group " + count).getBytes(Charset.forName("UTF-8"))) + .toString())) + .setRule(ruleList) + .setNodeEdgePoint(nepList) + .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic)) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .build(); + nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup); + count++; + } + return nodeRuleGroupMap; + } + + private Map createNodeRuleGroupForDsrNode(String nodeId, + OduSwitchingPools oorOduSwitchingPool, + Map ruleList, + Map onepl) { + // create NodeRuleGroup + if (oorOduSwitchingPool == null) { + LOG.info("TPDR node --> no switching pool"); + return new HashMap<>(); + } + LOG.info("ONEPL = {}", onepl.values()); + Map nodeRuleGroupMap = new HashMap<>(); + int count = 1; + for (NonBlockingList nbl : oorOduSwitchingPool.nonnullNonBlockingList().values()) { + LOG.info("Non blocking list = {}", nbl); + Map + nepList = new HashMap<>(); + for (TpId tp : nbl.getTpList()) { + LOG.info("EDOU TP = {}", String.join("+", nodeId, E_ODU, tp.getValue())); + LOG.info("DSR TP = {}", String.join("+", nodeId, DSR, tp.getValue())); + Uuid tpUuid = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, E_ODU, tp.getValue())).getBytes(Charset.forName("UTF-8"))) + .toString()); + Uuid tp1Uuid = new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, DSR, tp.getValue())).getBytes(Charset.forName("UTF-8"))) + .toString()); + if (onepl.containsKey(new OwnedNodeEdgePointKey(tpUuid)) + || onepl.containsKey(new OwnedNodeEdgePointKey(tp1Uuid))) { + org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint + nep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group + .NodeEdgePointBuilder() + .setTopologyUuid(tapiTopoUuid) + .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes( + (String.join("+", nodeId, DSR)).getBytes(Charset.forName("UTF-8"))) + .toString())) + .setNodeEdgePointUuid((tp.getValue().contains("CLIENT")) ? tp1Uuid : tpUuid) + .build(); + nepList.put(nep.key(), nep); + } + } + // Empty random creation of mandatory fields for avoiding errors.... + CostCharacteristic costCharacteristic = new CostCharacteristicBuilder() + .setCostAlgorithm("Restricted Shortest Path - RSP") + .setCostName("HOP_COUNT") + .setCostValue("12345678") + .build(); + LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder() + .setFixedLatencyCharacteristic("12345678") + .setQueingLatencyCharacteristic("12345678") + .setJitterCharacteristic("12345678") + .setWanderCharacteristic("12345678") + .setTrafficPropertyName("FIXED_LATENCY") + .build(); + RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder() + .setRiskCharacteristicName("risk characteristic") + .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2")) + .build(); + NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder() + .setUuid(new Uuid( + UUID.nameUUIDFromBytes(("dsr node rule group " + count).getBytes(Charset.forName("UTF-8"))) + .toString())) + .setRule(ruleList) + .setNodeEdgePoint(nepList) + .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic)) + .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic)) + .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic)) + .build(); + nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup); + count++; + } + return nodeRuleGroupMap; + } + + private List> createSupportedLayerProtocolQualifier( + List> sicList, LayerProtocolName lpn) { + if (sicList == null) { + return List.of(PHOTONICLAYERQUALIFIEROMS.class); + } + Map supIfMap = new HashMap<>(); + LOG.info("SIC list = {}", sicList); + for (Class supInterCapa : sicList) { + SupportedInterfaceCapability supIfCapa = new SupportedInterfaceCapabilityBuilder() + .withKey(new SupportedInterfaceCapabilityKey(convertSupIfCapa(supInterCapa))) + .setIfCapType(convertSupIfCapa(supInterCapa)) + .build(); + supIfMap.put(supIfCapa.key(), supIfCapa); + } + List> sclpqList = new ArrayList<>(); + for (SupportedInterfaceCapability sic : supIfMap.values()) { + switch (lpn.getName()) { + case "DSR": + case "ODU": + switch (sic.getIfCapType().getSimpleName()) { + case "If10GEODU2e": + sclpqList.add(ODUTYPEODU2E.class); + sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class); + break; + case "If10GEODU2": + sclpqList.add(ODUTYPEODU2.class); + sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class); + break; + case "If10GE": + sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class); + break; + case "If100GEODU4": + sclpqList.add(DIGITALSIGNALTYPE100GigE.class); + sclpqList.add(ODUTYPEODU4.class); + break; + case "If100GE": + sclpqList.add(DIGITALSIGNALTYPE100GigE.class); + break; + case "IfOCHOTU4ODU4": + case "IfOCH": + sclpqList.add(ODUTYPEODU4.class); + break; + default: + LOG.error("IfCapability type not managed"); + break; + } + break; + case "PHOTONIC_MEDIA": + if (sic.getIfCapType().getSimpleName().equals("IfOCHOTU4ODU4") + || sic.getIfCapType().getSimpleName().equals("IfOCH")) { + sclpqList.add(PHOTONICLAYERQUALIFIEROTSi.class); + sclpqList.add(PHOTONICLAYERQUALIFIEROMS.class); + } + break; + default: + LOG.error("Layer Protocol Name is unknown {}", lpn.getName()); + break; + } + } + return sclpqList; + } + + private static Class convertSupIfCapa(Class ifCapType) { + LOG.info("Interface Capability type = {}", ifCapType.getSimpleName()); + switch (ifCapType.getSimpleName()) { + case "If100GEODU4": + return If100GEODU4.class; + case "IfOCHOTU4ODU4": + return IfOCHOTU4ODU4.class; + case "If1GEODU0": + return If1GEODU0.class; + case "If10GEODU2e": + return If10GEODU2e.class; + case "If10GEODU2": + return If10GEODU2.class; + case "If100GE": + return If100GE.class; + case "If10GE": + return If10GE.class; + case "If1GE": + return If1GE.class; + case "IfOCH": + return IfOCH.class; + default: + return null; + } + } + + private void mergeNodeinTopology(Map nodeMap) { + // TODO is this merge correct? Should we just merge topology by changing the nodes map?? + // TODO: verify this is correct. Should we identify the context IID with the context UUID?? + LOG.info("Creating tapi node in TAPI topology context"); + InstanceIdentifier topoIID = InstanceIdentifier.builder(Context.class) + .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1.class) + .child(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext.class) + .child(Topology.class, new TopologyKey(tapiTopoUuid)) + .build(); + + Topology topology = new TopologyBuilder().setUuid(tapiTopoUuid).setNode(nodeMap).build(); + + // merge in datastore + this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, topoIID, + topology); + try { + this.networkTransactionService.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error populating TAPI topology: ", e); + } + LOG.info("Roadm Node added succesfully."); + } + + private void mergeLinkinTopology(Map linkMap) { + // TODO is this merge correct? Should we just merge topology by changing the nodes map?? + // TODO: verify this is correct. Should we identify the context IID with the context UUID?? + LOG.info("Creating tapi node in TAPI topology context"); + InstanceIdentifier topoIID = InstanceIdentifier.builder(Context.class) + .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1.class) + .child(org.opendaylight.yang.gen.v1.urn + .onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext.class) + .child(Topology.class, new TopologyKey(tapiTopoUuid)) + .build(); + + Topology topology = new TopologyBuilder().setUuid(tapiTopoUuid).setLink(linkMap).build(); + + // merge in datastore + this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, topoIID, + topology); + try { + this.networkTransactionService.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error populating TAPI topology: ", e); + } + LOG.info("Roadm Link added succesfully."); + } + + private void mergeSipsinContext(Map sips) { + // TODO is this merge correct? Should we just merge topology by changing the nodes map?? + // TODO: verify this is correct. Should we identify the context IID with the context UUID?? + try { + ContextBuilder contextBuilder = new ContextBuilder(); + contextBuilder.setServiceInterfacePoint(sips); + InstanceIdentifier contextIID = InstanceIdentifier.builder(Context.class).build(); + // merge in datastore + this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, contextIID, + contextBuilder.build()); + this.networkTransactionService.commit().get(); + LOG.info("TAPI SIPs merged successfully."); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to merge TAPI Sips", e); + } + } + + private void deleteLinkFromTopo(Uuid linkUuid) { + // TODO: check if this IID is correct + try { + InstanceIdentifier linkIID = InstanceIdentifier.builder(Context.class) + .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class, + new TopologyKey(tapiTopoUuid)).child(Link.class, new LinkKey(linkUuid)).build(); + this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, linkIID); + this.networkTransactionService.commit().get(); + LOG.info("TAPI link deleted successfully."); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to delete TAPI link", e); + } + } + + private void deleteNodeFromTopo(Uuid nodeUuid) { + // TODO: check if this IID is correct + try { + InstanceIdentifier nodeIDD = InstanceIdentifier.builder(Context.class) + .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class, + new TopologyKey(tapiTopoUuid)).child(Node.class, new NodeKey(nodeUuid)).build(); + this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, nodeIDD); + this.networkTransactionService.commit().get(); + LOG.info("TAPI Node deleted successfully."); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to delete TAPI Node", e); + } + } + + private void deleteSipFromTopo(Uuid sipUuid) { + // TODO: check if this IID is correct + try { + InstanceIdentifier sipIID = InstanceIdentifier.builder(Context.class) + .child(ServiceInterfacePoint.class, new ServiceInterfacePointKey(sipUuid)).build(); + this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, sipIID); + this.networkTransactionService.commit().get(); + LOG.info("TAPI SIP deleted successfully."); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to delete TAPI SIP", e); + } + } + + private void updateConnectivityServicesState(Uuid sipUuid, String nodeId) { + // TODO: check if this IID is correct + InstanceIdentifier connectivitycontextIID = InstanceIdentifier.builder(Context.class) + .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class) + .child(ConnectivityContext.class) + .build(); + ConnectivityContext connContext = null; + try { + Optional optConnContext = + this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivitycontextIID) + .get(); + if (!optConnContext.isPresent()) { + LOG.error("Couldnt retrieve connectivity context from datastore"); + return; + } + connContext = optConnContext.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Couldnt read connectivity context from datastore", e); + } + if (connContext == null) { + LOG.error("Connectivity context is empty"); + return; + } + // Loop through services, check if the endpoint uuid is equal to the sip. + // If so update state. + Map connServMap = connContext.getConnectivityService(); + Map connMap = connContext.getConnection(); + if (connServMap != null) { + for (ConnectivityService service:connServMap.values()) { + Map serviceEndPoints = service.getEndPoint(); + if (serviceEndPoints.values().stream().anyMatch(endPoint -> endPoint.getServiceInterfacePoint() + .getServiceInterfacePointUuid().equals(sipUuid))) { + LOG.info("Service using SIP of node {} identified. Update state of service", nodeId); + ConnectivityService updService = new ConnectivityServiceBuilder(service) + .setAdministrativeState(AdministrativeState.LOCKED) + .setOperationalState(OperationalState.DISABLED) + .setLifecycleState(LifecycleState.PENDINGREMOVAL) + .build(); + updateConnectivityService(updService); + } + } + } + // Update state of connections + if (connMap != null) { + for (Connection connection:connMap.values()) { + if (connection.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) { + Connection updConn = new ConnectionBuilder(connection) + .setLifecycleState(LifecycleState.PENDINGREMOVAL) + .setOperationalState(OperationalState.DISABLED) + .build(); + updateConnection(updConn); + } + } + } + } + + private void updateConnection(Connection updConn) { + // TODO: check if this IID is correct + InstanceIdentifier connectionIID = InstanceIdentifier.builder(Context.class) + .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class) + .child(ConnectivityContext.class).child(Connection.class, + new ConnectionKey(updConn.getUuid())).build(); + this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connectionIID, updConn); + try { + this.networkTransactionService.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error committing into datastore", e); + } + } + + private void updateConnectivityService(ConnectivityService updService) { + // TODO: check if this IID is correct + InstanceIdentifier connectivityserviceIID = InstanceIdentifier.builder(Context.class) + .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class) + .child(ConnectivityContext.class).child(ConnectivityService.class, + new ConnectivityServiceKey(updService.getUuid())).build(); + this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connectivityserviceIID, updService); + try { + this.networkTransactionService.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error committing into datastore", e); + } + } + +} diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java new file mode 100644 index 000000000..de9e8bb3e --- /dev/null +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2021 Nokia. 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.tapi.topology; + +import java.util.Collection; +import java.util.Map; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataTreeModification; +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.mapping.MappingKey; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapiPortMappingListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(TapiPortMappingListener.class); + + private final TapiNetworkModelService tapiNetworkModelService; + + public TapiPortMappingListener(TapiNetworkModelService tapiNetworkModelService) { + this.tapiNetworkModelService = tapiNetworkModelService; + } + + @Override + public void onDataTreeChanged(@NonNull Collection> changes) { + for (DataTreeModification change : changes) { + LOG.debug("TAPI module: Change in Node = {}", change.getRootNode()); + // Data before needs to be not null + if (change.getRootNode().getDataAfter() != null && change.getRootNode().getDataBefore() != null) { + Nodes nodesAft = change.getRootNode().getDataAfter(); + Nodes nodesBef = change.getRootNode().getDataBefore(); + // TODO -> need to filter out the ones that are not after creation. + // (Mapping before = null & Mapping after != null) is the rule for a first time connected device + String nodeId = nodesAft.getNodeId(); + Map mappingAft = nodesAft.getMapping(); + Map mappingBef = nodesBef.getMapping(); + LOG.info("Change in node {} with OR version = {}", nodeId, + nodesAft.getNodeInfo().getOpenroadmVersion().getName()); + if (mappingAft != null && mappingBef == null) { + LOG.info("New mapping for node {} = {}", nodeId, mappingAft); + LOG.info("As the mapping is now created for the first time, " + + "we can proceed with the creation of the node {} in the TAPI topology", nodeId); + this.tapiNetworkModelService.createTapiNode(nodeId, + nodesAft.getNodeInfo().getOpenroadmVersion().getIntValue(), nodesAft); + } else { + LOG.warn("Mapping already existed in the datastore, which means that node {} already existed " + + "in TAPI topology. The action to take will be different", nodeId); + } + } + } + } +} diff --git a/tapi/src/main/resources/OSGI-INF/blueprint/tapi-blueprint.xml b/tapi/src/main/resources/OSGI-INF/blueprint/tapi-blueprint.xml index 293ad605b..314df38f6 100644 --- a/tapi/src/main/resources/OSGI-INF/blueprint/tapi-blueprint.xml +++ b/tapi/src/main/resources/OSGI-INF/blueprint/tapi-blueprint.xml @@ -16,6 +16,9 @@ Author: Gilles Thouenon + + @@ -32,6 +35,15 @@ Author: Gilles Thouenon class="org.opendaylight.transportpce.tapi.utils.TapiListener"> + + + + + + + + + @@ -41,6 +53,19 @@ Author: Gilles Thouenon + + + + + + + + + + + + + -- 2.36.6