From e9a7fe954c92452e3d64aca9e84aec36d8bfd43a Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Thu, 16 Jan 2020 15:53:43 +0100 Subject: [PATCH] Path Computation Server Initial commit of Path Computation Server. This is the 3/3 Patch Set to provide Path Computation Element (PCE) conform to RFC5440. This integrates the Graph model and Algorithms features. Graph is fulfilled from BGP-LinkState if available otherwise a graph must be provided. Details information about how to use the PCE server will be provided in docs/pcep/pcep-user-guide-pce-server.rst JIRA: BGPCEP-858 Signed-off-by: Olivier Dugeon Change-Id: Ic0552b4c7ad856fe7a7cca214bbaf81f659d876c --- bgp/topology-provider/pom.xml | 8 + .../provider/AbstractTopologyBuilder.java | 98 +-- .../provider/LinkstateGraphBuilder.java | 685 ++++++++++++++++++ .../config/LinkstateGraphProvider.java | 40 + .../blueprint/bgp-topology-provider.xml | 6 + features/algo/features-algo/pom.xml | 4 +- features/bgp/odl-bgpcep-bgp-topology/pom.xml | 6 + features/pcep/features-pcep/pom.xml | 12 + .../odl-bgpcep-pcep-server-provider/pom.xml | 43 ++ features/pcep/odl-bgpcep-pcep-server/pom.xml | 37 + .../odl-bgpcep-pcep-topology-provider/pom.xml | 6 + features/pcep/pom.xml | 2 + features/pom.xml | 4 +- pcep/pcep-artifacts/pom.xml | 24 + pcep/pom.xml | 1 + pcep/server/pom.xml | 36 + pcep/server/server-api/pom.xml | 36 + .../bgpcep/pcep/server/PathComputation.java | 27 + .../bgpcep/pcep/server/PceServerProvider.java | 18 + pcep/server/server-provider/pom.xml | 77 ++ .../pcep/server/provider/MessagesUtil.java | 274 +++++++ .../server/provider/PathComputationImpl.java | 262 +++++++ .../server/provider/PceServerFactory.java | 62 ++ .../OSGI-INF/blueprint/pce-server.xml | 22 + pcep/topology/topology-provider/pom.xml | 4 + .../provider/ServerSessionManager.java | 4 + .../Stateful07TopologySessionListener.java | 55 +- .../config/PCEPTopologyProviderBean.java | 11 +- .../PCEPTopologyProviderDependencies.java | 8 + .../OSGI-INF/blueprint/pcep-topology.xml | 4 +- .../provider/AbstractPCEPSessionTest.java | 1 + pom.xml | 2 +- 32 files changed, 1823 insertions(+), 56 deletions(-) create mode 100644 bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateGraphBuilder.java create mode 100644 bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/config/LinkstateGraphProvider.java create mode 100644 features/pcep/odl-bgpcep-pcep-server-provider/pom.xml create mode 100644 features/pcep/odl-bgpcep-pcep-server/pom.xml create mode 100644 pcep/server/pom.xml create mode 100644 pcep/server/server-api/pom.xml create mode 100644 pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PathComputation.java create mode 100644 pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PceServerProvider.java create mode 100644 pcep/server/server-provider/pom.xml create mode 100644 pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/MessagesUtil.java create mode 100644 pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PathComputationImpl.java create mode 100644 pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PceServerFactory.java create mode 100644 pcep/server/server-provider/src/main/resources/OSGI-INF/blueprint/pce-server.xml diff --git a/bgp/topology-provider/pom.xml b/bgp/topology-provider/pom.xml index fa94ae759d..3524f14e6c 100644 --- a/bgp/topology-provider/pom.xml +++ b/bgp/topology-provider/pom.xml @@ -61,6 +61,14 @@ ${project.groupId} topology-api + + ${project.groupId} + graph-api + + + org.opendaylight.mdsal.model + odl-uint24 + org.opendaylight.yangtools concepts diff --git a/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/AbstractTopologyBuilder.java b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/AbstractTopologyBuilder.java index 8e0149c2c5..746f7f86a0 100644 --- a/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/AbstractTopologyBuilder.java +++ b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/AbstractTopologyBuilder.java @@ -76,6 +76,7 @@ public abstract class AbstractTopologyBuilder implements Cluste @GuardedBy("this") @VisibleForTesting protected int listenerScheduledRestartEnforceCounter = 0; + protected boolean networkTopologyTransaction = true; protected AbstractTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference, final TopologyId topologyId, final TopologyTypes types, final Class afi, @@ -164,56 +165,63 @@ public abstract class AbstractTopologyBuilder implements Cluste @Override @SuppressWarnings("checkstyle:IllegalCatch") public synchronized void onDataTreeChanged(final Collection> changes) { - if (this.closed.get()) { - LOG.trace("Transaction chain was already closed, skipping update."); - return; - } - // check if the transaction chain needed to be restarted due to a previous error - if (restartTransactionChainOnDemand()) { - LOG.debug("The data change {} is disregarded due to restart of listener {}", changes, this); - return; - } - final ReadWriteTransaction trans = this.chain.newReadWriteTransaction(); - LOG.trace("Received data change {} event with transaction {}", changes, trans.getIdentifier()); - final AtomicBoolean transactionInError = new AtomicBoolean(false); - for (final DataTreeModification change : changes) { - try { - routeChanged(change, trans); - } catch (final RuntimeException exc) { - LOG.warn("Data change {} (transaction {}) was not completely propagated to listener {}", change, - trans.getIdentifier(), this, exc); - // trans.cancel() is not supported by PingPongTransactionChain, so we just skip the problematic change - // trans.commit() must be called first to unlock the current transaction chain, to make the chain - // closable so we cannot exit the #onDataTreeChanged() yet - transactionInError.set(true); - break; + if (networkTopologyTransaction) { + if (this.closed.get()) { + LOG.trace("Transaction chain was already closed, skipping update."); + return; } - } - trans.commit().addCallback(new FutureCallback() { - @Override - public void onSuccess(final CommitInfo result) { - // as we are enforcing trans.commit(), in some cases the transaction execution actually could be - // successfully even when an exception is captured, thus #onTransactionChainFailed() never get invoked. - // Though the transaction chain remains usable, - // the data loss will not be able to be recovered. Thus we schedule a listener restart here - if (transactionInError.get()) { - LOG.warn("Transaction {} committed successfully while exception captured. Rescheduling a restart" - + " of listener {}", trans - .getIdentifier(), AbstractTopologyBuilder.this); - scheduleListenerRestart(); - } else { - LOG.trace("Transaction {} committed successfully", trans.getIdentifier()); + // check if the transaction chain needed to be restarted due to a previous error + if (restartTransactionChainOnDemand()) { + LOG.debug("The data change {} is disregarded due to restart of listener {}", changes, this); + return; + } + final ReadWriteTransaction trans = this.chain.newReadWriteTransaction(); + LOG.trace("Received data change {} event with transaction {}", changes, trans.getIdentifier()); + final AtomicBoolean transactionInError = new AtomicBoolean(false); + for (final DataTreeModification change : changes) { + try { + routeChanged(change, trans); + } catch (final RuntimeException exc) { + LOG.warn("Data change {} (transaction {}) was not completely propagated to listener {}", change, + trans.getIdentifier(), this, exc); + // trans.cancel() is not supported by PingPongTransactionChain, so we just skip the problematic + // change. + // trans.commit() must be called first to unlock the current transaction chain, to make the chain + // closable so we cannot exit the #onDataTreeChanged() yet + transactionInError.set(true); + break; } } + trans.commit().addCallback(new FutureCallback() { + @Override + public void onSuccess(final CommitInfo result) { + // as we are enforcing trans.commit(), in some cases the transaction execution actually could be + // successfully even when an exception is captured, thus #onTransactionChainFailed() never get + // invoked. Though the transaction chain remains usable, + // the data loss will not be able to be recovered. Thus we schedule a listener restart here + if (transactionInError.get()) { + LOG.warn("Transaction {} committed successfully while exception captured. Rescheduling a" + + " restart of listener {}", trans + .getIdentifier(), AbstractTopologyBuilder.this); + scheduleListenerRestart(); + } else { + LOG.trace("Transaction {} committed successfully", trans.getIdentifier()); + } + } - @Override - public void onFailure(final Throwable throwable) { - // we do nothing but print out the log. Transaction chain restart will be done in - // #onTransactionChainFailed() - LOG.error("Failed to propagate change (transaction {}) by listener {}", trans.getIdentifier(), - AbstractTopologyBuilder.this, throwable); + @Override + public void onFailure(final Throwable throwable) { + // we do nothing but print out the log. Transaction chain restart will be done in + // #onTransactionChainFailed() + LOG.error("Failed to propagate change (transaction {}) by listener {}", trans.getIdentifier(), + AbstractTopologyBuilder.this, throwable); + } + }, MoreExecutors.directExecutor()); + } else { + for (final DataTreeModification change : changes) { + routeChanged(change, null); } - }, MoreExecutors.directExecutor()); + } } @VisibleForTesting diff --git a/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateGraphBuilder.java b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateGraphBuilder.java new file mode 100644 index 0000000000..cc268d4034 --- /dev/null +++ b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateGraphBuilder.java @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.bgpcep.bgp.topology.provider; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import java.math.BigDecimal; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import org.opendaylight.graph.ConnectedGraph; +import org.opendaylight.graph.ConnectedGraphProvider; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; +import org.opendaylight.protocol.bgp.rib.RibReference; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateAddressFamily; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateSubsequentAddressFamily; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIds; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.link._case.LinkDescriptors; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.LinkStateAttribute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.LinkAttributesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.NodeAttributesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.LinkstateRoutes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.LinkstateRoute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.CRouterIdentifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.IsisNodeCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.OspfNodeCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.adj.flags.flags.isis.adj.flags._case.IsisAdjFlags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.adj.flags.flags.ospf.adj.flags._case.OspfAdjFlags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.flags.IsisPrefixFlagsCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.DecimalBandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Delay; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Loss; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Vertex.VertexType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.EdgeAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.EdgeAttributesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.MinMaxDelay; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.MinMaxDelayBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidthBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidthKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph.DomainScope; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.PrefixBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.vertex.SrgbBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.bgp.linkstate.topology.type.BgpLinkstateTopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.SrlgId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This Class build the Traffic Engineering Database as a Connected Graph + * suitable to be used latter by Path Computation algorithms to compute end to + * end path. + * + * @author Olivier Dugeon + * @author Philippe Niger + * + */ + +public class LinkstateGraphBuilder extends AbstractTopologyBuilder { + private static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder().addAugmentation( + TopologyTypes1.class, + new TopologyTypes1Builder().setBgpLinkstateTopology(new BgpLinkstateTopologyBuilder().build()).build()) + .build(); + + private static final String UNHANDLED_OBJECT_CLASS = "Unhandled object class {}"; + + private static final Logger LOG = LoggerFactory.getLogger(LinkstateGraphBuilder.class); + + private ConnectedGraphProvider graphProvider; + private ConnectedGraph cgraph; + + public LinkstateGraphBuilder(final DataBroker dataProvider, final RibReference locRibReference, + final TopologyId topologyId, ConnectedGraphProvider provider) { + super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class, + LinkstateSubsequentAddressFamily.class); + this.graphProvider = requireNonNull(provider); + this.cgraph = provider.createConnectedGraph("ted://" + topologyId.getValue(), + DomainScope.IntraDomain); + /* LinkStateGraphBuilder doesn't write information in the Network Topology tree of the Data Store. + * This is performed by ConnectedGraphProvider which write element in Graph tree of the Data Store */ + this.networkTopologyTransaction = false; + LOG.info("Started Traffic Engineering Graph Builder"); + } + + @VisibleForTesting + LinkstateGraphBuilder(final DataBroker dataProvider, final RibReference locRibReference, + final TopologyId topologyId, ConnectedGraphProvider provider, final long listenerResetLimitInMillsec, + final int listenerResetEnforceCounter) { + super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class, + LinkstateSubsequentAddressFamily.class, listenerResetLimitInMillsec, listenerResetEnforceCounter); + this.graphProvider = requireNonNull(provider); + this.cgraph = provider.createConnectedGraph("ted://" + topologyId.getValue(), + DomainScope.IntraDomain); + /* LinkStateGraphBuilder doesn't write information in the Network Topology tree of the Data Store. + * This is performed by ConnectedGraphProvider which write element in Graph tree of the Data Store */ + this.networkTopologyTransaction = false; + LOG.info("Started Traffic Engineering Graph Builder"); + } + + @Override + protected void createObject(final ReadWriteTransaction trans, final InstanceIdentifier id, + final LinkstateRoute value) { + final ObjectType t = value.getObjectType(); + Preconditions.checkArgument(t != null, "Route %s value %s has null object type", id, value); + + if (t instanceof LinkCase) { + createEdge(value, (LinkCase) t, value.getAttributes()); + } else if (t instanceof NodeCase) { + createVertex(value, (NodeCase) t, value.getAttributes()); + } else if (t instanceof PrefixCase) { + createPrefix(value, (PrefixCase) t, value.getAttributes()); + } else { + LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface()); + } + } + + /** + * Verify that mandatory information (Local & Remote Node and Link + * descriptors) are present in the link. + * + * @param linkCase The Link part of the Linkstate route + * + * @return True if all information are present, false otherwise + */ + private boolean checkLinkState(final LinkCase linkCase) { + if (linkCase.getLocalNodeDescriptors() == null || linkCase.getRemoteNodeDescriptors() == null) { + LOG.warn("Missing Local or Remote Node descriptor in link {}, skipping it", linkCase); + return false; + } + if (linkCase.getLinkDescriptors() == null) { + LOG.warn("Missing Link descriptor in link {}, skipping it", linkCase); + return false; + } + return true; + } + + /** + * Get Link attributes from the Link State route. + * + * @param attributes Link State Route Attributes + * + * @return Link Attributes + */ + private LinkAttributes getLinkAttributes(final Attributes attributes) { + final LinkAttributes la; + final Attributes1 attr = attributes.augmentation(Attributes1.class); + if (attr != null) { + final LinkStateAttribute attrType = attr.getLinkStateAttribute(); + if (attrType != null) { + la = ((LinkAttributesCase) attrType).getLinkAttributes(); + } else { + return null; + } + } else { + return null; + } + return la; + } + + /** + * Determine the Source Edge Key from the link descriptor. + * There is several case: IPv4, IPv6 address or Unnumbered Interface. + * + * @param linkCase The Link part of the Linkstate route + * + * @return Unique key + */ + private Uint64 getEdgeId(LinkCase linkCase) { + long key = 0; + if (linkCase.getLinkDescriptors().getIpv4InterfaceAddress() != null) { + key = ipv4ToKey(linkCase.getLinkDescriptors().getIpv4InterfaceAddress().getValue()); + } + if (linkCase.getLinkDescriptors().getIpv6InterfaceAddress() != null) { + key = ipv6ToKey(linkCase.getLinkDescriptors().getIpv6InterfaceAddress().getValue()); + } + if (linkCase.getLinkDescriptors().getLinkLocalIdentifier() != null) { + key = linkCase.getLinkDescriptors().getLinkLocalIdentifier().longValue(); + } + return Uint64.valueOf(key); + } + + /** + * Create new Connected Edge in the Connected Graph. + * + * @param value The complete Linkstate route information + * @param linkCase The Link part of the Linkstate route + * @param attributes The Link attributes + * + */ + private void createEdge(final LinkstateRoute value, final LinkCase linkCase, final Attributes attributes) { + Preconditions.checkArgument(checkLinkState(linkCase), "Missing mandatory information in link {}", linkCase); + + final LinkAttributes la = getLinkAttributes(attributes); + if (la == null) { + LOG.warn("Missing attributes in link {} route {}, skipping it", linkCase, value); + return; + } + + /* Get Source and Destination Vertex from the graph */ + Uint64 srcId = getVertexId(linkCase.getLocalNodeDescriptors().getCRouterIdentifier()); + Uint64 dstId = getVertexId(linkCase.getRemoteNodeDescriptors().getCRouterIdentifier()); + if (srcId == Uint64.ZERO || dstId == Uint64.ZERO) { + LOG.warn("Unable to get the Source or Destination Vertex Identifier from link {}, skipping it", linkCase); + return; + } + + /* Get Source and Destination Key for the corresponding Edge */ + Uint64 edgeId = getEdgeId(linkCase); + if (edgeId == Uint64.ZERO) { + LOG.warn("Unable to get the Edge Identifier from link {}, skipping it", linkCase); + return; + } + + /* Add associated Edge */ + Edge edge = new EdgeBuilder().setEdgeId(edgeId).setLocalVertexId(srcId).setRemoteVertexId(dstId) + .setName(srcId + " - " + dstId) + .setEdgeAttributes(createEdgeAttributes(la, linkCase.getLinkDescriptors())).build(); + + /* + * Add corresponding Prefix for the Local Address. Remote address will be added with the remote Edge */ + PrefixBuilder prefBuilder = new PrefixBuilder().setVertexId(srcId); + if (edge.getEdgeAttributes().getLocalAddress().getIpv4Address() != null) { + prefBuilder.setPrefix(new IpPrefix( + new Ipv4Prefix(edge.getEdgeAttributes().getLocalAddress().getIpv4Address().getValue() + "/32"))); + } + if (edge.getEdgeAttributes().getLocalAddress().getIpv6Address() != null) { + prefBuilder.setPrefix(new IpPrefix( + new Ipv6Prefix(edge.getEdgeAttributes().getLocalAddress().getIpv6Address().getValue() + "/128"))); + } + Prefix prefix = prefBuilder.build(); + + /* Add the Edge in the Connected Graph */ + LOG.info("Add Edge {} and associated Prefix {} in TED[{}]", edge.getName(), prefix.getPrefix(), cgraph); + cgraph.addEdge(edge); + cgraph.addPrefix(prefix); + } + + /** + * Create Edge Attributes from Link attributes. + * + * @param la Linkstate Attributes + * @param linkDesc Linkstate Descriptors + * + * @return EdgeAttributes + */ + private static final int MAX_PRIORITY = 8; + + private EdgeAttributes createEdgeAttributes(LinkAttributes la, final LinkDescriptors linkDesc) { + EdgeAttributesBuilder builder = new EdgeAttributesBuilder(); + + if (linkDesc.getIpv4InterfaceAddress() != null) { + builder.setLocalAddress(new IpAddress(new Ipv4Address(linkDesc.getIpv4InterfaceAddress()))); + } + if (linkDesc.getIpv6InterfaceAddress() != null) { + builder.setLocalAddress(new IpAddress(new Ipv6Address(linkDesc.getIpv6InterfaceAddress()))); + } + if (linkDesc.getIpv4NeighborAddress() != null) { + builder.setRemoteAddress(new IpAddress(new Ipv4Address(linkDesc.getIpv4NeighborAddress()))); + } + if (linkDesc.getIpv6NeighborAddress() != null) { + builder.setRemoteAddress(new IpAddress(new Ipv6Address(linkDesc.getIpv6NeighborAddress()))); + } + if (linkDesc.getLinkLocalIdentifier() != null) { + builder.setLocalIdentifier(linkDesc.getLinkLocalIdentifier()); + } + if (linkDesc.getLinkRemoteIdentifier() != null) { + builder.setRemoteIdentifier(linkDesc.getLinkRemoteIdentifier()); + } + if (la.getMetric() != null) { + builder.setMetric(la.getMetric().getValue()); + } + if (la.getTeMetric() != null) { + builder.setTeMetric(la.getTeMetric().getValue()); + } + if (la.getMaxLinkBandwidth() != null) { + builder.setMaxLinkBandwidth(bandwithToDecimalBandwidth(la.getMaxLinkBandwidth())); + } + if (la.getMaxReservableBandwidth() != null) { + builder.setMaxResvLinkBandwidth(bandwithToDecimalBandwidth(la.getMaxReservableBandwidth())); + } + if (la.getUnreservedBandwidth() != null) { + int upperBound = Math.min(la.getUnreservedBandwidth().size(), MAX_PRIORITY); + final List unRsvBw = new ArrayList<>(upperBound); + + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120 + .UnreservedBandwidth bandwidth : la.getUnreservedBandwidth()) { + unRsvBw.add(new UnreservedBandwidthBuilder() + .setBandwidth(bandwithToDecimalBandwidth(bandwidth.getBandwidth())) + .withKey(new UnreservedBandwidthKey(bandwidth.getPriority())).build()); + } + builder.setUnreservedBandwidth(unRsvBw); + } + if (la.getAdminGroup() != null) { + builder.setAdminGroup(la.getAdminGroup().getValue()); + } + if (la.getLinkDelay() != null) { + builder.setDelay(new Delay(la.getLinkDelay().getValue())); + } + if (la.getLinkMinMaxDelay() != null && la.getLinkMinMaxDelay() != null) { + MinMaxDelay mmDelay = new MinMaxDelayBuilder() + .setMaxDelay(new Delay(la.getLinkMinMaxDelay().getMaxDelay().getValue())) + .setMinDelay(new Delay(la.getLinkMinMaxDelay().getMinDelay().getValue())).build(); + builder.setMinMaxDelay(mmDelay); + } + if (la.getDelayVariation() != null) { + builder.setJitter(new Delay(la.getDelayVariation().getValue())); + } + if (la.getLinkLoss() != null) { + builder.setLoss(new Loss(la.getLinkLoss().getValue())); + } + if (la.getAvailableBandwidth() != null) { + builder.setAvailableBandwidth(bandwithToDecimalBandwidth(la.getAvailableBandwidth())); + } + if (la.getResidualBandwidth() != null) { + builder.setResidualBandwidth(bandwithToDecimalBandwidth(la.getResidualBandwidth())); + } + if (la.getUtilizedBandwidth() != null) { + builder.setUtilizedBandwidth(bandwithToDecimalBandwidth(la.getUtilizedBandwidth())); + } + if (la.getSharedRiskLinkGroups() != null) { + List srlgs = new ArrayList(); + for (SrlgId srlg : la.getSharedRiskLinkGroups()) { + srlgs.add(srlg.getValue()); + } + builder.setSrlgs(srlgs); + } + if (la.getSrAdjIds() != null) { + for (SrAdjIds adj : la.getSrAdjIds()) { + if (adj.getSidLabelIndex() instanceof LocalLabelCase) { + boolean backup = false; + if (adj.getFlags() instanceof OspfAdjFlags) { + backup = ((OspfAdjFlags) adj.getFlags()).isBackup(); + } + if (adj.getFlags() instanceof IsisAdjFlags) { + backup = ((IsisAdjFlags) adj.getFlags()).isBackup(); + } + if (!backup) { + builder.setAdjSid(((LocalLabelCase) adj.getSidLabelIndex()).getLocalLabel().getValue()); + } else { + builder.setBackupAdjSid(((LocalLabelCase) adj.getSidLabelIndex()).getLocalLabel().getValue()); + } + } + } + } + return builder.build(); + } + + /** + * Get Node Attributes from Link State Route attributes. + * + * @param attributes The attribute part from the Link State route + * + * @return Node Attributes + */ + private NodeAttributes getNodeAttributes(final Attributes attributes) { + final NodeAttributes na; + final Attributes1 attr = attributes.augmentation(Attributes1.class); + if (attr != null) { + final LinkStateAttribute attrType = attr.getLinkStateAttribute(); + if (attrType != null) { + na = ((NodeAttributesCase) attrType).getNodeAttributes(); + } else { + return null; + } + } else { + return null; + } + return na; + } + + /** + * Create Vertex from the Node Attributes. + * + * @param na Node Attributes + * @param cvertex Connected Vertex associated to this Vertex + * @param as As number + * + * @return New Vertex + */ + private Vertex getVertex(NodeAttributes na, Uint64 id, int as) { + VertexBuilder builder = new VertexBuilder().setVertexId(id).setAsn(Uint32.valueOf(as)); + if (na.getIpv4RouterId() != null) { + builder.setRouterId(new IpAddress(new Ipv4Address(na.getIpv4RouterId().getValue()))); + } + if (na.getIpv6RouterId() != null) { + builder.setRouterId(new IpAddress(new Ipv6Address(na.getIpv6RouterId().getValue()))); + } + /* + * Set Router Name with dynamic hostname (IS-IS) or IPv4 address in dot decimal format (OSPF) + */ + if (na.getDynamicHostname() != null) { + builder.setName(na.getDynamicHostname()); + } else { + int key = id.intValue(); + builder.setName( + ((key << 24) & 0xFF) + "." + ((key << 16) & 0xFF) + "." + ((key << 8) & 0xFF) + "." + (key & 0xFF)); + } + if (na.getSrCapabilities() != null) { + builder.setSrgb(new SrgbBuilder() + .setLowerBound( + ((LocalLabelCase) na.getSrCapabilities().getSidLabelIndex()).getLocalLabel().getValue()) + .setRangeSize(na.getSrCapabilities().getRangeSize().getValue()) + .build()); + } + if (na.getNodeFlags() != null) { + if (na.getNodeFlags().isAbr()) { + builder.setVertexType(VertexType.Abr); + } + if (na.getNodeFlags().isExternal()) { + builder.setVertexType(VertexType.AsbrOut); + } + } else { + builder.setVertexType(VertexType.Standard); + } + return builder.build(); + } + + /** + * Create new Connected Vertex in the Connected Graph. + * + * @param value The complete Linkstate route information + * @param nodeCase The node part of the Linkstate route + * @param attributes The node attributes + */ + private void createVertex(final LinkstateRoute value, final NodeCase nodeCase, final Attributes attributes) { + Preconditions.checkArgument(nodeCase != null, "Missing Node Case. Skip this Node"); + Preconditions.checkArgument(nodeCase.getNodeDescriptors() != null, "Missing Node Descriptors. Skip this Node"); + + Uint64 vertexId = getVertexId(nodeCase.getNodeDescriptors().getCRouterIdentifier()); + if (vertexId == Uint64.ZERO) { + LOG.warn("Unable to get Vertex Identifier from descriptor {}, skipping it", nodeCase.getNodeDescriptors()); + return; + } + + NodeAttributes na = getNodeAttributes(attributes); + if (na == null) { + LOG.warn("Missing attributes in node {} route {}, skipping it", nodeCase, value); + return; + } + + int asNumber = 0; + if (nodeCase.getNodeDescriptors() != null) { + asNumber = nodeCase.getNodeDescriptors().getAsNumber().getValue().intValue(); + } + Vertex vertex = getVertex(na, vertexId, asNumber); + + /* Add the Connected Vertex and associated Vertex in the Graph */ + LOG.info("Add Vertex {} in TED[{}]", vertex.getName(), cgraph); + cgraph.addVertex(vertex); + } + + /** + * Create new Prefix in the Connected Graph. + * + * @param value The complete Linkstate route information + * @param prefixCase The Prefix part of the Linkstate route + * @param attributes The Prefix attributes + */ + private void createPrefix(final LinkstateRoute value, final PrefixCase prefixCase, final Attributes attributes) { + final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation(); + if (ippfx == null) { + LOG.warn("IP reachability not present in prefix {} route {}, skipping it", prefixCase, value); + return; + } + + /* Verify that all mandatory information are present */ + final PrefixAttributes pa; + final Attributes1 attr = attributes.augmentation(Attributes1.class); + if (attr != null) { + final LinkStateAttribute attrType = attr.getLinkStateAttribute(); + if (attrType != null) { + pa = ((PrefixAttributesCase) attrType).getPrefixAttributes(); + } else { + LOG.warn("Missing attribute type in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value); + return; + } + } else { + LOG.warn("Missing attributes in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value); + return; + } + + /* + * Get Connected Vertex from Connected Graph corresponding to the + * Advertising Node Descriptor + */ + Uint64 vertexId = getVertexId(prefixCase.getAdvertisingNodeDescriptors().getCRouterIdentifier()); + if (vertexId == Uint64.ZERO) { + LOG.warn("Unable to get the Vertex Identifier from descriptor {}, skipping it", + prefixCase.getAdvertisingNodeDescriptors()); + return; + } + + /* Create Prefix */ + PrefixBuilder builder = new PrefixBuilder().setVertexId(vertexId); + if (pa.getSrPrefix() != null && pa.getSrPrefix().getSidLabelIndex() instanceof SidCase) { + builder.setPrefixSid(((SidCase) pa.getSrPrefix().getSidLabelIndex()).getSid()); + if (pa.getSrPrefix().getFlags() instanceof IsisPrefixFlagsCase) { + builder.setNodeSid( + ((IsisPrefixFlagsCase) pa.getSrPrefix().getFlags()).getIsisPrefixFlags().isNodeSid()); + } else { + /* + * Seems that OSPF Flags are not accessible. Assuming that the + * Prefix is a Node SID + */ + builder.setNodeSid(true); + } + } + if (ippfx.getIpv4Prefix() != null) { + builder.setPrefix(new IpPrefix(ippfx.getIpv4Prefix())); + } + if (ippfx.getIpv6Prefix() != null) { + builder.setPrefix(new IpPrefix(ippfx.getIpv6Prefix())); + } + Prefix prefix = builder.build(); + + /* Add the Prefix to the Connected Vertex within the Connected Graph */ + LOG.info("Add prefix {} in TED[{}]", builder.getPrefix(), cgraph); + cgraph.addPrefix(prefix); + } + + @Override + protected void removeObject(final ReadWriteTransaction trans, final InstanceIdentifier id, + final LinkstateRoute value) { + if (value == null) { + LOG.error("Empty before-data received in delete data change notification for instance id {}", id); + return; + } + + final ObjectType t = value.getObjectType(); + if (t instanceof LinkCase) { + removeEdge((LinkCase) t); + } else if (t instanceof NodeCase) { + removeVertex((NodeCase) t); + } else if (t instanceof PrefixCase) { + removePrefix((PrefixCase) t); + } else { + LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface()); + } + } + + private void removeEdge(LinkCase linkCase) { + /* Get Source and Destination Connected Vertex */ + if (linkCase.getLinkDescriptors() == null) { + LOG.warn("Missing Link descriptor in link {}, skipping it", linkCase); + return; + } + EdgeKey edgeKey = new EdgeKey(getEdgeId(linkCase)); + if ((edgeKey == null) || (edgeKey.getEdgeId() == Uint64.ZERO)) { + LOG.warn("Unable to get the Edge Key from link {}, skipping it", linkCase); + return; + } + + LOG.info("Deleted Edge {} from TED[{}]", edgeKey, cgraph); + cgraph.deleteEdge(edgeKey); + } + + private void removeVertex(NodeCase nodeCase) { + VertexKey vertexKey = new VertexKey(getVertexId(nodeCase.getNodeDescriptors().getCRouterIdentifier())); + if ((vertexKey == null) || (vertexKey.getVertexId() == Uint64.ZERO)) { + LOG.warn("Unable to get Vertex Key from descriptor {}, skipping it", nodeCase.getNodeDescriptors()); + return; + } + + LOG.info("Deleted Vertex {} in TED[{}]", vertexKey, cgraph); + cgraph.deleteVertex(vertexKey); + } + + private void removePrefix(PrefixCase prefixCase) { + final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation(); + if (ippfx == null) { + LOG.warn("IP reachability not present in prefix {}, skipping it", prefixCase); + return; + } + + LOG.info("Deleted prefix {} in TED[{}]", ippfx, cgraph); + cgraph.deletePrefix(ippfx); + } + + /** + * Get Vertex in the Graph by the OSPF Router ID or IS-IS-System ID. + * + * @param routerID The Router Identifier entry + * + * @return Vertex in the Connected Graph that corresponds to this Router ID. Vertex is created if not found. + */ + private Uint64 getVertexId(CRouterIdentifier routerID) { + Long rid = 0L; + + if (routerID instanceof IsisNodeCase) { + byte[] isoId = ((IsisNodeCase) routerID).getIsisNode().getIsoSystemId().getValue(); + final byte[] convert = {0, 0, isoId[0], isoId[1], isoId[2], isoId[3], isoId[4], isoId[5]}; + rid = ByteBuffer.wrap(convert).getLong(); + } + if (routerID instanceof OspfNodeCase) { + rid = ((OspfNodeCase) routerID).getOspfNode().getOspfRouterId().longValue(); + } + + LOG.debug("Get Vertex Identifier {}", rid); + return Uint64.valueOf(rid); + } + + private DecimalBandwidth bandwithToDecimalBandwidth(Bandwidth bw) { + return new DecimalBandwidth(BigDecimal.valueOf(ByteBuffer.wrap(bw.getValue()).getFloat())); + } + + private long ipv4ToKey(String str) { + byte[] ip; + try { + ip = ((Inet4Address) Inet4Address.getByName(str)).getAddress(); + } catch (UnknownHostException e) { + return 0; + } + return (((0xFF & ip[0]) << 24) | ((0xFF & ip[1]) << 16) | ((0xFF & ip[2]) << 8) | (0xFF & ip[3])); + } + + private Long ipv6ToKey(String str) { + byte[] ip; + try { + ip = ((Inet6Address) Inet6Address.getByName(str)).getAddress(); + } catch (UnknownHostException e) { + return 0L; + } + /* Keep only the lower 64bits from the IP address */ + byte[] lowerIP = {ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]}; + return ByteBuffer.wrap(lowerIP).getLong(); + } + + @Override + protected InstanceIdentifier getRouteWildcard(final InstanceIdentifier tablesId) { + return tablesId.child(LinkstateRoutesCase.class, LinkstateRoutes.class).child(LinkstateRoute.class); + } + + @Override + protected void clearTopology() { + cgraph.clear(); + } + +} diff --git a/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/config/LinkstateGraphProvider.java b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/config/LinkstateGraphProvider.java new file mode 100644 index 0000000000..1d1e3a0581 --- /dev/null +++ b/bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/config/LinkstateGraphProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Orange. 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.bgpcep.bgp.topology.provider.config; + +import org.opendaylight.bgpcep.bgp.topology.provider.AbstractTopologyBuilder; +import org.opendaylight.bgpcep.bgp.topology.provider.LinkstateGraphBuilder; +import org.opendaylight.bgpcep.bgp.topology.provider.spi.BgpTopologyDeployer; +import org.opendaylight.graph.ConnectedGraphProvider; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.protocol.bgp.rib.RibReference; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; + +public final class LinkstateGraphProvider extends AbstractBgpTopologyProvider { + + ConnectedGraphProvider graphProvider; + + public LinkstateGraphProvider(final BgpTopologyDeployer deployer, final ConnectedGraphProvider graphProvider) { + super(deployer); + this.graphProvider = graphProvider; + } + + @Override + AbstractTopologyBuilder createTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference, + final TopologyId topologyId) { + return new LinkstateGraphBuilder(dataProvider, locRibReference, topologyId, this.graphProvider); + } + + @Override + public boolean topologyTypeFilter(final Topology topology) { + final TopologyTypes1 topoAug = getTopologyAug(topology); + return topoAug != null && topoAug.getBgpLinkstateTopology() != null; + } +} diff --git a/bgp/topology-provider/src/main/resources/OSGI-INF/blueprint/bgp-topology-provider.xml b/bgp/topology-provider/src/main/resources/OSGI-INF/blueprint/bgp-topology-provider.xml index d98416b448..85a96dbc4e 100644 --- a/bgp/topology-provider/src/main/resources/OSGI-INF/blueprint/bgp-topology-provider.xml +++ b/bgp/topology-provider/src/main/resources/OSGI-INF/blueprint/bgp-topology-provider.xml @@ -33,4 +33,10 @@ + + + + + + diff --git a/features/algo/features-algo/pom.xml b/features/algo/features-algo/pom.xml index b859177d91..8ad966221c 100644 --- a/features/algo/features-algo/pom.xml +++ b/features/algo/features-algo/pom.xml @@ -23,13 +23,13 @@ ${project.groupId} - odl-bgpcep-algo + odl-bgpcep-algo-api xml features ${project.groupId} - odl-bgpcep-algo-api + odl-bgpcep-algo xml features diff --git a/features/bgp/odl-bgpcep-bgp-topology/pom.xml b/features/bgp/odl-bgpcep-bgp-topology/pom.xml index 46db6c5e9c..f847a6de8d 100644 --- a/features/bgp/odl-bgpcep-bgp-topology/pom.xml +++ b/features/bgp/odl-bgpcep-bgp-topology/pom.xml @@ -44,6 +44,12 @@ xml features + + ${project.groupId} + odl-bgpcep-graph + xml + features + org.opendaylight.mdsal.model odl-mdsal-model-draft-clemm-netmod-yang-network-topo-01 diff --git a/features/pcep/features-pcep/pom.xml b/features/pcep/features-pcep/pom.xml index a3157b51ce..fbf5d7b080 100644 --- a/features/pcep/features-pcep/pom.xml +++ b/features/pcep/features-pcep/pom.xml @@ -51,6 +51,12 @@ xml features + + ${project.groupId} + odl-bgpcep-pcep-server + xml + features + ${project.groupId} odl-bgpcep-pcep-topology @@ -63,6 +69,12 @@ xml features + + ${project.groupId} + odl-bgpcep-pcep-server-provider + xml + features + ${project.groupId} odl-bgpcep-pcep-p2mp-te-lsp diff --git a/features/pcep/odl-bgpcep-pcep-server-provider/pom.xml b/features/pcep/odl-bgpcep-pcep-server-provider/pom.xml new file mode 100644 index 0000000000..d774ecc2e4 --- /dev/null +++ b/features/pcep/odl-bgpcep-pcep-server-provider/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + org.opendaylight.bgpcep + single-feature-parent + 0.14.0-SNAPSHOT + ../../../single-feature-parent + + + odl-bgpcep-pcep-server-provider + feature + + OpenDaylight :: PCEP :: PCE Server Provider + + + + ${project.groupId} + pcep-server-provider + + + ${project.groupId} + odl-bgpcep-pcep-server + xml + features + + + ${project.groupId} + odl-bgpcep-algo + xml + features + + + diff --git a/features/pcep/odl-bgpcep-pcep-server/pom.xml b/features/pcep/odl-bgpcep-pcep-server/pom.xml new file mode 100644 index 0000000000..e69d9eafbb --- /dev/null +++ b/features/pcep/odl-bgpcep-pcep-server/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + + org.opendaylight.bgpcep + single-feature-parent + 0.14.0-SNAPSHOT + ../../../single-feature-parent + + + odl-bgpcep-pcep-server + feature + + OpenDaylight :: PCEP :: PCE Server API + + + + ${project.groupId} + pcep-server-api + + + ${project.groupId} + odl-bgpcep-algo-api + xml + features + + + diff --git a/features/pcep/odl-bgpcep-pcep-topology-provider/pom.xml b/features/pcep/odl-bgpcep-pcep-topology-provider/pom.xml index 16c9aee524..65a603c669 100644 --- a/features/pcep/odl-bgpcep-pcep-topology-provider/pom.xml +++ b/features/pcep/odl-bgpcep-pcep-topology-provider/pom.xml @@ -44,6 +44,12 @@ xml features + + ${project.groupId} + odl-bgpcep-pcep-server-provider + xml + features + org.opendaylight.mdsal odl-mdsal-dom-broker diff --git a/features/pcep/pom.xml b/features/pcep/pom.xml index 7c128fcf70..743df9beff 100644 --- a/features/pcep/pom.xml +++ b/features/pcep/pom.xml @@ -28,8 +28,10 @@ odl-bgpcep-pcep-impl odl-bgpcep-programming-api odl-bgpcep-programming-impl + odl-bgpcep-pcep-server odl-bgpcep-pcep-topology odl-bgpcep-pcep-stateful07 + odl-bgpcep-pcep-server-provider odl-bgpcep-pcep-topology-provider odl-bgpcep-pcep-tunnel-provider odl-bgpcep-pcep-segment-routing diff --git a/features/pom.xml b/features/pom.xml index a37209546f..a1faa69cad 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -21,10 +21,10 @@ pom - bgp - pcep graph + bgp algo + pcep bgpcep-extras bmp rsvp diff --git a/pcep/pcep-artifacts/pom.xml b/pcep/pcep-artifacts/pom.xml index fd3d4a7098..efe76288e4 100644 --- a/pcep/pcep-artifacts/pom.xml +++ b/pcep/pcep-artifacts/pom.xml @@ -82,6 +82,16 @@ pcep-segment-routing ${project.version} + + ${project.groupId} + pcep-server-api + ${project.version} + + + ${project.groupId} + pcep-server-provider + ${project.version} + ${project.groupId} pcep-topology-api @@ -172,6 +182,13 @@ xml ${project.version} + + ${project.groupId} + odl-bgpcep-pcep-server + features + xml + ${project.version} + ${project.groupId} odl-bgpcep-pcep-topology @@ -193,6 +210,13 @@ xml ${project.version} + + ${project.groupId} + odl-bgpcep-pcep-server-provider + features + xml + ${project.version} + ${project.groupId} odl-bgpcep-pcep-topology-provider diff --git a/pcep/pom.xml b/pcep/pom.xml index afa4aa2779..6c2856711c 100644 --- a/pcep/pom.xml +++ b/pcep/pom.xml @@ -32,6 +32,7 @@ ietf-stateful07 ietf-p2mp-te-lsp testtool + server topology segment-routing pcc-mock diff --git a/pcep/server/pom.xml b/pcep/server/pom.xml new file mode 100644 index 0000000000..62df503226 --- /dev/null +++ b/pcep/server/pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + + org.opendaylight.odlparent + odlparent-lite + 6.0.4 + + + + org.opendaylight.bgpcep + pcep-server-parent + 0.14.0-SNAPSHOT + pom + Path Computation Element Server + ${project.artifactId} + + + server-api + server-provider + + + + true + true + + diff --git a/pcep/server/server-api/pom.xml b/pcep/server/server-api/pom.xml new file mode 100644 index 0000000000..4e17c807de --- /dev/null +++ b/pcep/server/server-api/pom.xml @@ -0,0 +1,36 @@ + + + + + + 4.0.0 + + org.opendaylight.bgpcep + binding-parent + 0.14.0-SNAPSHOT + ../../../binding-parent + + + pcep-server-api + Path Computation Server API + bundle + ${project.artifactId} + + + + ${project.groupId} + pcep-api + + + ${project.groupId} + graph-api + + + diff --git a/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PathComputation.java b/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PathComputation.java new file mode 100644 index 0000000000..ad8e761180 --- /dev/null +++ b/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PathComputation.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.bgpcep.pcep.server; + +import java.util.List; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObj; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.Requests; + +public interface PathComputation { + + Message computePath(Requests req); + + Ero computeEro(EndpointsObj endpoints, Bandwidth bandwidth, ClassType classType, List metrics, + boolean segmentRouting); + +} diff --git a/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PceServerProvider.java b/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PceServerProvider.java new file mode 100644 index 0000000000..ee856c6348 --- /dev/null +++ b/pcep/server/server-api/src/main/java/org/opendaylight/bgpcep/pcep/server/PceServerProvider.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.bgpcep.pcep.server; + +import org.opendaylight.graph.ConnectedGraph; + +public interface PceServerProvider { + + PathComputation getPathComputation(); + + ConnectedGraph getTedGraph(); +} diff --git a/pcep/server/server-provider/pom.xml b/pcep/server/server-provider/pom.xml new file mode 100644 index 0000000000..2dcf64309a --- /dev/null +++ b/pcep/server/server-provider/pom.xml @@ -0,0 +1,77 @@ + + + + + + + 4.0.0 + + org.opendaylight.bgpcep + bgpcep-parent + 0.14.0-SNAPSHOT + ../../../parent + + + pcep-server-provider + PCE Server Provider + bundle + ${project.artifactId} + + + + ${project.groupId} + pcep-server-api + + + ${project.groupId} + graph-api + + + ${project.groupId} + algo-api + + + ${project.groupId} + concepts + + + ${project.groupId} + pcep-api + + + ${project.groupId} + pcep-spi + + + ${project.groupId} + pcep-segment-routing + + + ${project.groupId} + rsvp-api + + + org.opendaylight.yangtools + yang-common + + + org.slf4j + slf4j-api + + + com.google.guava + guava + + + org.opendaylight.mdsal.binding.model.ietf + rfc6991-ietf-inet-types + + + diff --git a/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/MessagesUtil.java b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/MessagesUtil.java new file mode 100644 index 0000000000..1bd44466c8 --- /dev/null +++ b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/MessagesUtil.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.bgpcep.pcep.server.provider; + +import com.google.common.collect.Lists; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.protocol.pcep.spi.PCEPErrors; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ieee754.rev130819.Float32; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ConstrainedPath; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.path.descriptions.PathDescription; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcrep; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcrepBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.SidType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.pcrep.pcrep.message.replies.result.success._case.success.paths.ero.subobject.subobject.type.SrEroType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.pcrep.pcrep.message.replies.result.success._case.success.paths.ero.subobject.subobject.type.SrEroTypeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.IpNodeIdBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.NoPathVectorTlv.Flags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.BandwidthBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassTypeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.ero.Subobject; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.ero.SubobjectBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.MetricsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.metric.object.MetricBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.request.RpsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.PcrepMessageBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.RepliesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.FailureCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.SuccessCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.failure._case.NoPathBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.failure._case.no.path.TlvsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.failure._case.no.path.tlvs.NoPathVectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.success._case.SuccessBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.success._case.success.Paths; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcrep.message.pcrep.message.replies.result.success._case.success.PathsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2p; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.Rp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.ip.prefix._case.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.ip.prefix._case.IpPrefixBuilder; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint8; + +public final class MessagesUtil { + + public static final byte NO_PATH = 0x0; + public static final byte UNKNOWN_SOURCE = 0x1; + public static final byte UNKNOWN_DESTINATION = 0x0; + + /* + * See + * https://www.iana.org/assignments/pcep/pcep.xhtml#metric-object-ni-field + */ + public static final int IGP_METRIC = 1; + public static final int TE_METRIC = 2; + public static final int PATH_DELAY = 12; + + private MessagesUtil() { + throw new UnsupportedOperationException(); + } + + public static Ero getEro(List pathDescriptions) { + /* Prepare ERO */ + final EroBuilder eroBuilder = new EroBuilder(); + eroBuilder.setIgnore(false); + eroBuilder.setProcessingRule(true); + final List eroSubs = new ArrayList<>(); + + /* Fulfill ERO sublist */ + for (PathDescription path : pathDescriptions) { + Subobject sb = null; + if (path.getLabel() == null) { + IpPrefix ipPref = null; + /* Prepare SubObject for IPv4 or IPv6 address */ + if (path.getIpv4() != null) { + final Ipv4Prefix ipv4Pref = new Ipv4Prefix(path.getIpv4().getValue() + "/32"); + ipPref = new IpPrefixBuilder().setIpPrefix( + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715 + .IpPrefix(ipv4Pref)) + .build(); + } + if (path.getIpv6() != null) { + final Ipv6Prefix ipv6Pref = new Ipv6Prefix(path.getIpv6().getValue() + "/128"); + ipPref = new IpPrefixBuilder().setIpPrefix( + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715 + .IpPrefix(ipv6Pref)) + .build(); + } + if (ipPref != null) { + final IpPrefixCase ipPrefCase = new IpPrefixCaseBuilder().setIpPrefix(ipPref).build(); + sb = new SubobjectBuilder().setSubobjectType(ipPrefCase).setLoose(false).build(); + } + } else { + /* Prepare SubObject for Segment Routing */ + SrEroType srEro = null; + if (path.getIpv4() != null) { + srEro = new SrEroTypeBuilder() + .setSidType(SidType.Ipv4NodeId) + .setSid(path.getLabel().getValue()) + .setCFlag(false) + .setMFlag(false) + .setNai(new IpNodeIdBuilder() + .setIpAddress(new IpAddressNoZone(new Ipv4AddressNoZone(path.getIpv4().getValue()))) + .build()) + .build(); + } + if (path.getIpv6() != null) { + srEro = new SrEroTypeBuilder() + .setSidType(SidType.Ipv6NodeId) + .setSid(path.getLabel().getValue()) + .setCFlag(false) + .setMFlag(false) + .setNai(new IpNodeIdBuilder() + .setIpAddress(new IpAddressNoZone(new Ipv6AddressNoZone(path.getIpv6().getValue()))) + .build()) + .build(); + } + if (srEro != null) { + sb = new SubobjectBuilder().setSubobjectType(srEro).setLoose(false).build(); + } + } + + /* Add corresponding SubObject to the ERO List */ + if (sb != null) { + eroSubs.add(sb); + } + } + /* Set ERO sublist */ + eroBuilder.setSubobject(eroSubs); + + return eroBuilder.build(); + } + + private static PathsBuilder buildPath(ConstrainedPath cpath) { + final PathsBuilder pathBuilder = new PathsBuilder(); + + /* Get ERO from Path Description */ + pathBuilder.setEro(getEro(cpath.getPathDescription())); + + /* Fulfill Computed Metrics if available */ + final ArrayList metrics = new ArrayList(); + if (cpath.getMetric() != null) { + final MetricBuilder metricBuilder = new MetricBuilder().setComputed(true) + .setMetricType(Uint8.valueOf(IGP_METRIC)).setValue(new Float32( + ByteBuffer.allocate(4).putFloat(Float.valueOf(cpath.getMetric().floatValue())).array())); + metrics.add(new MetricsBuilder().setMetric(metricBuilder.build()).build()); + } + if (cpath.getTeMetric() != null) { + final MetricBuilder metricBuilder = new MetricBuilder().setComputed(true) + .setMetricType(Uint8.valueOf(TE_METRIC)).setValue(new Float32( + ByteBuffer.allocate(4).putFloat(Float.valueOf(cpath.getTeMetric().floatValue())).array())); + metrics.add(new MetricsBuilder().setMetric(metricBuilder.build()).build()); + } + if (cpath.getDelay() != null) { + final MetricBuilder metricBuilder = new MetricBuilder().setComputed(true) + .setMetricType(Uint8.valueOf(PATH_DELAY)).setValue(new Float32(ByteBuffer.allocate(4) + .putFloat(Float.valueOf(cpath.getDelay().getValue().floatValue())).array())); + metrics.add(new MetricsBuilder().setMetric(metricBuilder.build()).build()); + } + if (!metrics.isEmpty()) { + pathBuilder.setMetrics(metrics); + } + /* Fulfill Bandwidth and ClassType if set */ + if (cpath.getBandwidth() != null) { + final BandwidthBuilder bwBuilder = new BandwidthBuilder(); + bwBuilder.setBandwidth(new Bandwidth(new Float32(ByteBuffer.allocate(4) + .putFloat(Float.valueOf(cpath.getBandwidth().getValue().floatValue())).array()))); + pathBuilder.setBandwidth(bwBuilder.build()); + if (cpath.getClassType() != null) { + pathBuilder.setClassType(new ClassTypeBuilder().setClassType( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109 + .ClassType(cpath.getClassType())) + .build()); + } + } + return pathBuilder; + } + + public static Pcrep createPcRepMessage(Rp rp, P2p p2p, ConstrainedPath cpath) { + + /* Prepare Path Object with ERO and Object from the Request */ + final ArrayList paths = new ArrayList(); + PathsBuilder pathBuilder = buildPath(cpath); + + if (p2p.getLspa() != null) { + pathBuilder.setLspa(p2p.getLspa()); + } + if (p2p.getIro() != null) { + pathBuilder.setIro(p2p.getIro()); + } + if (p2p.getXro() != null) { + pathBuilder.setXro(p2p.getXro()); + } + paths.add(pathBuilder.build()); + + /* Prepare Reply with Path Object */ + final RepliesBuilder replyBuilder = new RepliesBuilder() + .setRp(rp) + .setResult(new SuccessCaseBuilder().setSuccess(new SuccessBuilder().setPaths(paths).build()).build()); + + /* Prepare PcRep Message */ + final PcrepMessageBuilder msgBuilder = new PcrepMessageBuilder() + .setReplies(Lists.newArrayList(replyBuilder.build())); + return new PcrepBuilder().setPcrepMessage(msgBuilder.build()).build(); + } + + public static Pcrep createNoPathMessage(Rp rp, byte reason) { + + /* Prepare NoPath Object */ + final Flags flags = new Flags(false, false, false, false, false, false, + (reason == UNKNOWN_DESTINATION) ? true : false, (reason == UNKNOWN_SOURCE) ? true : false); + final NoPathVectorBuilder npvBuilder = new NoPathVectorBuilder().setFlags(flags); + final TlvsBuilder tlvsBuilder = new TlvsBuilder().setNoPathVector(npvBuilder.build()); + final NoPathBuilder npBuilder = new NoPathBuilder() + .setProcessingRule(false) + .setIgnore(false) + .setNatureOfIssue(Uint8.ZERO) + .setUnsatisfiedConstraints(true) + .setTlvs(tlvsBuilder.build()); + + /* Prepare Reply */ + final RepliesBuilder replyBuilder = new RepliesBuilder() + .setRp(rp) + .setResult(new FailureCaseBuilder().setNoPath(npBuilder.build()).build()); + + /* Prepare PcRep Message */ + final PcrepMessageBuilder msgBuilder = new PcrepMessageBuilder() + .setReplies(Lists.newArrayList(replyBuilder.build())); + return new PcrepBuilder().setPcrepMessage(msgBuilder.build()).build(); + } + + public static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) { + final PcerrMessageBuilder msgBuilder = new PcerrMessageBuilder(); + return new PcerrBuilder().setPcerrMessage(msgBuilder + .setErrorType( + new RequestCaseBuilder().setRequest(new RequestBuilder() + .setRps(Lists + .newArrayList(new RpsBuilder().setRp(new RpBuilder().setProcessingRule(false) + .setIgnore(false).setRequestId(new RequestId(reqID)).build()).build())) + .build()).build()) + .setErrors(Collections.singletonList(new ErrorsBuilder().setErrorObject(new ErrorObjectBuilder() + .setType(pcepErrors.getErrorType()).setValue(pcepErrors.getErrorValue()).build()).build())) + .build()).build(); + } + +} diff --git a/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PathComputationImpl.java b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PathComputationImpl.java new file mode 100644 index 0000000000..af094ec35d --- /dev/null +++ b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PathComputationImpl.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.bgpcep.pcep.server.provider; + +import com.google.common.base.Preconditions; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.util.List; +import org.opendaylight.algo.PathComputationAlgorithm; +import org.opendaylight.algo.PathComputationProvider; +import org.opendaylight.bgpcep.pcep.server.PathComputation; +import org.opendaylight.graph.ConnectedGraph; +import org.opendaylight.graph.ConnectedVertex; +import org.opendaylight.protocol.pcep.spi.PCEPErrors; +import org.opendaylight.protocol.pcep.spi.PSTUtil; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.DecimalBandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Delay; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.AlgorithmType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ComputationStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.ConstrainedPath; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.PathConstraints; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.PathConstraints.AddressFamily; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev200120.get.constrained.path.input.ConstraintsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.classtype.object.ClassType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv4Case; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv6Case; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObj; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.Requests; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq.message.requests.segment.computation.P2p; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint8; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PathComputationImpl implements PathComputation { + + private static final Logger LOG = LoggerFactory.getLogger(PathComputationImpl.class); + + private final ConnectedGraph tedGraph; + private final PathComputationProvider algoProvider; + + public PathComputationImpl(ConnectedGraph tedGraph, PathComputationProvider algoProvider) { + Preconditions.checkArgument(tedGraph != null); + this.tedGraph = tedGraph; + this.algoProvider = algoProvider; + } + + @Override + public Message computePath(Requests req) { + LOG.info("Received Compute Path request"); + + /* Check that Request Parameter Object is present */ + if (req == null || req.getRp() == null) { + LOG.error("Missing Request Parameter Objects. Abort!"); + return MessagesUtil.createErrorMsg(PCEPErrors.RP_MISSING, Uint32.ZERO); + } + + LOG.debug("Request for path computation {}", req); + + /* + * Check that mandatory End Point Objects are present and Source / + * Destination are know in the TED Graph + */ + P2p input = req.getSegmentComputation().getP2p(); + if (input == null || input.getEndpointsObj() == null) { + LOG.error("Missing End Point Objects. Abort!"); + Uint32 reqID = req.getRp().getRequestId().getValue(); + return MessagesUtil.createErrorMsg(PCEPErrors.END_POINTS_MISSING, reqID); + } + VertexKey source = getSourceVertexKey(input.getEndpointsObj()); + VertexKey destination = getDestinationVertexKey(input.getEndpointsObj()); + if (source == null) { + return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_SOURCE); + } + if (destination == null) { + return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.UNKNOWN_DESTINATION); + } + + /* Create new Constraints Object from the request */ + PathConstraints cts = getConstraints(input, !PSTUtil.isDefaultPST(req.getRp().getTlvs().getPathSetupType())); + + /* Determine Path Computation Algorithm according to Input choice */ + AlgorithmType algoType; + if ((cts.getTeMetric() == null) && (cts.getDelay() == null)) { + algoType = AlgorithmType.Spf; + } else if (cts.getDelay() == null) { + algoType = AlgorithmType.Cspf; + } else { + algoType = AlgorithmType.Samcra; + } + PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType); + if (algo == null) { + return MessagesUtil.createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO); + } + + /* Request Path Computation for given source, destination and constraints */ + LOG.debug("Call Path Computation {} algorithm for path from {} to {} with contraints {}", + algoType, source, destination, cts); + final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts); + + LOG.info("Computed path: {}", cpath.getPathDescription()); + + /* Check if we got a valid Path and return appropriate message */ + if (cpath.getStatus() == ComputationStatus.Completed) { + return MessagesUtil.createPcRepMessage(req.getRp(), req.getSegmentComputation().getP2p(), cpath); + } else { + return MessagesUtil.createNoPathMessage(req.getRp(), MessagesUtil.NO_PATH); + } + } + + @Override + public Ero computeEro(EndpointsObj endpoints, Bandwidth bandwidth, ClassType classType, List metrics, + boolean segmentRouting) { + VertexKey source = getSourceVertexKey(endpoints); + VertexKey destination = getDestinationVertexKey(endpoints); + if (source == null) { + return null; + } + if (destination == null) { + return null; + } + /* Create new Constraints Object from the request */ + PathConstraints cts = getConstraints(endpoints, bandwidth, classType, metrics, segmentRouting); + + /* Determine Path Computation Algorithm according to parameters */ + AlgorithmType algoType; + if ((cts.getTeMetric() == null) && (cts.getDelay() == null) && (cts.getBandwidth() == null)) { + algoType = AlgorithmType.Spf; + } else if (cts.getDelay() == null) { + algoType = AlgorithmType.Cspf; + } else { + algoType = AlgorithmType.Samcra; + } + PathComputationAlgorithm algo = algoProvider.getPathComputationAlgorithm(tedGraph, algoType); + if (algo == null) { + return null; + } + + /* + * Request Path Computation for given source, destination and + * constraints + */ + final ConstrainedPath cpath = algo.computeP2pPath(source, destination, cts); + + LOG.info("Computed ERO: {}", cpath.getPathDescription()); + + /* Check if we got a valid Path and return appropriate ERO */ + if (cpath.getStatus() == ComputationStatus.Completed) { + return MessagesUtil.getEro(cpath.getPathDescription()); + } else { + return null; + } + } + + private VertexKey getSourceVertexKey(EndpointsObj endPoints) { + IpAddress address = null; + + if (endPoints.getAddressFamily() instanceof Ipv4Case) { + address = new IpAddress(((Ipv4Case) endPoints.getAddressFamily()).getIpv4().getSourceIpv4Address()); + } + if (endPoints.getAddressFamily() instanceof Ipv6Case) { + address = new IpAddress(((Ipv6Case) endPoints.getAddressFamily()).getIpv6().getSourceIpv6Address()); + } + if (address == null) { + return null; + } + + ConnectedVertex vertex = tedGraph.getConnectedVertex(address); + LOG.debug("Compute path from Source {}", vertex.toString()); + return (vertex != null) ? vertex.getVertex().key() : null; + } + + private VertexKey getDestinationVertexKey(EndpointsObj endPoints) { + IpAddress address = null; + + if (endPoints.getAddressFamily() instanceof Ipv4Case) { + address = new IpAddress(((Ipv4Case) endPoints.getAddressFamily()).getIpv4().getDestinationIpv4Address()); + } + if (endPoints.getAddressFamily() instanceof Ipv6Case) { + address = new IpAddress(((Ipv6Case) endPoints.getAddressFamily()).getIpv6().getDestinationIpv6Address()); + } + if (address == null) { + return null; + } + + ConnectedVertex vertex = tedGraph.getConnectedVertex(address); + LOG.debug("Compute path to Destination {}", vertex.toString()); + return (vertex != null) ? vertex.getVertex().key() : null; + } + + private PathConstraints getConstraints(P2p parameters, boolean segmentRouting) { + return getConstraints(parameters.getEndpointsObj(), parameters.getBandwidth(), parameters.getClassType(), + parameters.getMetrics(), segmentRouting); + } + + private PathConstraints getConstraints(EndpointsObj endpoints, Bandwidth bandwidth, ClassType classType, + List metrics, boolean segmentRouting) { + ConstraintsBuilder ctsBuilder = new ConstraintsBuilder(); + Float convert; + + /* Set Metrics if any */ + if (metrics != null) { + for (Metrics metric : metrics) { + convert = ByteBuffer.wrap(metric.getMetric().getValue().getValue()).getFloat(); + switch (metric.getMetric().getMetricType().intValue()) { + case MessagesUtil.IGP_METRIC: + ctsBuilder.setMetric(Uint32.valueOf(convert.longValue())); + break; + case MessagesUtil.TE_METRIC: + ctsBuilder.setTeMetric(Uint32.valueOf(convert.longValue())); + break; + case MessagesUtil.PATH_DELAY: + ctsBuilder.setDelay(new Delay(Uint32.valueOf(convert.longValue()))); + break; + default: + LOG.warn("Metric {} is not handle by Path Computation Constraints", metric); + break; + } + } + } + + /* Set Bandwidth and Class Type */ + if (bandwidth != null) { + convert = ByteBuffer.wrap(bandwidth.getBandwidth().getValue()).getFloat(); + ctsBuilder.setBandwidth(new DecimalBandwidth(BigDecimal.valueOf(convert.longValue()))); + if (classType != null) { + ctsBuilder.setClassType(classType.getClassType().getValue()); + } else { + ctsBuilder.setClassType(Uint8.ZERO); + } + } + + /* Set Address Family */ + if (endpoints.getAddressFamily() instanceof Ipv4Case) { + if (segmentRouting) { + ctsBuilder.setAddressFamily(AddressFamily.SrIpv4); + } else { + ctsBuilder.setAddressFamily(AddressFamily.Ipv4); + } + } else { + if (segmentRouting) { + ctsBuilder.setAddressFamily(AddressFamily.SrIpv6); + } else { + ctsBuilder.setAddressFamily(AddressFamily.Ipv6); + } + } + + return ctsBuilder.build(); + } +} diff --git a/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PceServerFactory.java b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PceServerFactory.java new file mode 100644 index 0000000000..813a6a4abe --- /dev/null +++ b/pcep/server/server-provider/src/main/java/org/opendaylight/bgpcep/pcep/server/provider/PceServerFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Orange. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.bgpcep.pcep.server.provider; + +import com.google.common.base.Preconditions; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.algo.PathComputationProvider; +import org.opendaylight.bgpcep.pcep.server.PceServerProvider; +import org.opendaylight.graph.ConnectedGraph; +import org.opendaylight.graph.ConnectedGraphProvider; + +public class PceServerFactory implements PceServerProvider { + + private final ConnectedGraphProvider graphProvider; + private final PathComputationProvider algoProvider; + private ConnectedGraph tedGraph = null; + + public PceServerFactory(ConnectedGraphProvider graphProvider, PathComputationProvider pathComputationProvider) { + Preconditions.checkArgument(graphProvider != null); + this.graphProvider = graphProvider; + this.algoProvider = pathComputationProvider; + setTedGraph(); + } + + /** + * Set Traffic Engineering Graph. This method is necessary as the TedGraph could be available + * after the PathComputationFactory start e.g. manual insertion of a ted Graph, or late tedGraph fulfillment + * from BGP Link State. + */ + private void setTedGraph() { + for (ConnectedGraph cgraph : this.graphProvider.getConnectedGraphs()) { + if (cgraph.getGraph().getName().startsWith("ted://")) { + this.tedGraph = cgraph; + break; + } + } + } + + @Override + public PathComputationImpl getPathComputation() { + /* Leave a change to get a valid Graph */ + if (tedGraph == null) { + setTedGraph(); + } + return new PathComputationImpl(tedGraph, algoProvider); + } + + @Override + public @Nullable ConnectedGraph getTedGraph() { + /* Leave a change to get a valid Graph in case of late fulfillment */ + if (tedGraph == null) { + setTedGraph(); + } + return this.tedGraph; + } +} diff --git a/pcep/server/server-provider/src/main/resources/OSGI-INF/blueprint/pce-server.xml b/pcep/server/server-provider/src/main/resources/OSGI-INF/blueprint/pce-server.xml new file mode 100644 index 0000000000..a4f5962c9d --- /dev/null +++ b/pcep/server/server-provider/src/main/resources/OSGI-INF/blueprint/pce-server.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/pcep/topology/topology-provider/pom.xml b/pcep/topology/topology-provider/pom.xml index d04f475cda..b6e03187f0 100644 --- a/pcep/topology/topology-provider/pom.xml +++ b/pcep/topology/topology-provider/pom.xml @@ -41,6 +41,10 @@ ${project.groupId} pcep-topology-spi + + ${project.groupId} + pcep-server-api + ${project.groupId} programming-api diff --git a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java index 487e867894..dd96a7917b 100644 --- a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java +++ b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java @@ -275,4 +275,8 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, Topology PCEPDispatcherDependencies getPCEPDispatcherDependencies() { return this.pcepDispatcherDependencies; } + + PCEPTopologyProviderDependencies getPCEPTopologyProviderDependencies() { + return this.dependenciesProvider; + } } \ No newline at end of file diff --git a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListener.java b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListener.java index 3129288287..a4fbe85ce3 100644 --- a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListener.java +++ b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListener.java @@ -28,6 +28,8 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.checkerframework.checker.lock.qual.GuardedBy; +import org.opendaylight.bgpcep.pcep.server.PathComputation; +import org.opendaylight.bgpcep.pcep.server.PceServerProvider; import org.opendaylight.protocol.pcep.PCEPSession; import org.opendaylight.protocol.pcep.spi.PCEPErrors; import org.opendaylight.protocol.pcep.spi.PSTUtil; @@ -69,11 +71,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.iet import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.srp.object.SrpBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.stateful.capability.tlv.Stateful; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.symbolic.path.name.tlv.SymbolicPathNameBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.PcerrMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspArgs; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId; @@ -109,11 +113,14 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener< private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false); private final AtomicBoolean initiationCapability = new AtomicBoolean(false); + private PceServerProvider pceServerProvider; + /** * Creates a new stateful topology session listener for given server session manager. */ Stateful07TopologySessionListener(final ServerSessionManager serverSessionManager) { super(serverSessionManager); + this.pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider(); } private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) { @@ -364,11 +371,37 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener< return pb.build(); } + private boolean handlePcreqMessage(final PcreqMessage message) { + + LOG.info("Start PcRequest Message handler"); + + /* Get a Path Computation to compute the Path from the Request */ + PathComputation pathComputation = this.pceServerProvider.getPathComputation(); + Message rep = null; + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq + .message.Requests req : message.getRequests()) { + LOG.debug("Process request {}", req); + rep = pathComputation.computePath(req); + SrpIdNumber repId = null; + if (req.getRp() != null) { + repId = new SrpIdNumber(req.getRp().getRequestId().getValue()); + } else { + repId = new SrpIdNumber(Uint32.ZERO); + } + sendMessage(rep, repId, null); + } + return false; + } + @Override protected synchronized boolean onMessage(final MessageContext ctx, final Message message) { if (message instanceof PcerrMessage) { return handleErrorMessage((PcerrMessage) message); } + if (message instanceof Pcreq) { + LOG.info("PcReq detected. Start Request Message handler"); + return handlePcreqMessage(((Pcreq) message).getPcreqMessage()); + } if (!(message instanceof PcrptMessage)) { return true; } @@ -714,14 +747,28 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener< // Build the request final RequestsBuilder rb = new RequestsBuilder(); - final Arguments2 args = this.input.getArguments().augmentation(Arguments2.class); - final Lsp inputLsp = args != null ? args.getLsp() : null; + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120 + .add.lsp.args.Arguments args = this.input.getArguments(); + final Arguments2 args2 = args.augmentation(Arguments2.class); + final Lsp inputLsp = args2 != null ? args2.getLsp() : null; if (inputLsp == null) { return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future(); } rb.fieldsFrom(this.input.getArguments()); + /* Call Path Computation if an ERO was not provided */ + boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType()); + if ((rb.getEro() == null) + || (rb.getEro().getSubobject() == null) + || (rb.getEro().getSubobject().size() == 0)) { + + /* Get a Path Computation to compute the Path from the Arguments */ + PathComputation pathComputation = pceServerProvider.getPathComputation(); + rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(), args.getClassType(), + args.getMetrics(), segmentRouting)); + } + final TlvsBuilder tlvsBuilder; if (inputLsp.getTlvs() != null) { tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs()); @@ -735,11 +782,11 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener< final SrpBuilder srpBuilder = new SrpBuilder() .setOperationId(nextRequest()) .setProcessingRule(Boolean.TRUE); - if (!PSTUtil.isDefaultPST(args.getPathSetupType())) { + if (segmentRouting) { srpBuilder.setTlvs( new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf .stateful.rev181109.srp.object.srp.TlvsBuilder() - .setPathSetupType(args.getPathSetupType()).build()); + .setPathSetupType(args2.getPathSetupType()).build()); } rb.setSrp(srpBuilder.build()); diff --git a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderBean.java b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderBean.java index b38582dc9e..df0ac55ef5 100644 --- a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderBean.java +++ b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderBean.java @@ -15,6 +15,7 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; import org.checkerframework.checker.lock.qual.GuardedBy; +import org.opendaylight.bgpcep.pcep.server.PceServerProvider; import org.opendaylight.bgpcep.pcep.topology.provider.PCEPTopologyProvider; import org.opendaylight.bgpcep.pcep.topology.provider.TopologySessionListenerFactory; import org.opendaylight.bgpcep.pcep.topology.spi.stats.TopologySessionStatsRegistry; @@ -46,6 +47,7 @@ public final class PCEPTopologyProviderBean implements PCEPTopologyProviderDepen private final BundleContext bundleContext; private final ClusterSingletonServiceProvider cssp; private final TopologySessionStatsRegistry stateRegistry; + private final PceServerProvider pceServerProvider; @GuardedBy("this") private PCEPTopologyProviderBeanCSS pcepTopoProviderCSS; @@ -56,7 +58,8 @@ public final class PCEPTopologyProviderBean implements PCEPTopologyProviderDepen final PCEPDispatcher pcepDispatcher, final RpcProviderService rpcProviderRegistry, final TopologySessionListenerFactory sessionListenerFactory, - final TopologySessionStatsRegistry stateRegistry) { + final TopologySessionStatsRegistry stateRegistry, + final PceServerProvider pceServerProvider) { this.cssp = requireNonNull(cssp); this.bundleContext = requireNonNull(bundleContext); this.pcepDispatcher = requireNonNull(pcepDispatcher); @@ -64,6 +67,7 @@ public final class PCEPTopologyProviderBean implements PCEPTopologyProviderDepen this.sessionListenerFactory = requireNonNull(sessionListenerFactory); this.rpcProviderRegistry = requireNonNull(rpcProviderRegistry); this.stateRegistry = requireNonNull(stateRegistry); + this.pceServerProvider = requireNonNull(pceServerProvider); final List capabilities = this.pcepDispatcher.getPCEPSessionNegotiatorFactory() .getPCEPSessionProposalFactory().getCapabilities(); final boolean statefulCapability = capabilities.stream().anyMatch(PCEPCapability::isStateful); @@ -125,6 +129,11 @@ public final class PCEPTopologyProviderBean implements PCEPTopologyProviderDepen return this.stateRegistry; } + @Override + public PceServerProvider getPceServerProvider() { + return this.pceServerProvider; + } + private static class PCEPTopologyProviderBeanCSS implements ClusterSingletonService, AutoCloseable { private final ServiceGroupIdentifier sgi; private final PCEPTopologyProvider pcepTopoProvider; diff --git a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderDependencies.java b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderDependencies.java index ad090a6550..24e87c70bf 100644 --- a/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderDependencies.java +++ b/pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderDependencies.java @@ -9,6 +9,7 @@ package org.opendaylight.bgpcep.pcep.topology.provider.config; import com.google.common.annotations.Beta; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.bgpcep.pcep.server.PceServerProvider; import org.opendaylight.bgpcep.pcep.topology.provider.TopologySessionListenerFactory; import org.opendaylight.bgpcep.pcep.topology.spi.stats.TopologySessionStatsRegistry; import org.opendaylight.mdsal.binding.api.DataBroker; @@ -55,4 +56,11 @@ public interface PCEPTopologyProviderDependencies { * @return TopologySessionStateRegistry */ TopologySessionStatsRegistry getStateRegistry(); + + /** + * PCE Server Provider. + * + * @return PceServerProvider + */ + PceServerProvider getPceServerProvider(); } diff --git a/pcep/topology/topology-provider/src/main/resources/OSGI-INF/blueprint/pcep-topology.xml b/pcep/topology/topology-provider/src/main/resources/OSGI-INF/blueprint/pcep-topology.xml index f6157fbe83..b67b66b825 100644 --- a/pcep/topology/topology-provider/src/main/resources/OSGI-INF/blueprint/pcep-topology.xml +++ b/pcep/topology/topology-provider/src/main/resources/OSGI-INF/blueprint/pcep-topology.xml @@ -13,7 +13,7 @@ class="org.opendaylight.bgpcep.pcep.topology.provider.Stateful07TopologySessionListenerFactory"/> - + @@ -23,6 +23,7 @@ + + diff --git a/pcep/topology/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractPCEPSessionTest.java b/pcep/topology/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractPCEPSessionTest.java index 8a97d8e7aa..da820dc03b 100644 --- a/pcep/topology/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractPCEPSessionTest.java +++ b/pcep/topology/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractPCEPSessionTest.java @@ -153,6 +153,7 @@ public abstract class AbstractPCEPSessionTestutil + graph bgp bmp - graph algo pcep programming -- 2.36.6