/* * 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.pce; import java.util.List; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.transportpce.pce.PceResult.LocalCause; import org.opendaylight.transportpce.pce.gnpy.ConnectToGnpyServer; import org.opendaylight.transportpce.pce.gnpy.ExtractTopoDataStoreImpl; import org.opendaylight.transportpce.pce.gnpy.GnpyResult; import org.opendaylight.transportpce.pce.gnpy.ServiceDataStoreOperationsImpl; import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi; import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApiBuilder; import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.gnpy.api.ServiceFileBuilder; import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.gnpy.api.TopologyFileBuilder; import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Connections; import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Elements; import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.service.PathRequest; import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.Synchronization; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestInput; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.service.path.rpc.result.PathDescriptionBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.AToZDirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ZToADirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.RoutingConstraintsSp.PceMetric; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * Class for Sending * PCE requests : * - path-computation-request * - cancel-resource-reserve. * @author Martial Coulibaly ( martial.coulibaly@gfi.com ) on behalf of Orange * */ public class PceSendingPceRPCs { /* Logging. */ private static final Logger LOG = LoggerFactory.getLogger(PceSendingPceRPCs.class); /* define procedure success (or not ). */ private PceResult rc = new PceResult(); /* * define type of request
true pathcomputation
* false cancelresourcereserve . */ private PathDescriptionBuilder pathDescription; private PathComputationRequestInput input; private DataBroker dataBroker; private PceConstraints pceHardConstraints = new PceConstraints(); private PceConstraints pceSoftConstraints = new PceConstraints(); private Long gnpyRequestId = new Long(0); public PceSendingPceRPCs() { setPathDescription(null); this.input = null; this.dataBroker = null; } public PceSendingPceRPCs(PathComputationRequestInput input, DataBroker dataBroker) { setPathDescription(null); // TODO compliance check to check that input is not empty this.input = input; this.dataBroker = dataBroker; } public void cancelResourceReserve() { LOG.info("Wait for 10s til beginning the PCE cancelResourceReserve request"); try { Thread.sleep(10000); // sleep for 10s } catch (InterruptedException e) { LOG.error(e.toString()); } LOG.info("cancelResourceReserve ..."); } public void pathComputation() throws Exception { // Comput the path according to the constraints of PCE rc = pathComputationPCE(); LOG.info("setPathDescription ..."); AToZDirection atoz = rc.getAtoZDirection(); ZToADirection ztoa = rc.getZtoADirection(); ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer(); if ((atoz == null) || (atoz.getAToZ() == null)) { rc.setRC("400"); LOG.warn("In PCE pathComputation: empty atoz path after description: result = {}", rc.toString()); return; } else { // Send the computed path A-to-Z to GNPY tool if (connectToGnpy.isGnpyURLExist()) { ExtractTopoDataStoreImpl xtrTopo = new ExtractTopoDataStoreImpl(dataBroker, input, atoz, gnpyRequestId); gnpyRequestId++; List elementsList1 = xtrTopo.getElements(); List connectionsList1 = xtrTopo.getConnections(); List pathRequestList1 = xtrTopo.getPathRequest(); List synchronizationList1 = xtrTopo.getSynchronization(); String gnpyResponse1 = getGnpyResponse(elementsList1, connectionsList1, pathRequestList1, synchronizationList1); // Analyze the response if (gnpyResponse1 != null) { GnpyResult gnpyResult = new GnpyResult(gnpyResponse1); LOG.debug("GNPy result created"); gnpyResult.analyzeResult(); } else { LOG.error("No response from the GNPy server"); } } } if ((ztoa == null) || (ztoa.getZToA() == null)) { rc.setRC("400"); LOG.error("In pathComputation empty ztoa path after description: result = {}", rc.toString()); return; } else { // Send the computed path Z-to-A to GNPY tool if (connectToGnpy.isGnpyURLExist()) { ExtractTopoDataStoreImpl xtrTopo = new ExtractTopoDataStoreImpl(dataBroker, input, ztoa, gnpyRequestId); gnpyRequestId++; List elementsList2 = xtrTopo.getElements(); List connectionsList2 = xtrTopo.getConnections(); List pathRequestList2 = xtrTopo.getPathRequest(); List synchronizationList2 = xtrTopo.getSynchronization(); String gnpyResponse2 = getGnpyResponse(elementsList2, connectionsList2, pathRequestList2, synchronizationList2); // Analyze the response if (gnpyResponse2 != null) { GnpyResult gnpyResult = new GnpyResult(gnpyResponse2); LOG.debug("GNPy result created"); gnpyResult.analyzeResult(); } else { LOG.info("No response from the GNPy server"); } } } // Set the description of the path setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa)); LOG.info("In pathComputation Graph is Found"); } public PceResult pathComputationPCE() { LOG.info("PathComputation ..."); PceConstraintsCalc constraints = new PceConstraintsCalc(input, dataBroker); pceHardConstraints = constraints.getPceHardConstraints(); pceSoftConstraints = constraints.getPceSoftConstraints(); LOG.info("nwAnalizer ..."); PceCalculation nwAnalizer = new PceCalculation(input, dataBroker, pceHardConstraints, pceSoftConstraints, rc); nwAnalizer.calcPath(); rc = nwAnalizer.getReturnStructure(); if (!rc.getStatus()) { LOG.error("In pathComputation nwAnalizer: result = {}", rc.toString()); return null; } LOG.info("PceGraph ..."); LOG.warn("PathComputation: aPceNode '{}' - zPceNode '{}'", nwAnalizer.getaPceNode(), nwAnalizer.getzPceNode()); PceGraph graph = new PceGraph(nwAnalizer.getaPceNode(), nwAnalizer.getzPceNode(), nwAnalizer.getAllPceNodes(), pceHardConstraints, pceSoftConstraints, rc); graph.calcPath(); rc = graph.getReturnStructure(); if (!rc.getStatus()) { LOG.warn("In pathComputation : Graph return without Path "); // TODO fix. This is quick workaround for algorithm problem if ((rc.getLocalCause() == LocalCause.TOO_HIGH_LATENCY) && (pceHardConstraints.getPceMetrics() == PceMetric.HopCount) && (pceHardConstraints.getMaxLatency() != -1)) { pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay); graph = patchRerunGraph(graph); } if (!rc.getStatus()) { LOG.error("In pathComputation graph.calcPath: result = {}", rc.toString()); return null; } } LOG.info("PcePathDescription ..."); PcePathDescription description = new PcePathDescription(graph.getPathAtoZ(), nwAnalizer.getAllPceLinks(), rc); description.buildDescriptions(); rc = description.getReturnStructure(); if (!rc.getStatus()) { LOG.error("In pathComputation description: result = {}", rc.toString()); return null; } return rc; } private String getGnpyResponse(List elementsList, List connectionsList, List pathRequestList, List synchronizationList) throws Exception { GnpyApi gnpyApi = new GnpyApiBuilder() .setTopologyFile( new TopologyFileBuilder().setElements(elementsList).setConnections(connectionsList).build()) .setServiceFile(new ServiceFileBuilder().setPathRequest(pathRequestList).build()).build(); InstanceIdentifier idGnpyApi = InstanceIdentifier.builder(GnpyApi.class).build(); String gnpyJson; ServiceDataStoreOperationsImpl sd = new ServiceDataStoreOperationsImpl(dataBroker); gnpyJson = sd.createJsonStringFromDataObject(idGnpyApi, gnpyApi); LOG.debug("GNPy Id: {} / json created : {}", idGnpyApi, gnpyJson); ConnectToGnpyServer connect = new ConnectToGnpyServer(); String gnpyJsonModified = gnpyJson.replace("gnpy-eqpt-config:", "") .replace("gnpy-path-computation-simplified:", "").replace("gnpy-network-topology:", ""); String gnpyResponse = connect.gnpyCnx(gnpyJsonModified); return gnpyResponse; } private PceGraph patchRerunGraph(PceGraph graph) { LOG.info("In pathComputation patchRerunGraph : rerun Graph with metric = PROPAGATION-DELAY "); graph.setConstrains(pceHardConstraints, pceSoftConstraints); graph.calcPath(); return graph; } public PathDescriptionBuilder getPathDescription() { return pathDescription; } private void setPathDescription(PathDescriptionBuilder pathDescription) { this.pathDescription = pathDescription; } public Boolean getSuccess() { return rc.getStatus(); } public String getMessage() { return rc.getMessage(); } public String getResponseCode() { return rc.getResponseCode(); } }