/* * Copyright © 2017 AT&T 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.renderer.provisiondevice; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; import java.util.concurrent.ExecutionException; import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.MountPointService; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.transportpce.renderer.mapping.PortMapping; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.circuit.pack.Ports; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.circuit.pack.PortsKey; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.circuit.packs.CircuitPacks; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.circuit.packs.CircuitPacksKey; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.interfaces.grp.Interface; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.interfaces.grp.InterfaceBuilder; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.interfaces.grp.InterfaceKey; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.org.openroadm.device.container.OrgOpenroadmDevice; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.port.Interfaces; import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OpticalChannel; import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.Interface1; import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.Interface1Builder; import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.och.container.OchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.Network; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OpenRoadmInterfaces { private final DataBroker db; private final String nodeId; private final String logicalConnPoint; private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmInterfaces.class); private final DataBroker netconfNodeDataBroker; public OpenRoadmInterfaces(DataBroker db, MountPointService mps, String nodeId, String logicalConnPoint) { this.db = db; this.logicalConnPoint = logicalConnPoint; this.nodeId = nodeId; netconfNodeDataBroker = PortMapping.getDeviceDataBroker(nodeId, mps); } /** * This methods creates an OCH interface on the ROADM nodes's termination point * based on following steps: * *

* 1. Get the physical mapping corresponding to logical port. * 2. Create generic interface object based on data in mapping object. * 3. Set the value for supporting interface (OMS) if present in the local mapping * otherwise fetch it for the first time and update the local mapping. * 4. Add Och interface specific augmentation such as waveNumber etc. * * @param waveNumber wavelength number of the Och interface. * * @return Name of the interface if successful, otherwise return null. */ public String createOchInterface(Long waveNumber) { // Add OOCH augmentation to the interface Mapping portMap = getMapping(nodeId, logicalConnPoint); if (portMap != null) { InterfaceBuilder ifBuilder = intfBuilder(portMap); // OCH interface specific data OchBuilder ocIfBuilder = new OchBuilder(); ocIfBuilder.setWavelengthNumber(waveNumber); Interface1Builder optbld1 = new Interface1Builder(); ifBuilder.setKey(new InterfaceKey(logicalConnPoint + "-" + waveNumber.toString())); ifBuilder.addAugmentation(Interface1.class, optbld1.setOch(ocIfBuilder.build()).build()); ifBuilder.setName(logicalConnPoint + "-" + waveNumber.toString()); InstanceIdentifier interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child( Interface.class, new InterfaceKey(logicalConnPoint + "-" + waveNumber.toString())); if (logicalConnPoint.toUpperCase().contains("TTP") && StringUtils.isNotEmpty(portMap.getSupportingOms())) { LOG.info("Oms interface present in local mapping for " + logicalConnPoint); ifBuilder.setSupportingInterface(portMap.getSupportingOms()); } else if (logicalConnPoint.toUpperCase().contains("TTP") && StringUtils.isEmpty(portMap .getSupportingOms())) { Ports port = getPort(portMap); if (port != null && port.getInterfaces() != null) { LOG.info("Oms interface not present in local mapping, getting it for the first time for " + logicalConnPoint); LOG.info(port.toString()); for (Interfaces intf : port.getInterfaces()) { LOG.info(intf.toString()); //TODO: This method assumes the name of the interface contains OMS substring in it //update it to fetch OMS interface more efficiently. if (intf.getInterfaceName().toUpperCase().contains("OMS")) { String omsInterface = intf.getInterfaceName(); LOG.info("found oms interface for {} with name {}", logicalConnPoint, omsInterface); ifBuilder.setSupportingInterface(omsInterface); MappingBuilder mapBldr = new MappingBuilder(); InstanceIdentifier mapIID = InstanceIdentifier.create(Network.class).child( Nodes.class, new NodesKey(nodeId)).child(Mapping.class, new MappingKey(portMap .getLogicalConnectionPoint())); mapBldr.setSupportingOms(omsInterface); mapBldr.setKey(new MappingKey(portMap.getLogicalConnectionPoint())); try { final WriteTransaction writeTransaction = db.newWriteOnlyTransaction(); writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, mapIID, mapBldr.build()); CheckedFuture submit = writeTransaction .submit(); LOG.info("Updated mapping for " + port.getPortName() + "at " + portMap .getSupportingCircuitPackName() + " with support oms interface " + intf .getInterfaceName()); submit.checkedGet(); break; } catch (TransactionCommitFailedException ex) { // TODO Auto-generated catch block LOG.info("unable to save mapping for " + port.getPortName() + " at " + portMap .getSupportingCircuitPackName()); } } } } else { LOG.error("Interface is missing for Port " + port.getPortName() + " @ " + portMap .getSupportingCircuitPackName()); return null; } } if (postInterface(interfacesIID, ifBuilder)) { return ifBuilder.getName(); } else { return null; } } // TODO: implement OCH facility for xponder return null; } public String createODU4Interface() { // Add ODU4 augmentation to the interface // TODO: implement this method return null; } public String createOTU4Interface() { // Add OTU4 augmentation to the interface // TODO: implement this method return null; } public String createETHInterface() { // Add ETH augmentation to the interface // TODO: implement this method return null; } /** * This methods does a get operation on the port subtree of the device's * operational data store.This method will be called once for each Degree port * in order to fetch the OMS interface for the first time. * * @param portMap Mapping object * * @return Ports object read from the device. */ public Ports getPort(Mapping portMap) { // Get Port subtree corresponding to the logical connection point if (netconfNodeDataBroker != null) { ReadOnlyTransaction rtx = netconfNodeDataBroker.newReadOnlyTransaction(); InstanceIdentifier portIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child( CircuitPacks.class, new CircuitPacksKey(portMap.getSupportingCircuitPackName())).child(Ports.class, new PortsKey(portMap.getSupportingPort())); Optional portObject; try { portObject = rtx.read(LogicalDatastoreType.OPERATIONAL, portIID).get(); if (portObject.isPresent()) { return portObject.get(); } } catch (InterruptedException | ExecutionException ex) { LOG.info("Error getting port subtree from the device "); return null; } } return null; } /** * This methods creates a generic interface builder object * to set the value that are common irrespective of the interface type. * * @param portMap Mapping object containing attributes required to create * interface on the device. * * @return InterfaceBuilder object with the data. */ public InterfaceBuilder intfBuilder(Mapping portMap) { InterfaceBuilder ifBuilder = new InterfaceBuilder(); ifBuilder.setType(OpticalChannel.class); ifBuilder.setDescription(" TBD "); ifBuilder.setCircuitId(" TBD "); ifBuilder.setSupportingCircuitPackName(portMap.getSupportingCircuitPackName()); ifBuilder.setSupportingPort(portMap.getSupportingPort()); return ifBuilder; } /** * This methods does an edit-config operation on the openROADM * device in order to create the given interface. * * @param interfacesIID Instance identifier for the interfaces subtree in the device. * @param ifBuilder Builder object containing the data to post. * * @return Result of operation true/false based on success/failure. */ public boolean postInterface(InstanceIdentifier interfacesIID, InterfaceBuilder ifBuilder) { // Post interface with its specific augmentation to the device if (netconfNodeDataBroker != null) { final WriteTransaction writeTransaction = netconfNodeDataBroker.newWriteOnlyTransaction(); writeTransaction.put(LogicalDatastoreType.CONFIGURATION, interfacesIID, ifBuilder.build()); final CheckedFuture submit = writeTransaction.submit(); try { submit.checkedGet(); LOG.info("Successfully posted interface " + ifBuilder.getName()); return true; } catch (TransactionCommitFailedException ex) { LOG.warn("Failed to post {} ", ifBuilder.getName()); return false; } } else { return false; } } /** * This method for a given node's termination point returns the Mapping * object based on portmapping.yang model stored in the MD-SAL * data store which is created when the node is connected for the first time. * The mapping object basically contains the following attributes of interest: * *

* 1. Supporting circuit pack * 2. Supporting port * 3. Supporting OMS interface (if port on ROADM) * * @param nodeId unique Identifier for the node of interest. * @param logicalConnPoint Name of the logical point * * @return Result Mapping object if success otherwise null. */ public Mapping getMapping(String nodeId, String logicalConnPoint) { // Getting circuit pack and port corresponding to logical connection // point InstanceIdentifier portMapping = InstanceIdentifier.builder(Network.class).child(Nodes.class, new NodesKey(nodeId)).child(Mapping.class, new MappingKey(logicalConnPoint)).build(); ReadOnlyTransaction readTx = db.newReadOnlyTransaction(); Optional mapObject; try { mapObject = readTx.read(LogicalDatastoreType.CONFIGURATION, portMapping).get(); if (mapObject.isPresent()) { LOG.info("Found mapping for the logical port " + mapObject.get().toString()); return mapObject.get(); } else { LOG.info("Could not find mapping for logical connection point : " + logicalConnPoint + " for nodeId " + nodeId); return null; } } catch (InterruptedException | ExecutionException ex) { LOG.info("Unable to read mapping for logical connection point : " + logicalConnPoint + " for nodeId " + nodeId); } return null; } }