Bump upstreams
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / ManagedTePath.java
index d3fb941dc02a52b199200ddfa16661db04760acd..a3f22345d57cbfaadc022765167952692a3baa9b 100644 (file)
@@ -17,30 +17,39 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.nio.ByteBuffer;
 import java.util.Collections;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.graph.ConnectedEdge;
+import org.opendaylight.graph.ConnectedEdgeTrigger;
 import org.opendaylight.graph.ConnectedGraph;
+import org.opendaylight.graph.ConnectedVertex;
+import org.opendaylight.graph.ConnectedVertexTrigger;
 import org.opendaylight.mdsal.binding.api.WriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 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.Ipv4AddressNoZone;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.edge.attributes.UnreservedBandwidth;
 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.network.topology.rev140113.NetworkTopologyRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220310.AddressFamily;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220310.ComputationStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220310.path.descriptions.PathDescription;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ComputationStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.descriptions.PathDescription;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments2Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments3Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.LspBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.PathComputationClient1;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.PathStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.PathType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.pcc.configured.lsp.ConfiguredLsp;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.pcc.configured.lsp.ConfiguredLspBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.pcc.configured.lsp.configured.lsp.IntendedPath;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev210720.pcc.configured.lsp.configured.lsp.intended.path.Constraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathComputationClient1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.intended.path.Constraints;
 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.endpoints.address.family.Ipv4CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv6CaseBuilder;
@@ -50,19 +59,21 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
 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.path.setup.type.tlv.PathSetupTypeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.NetworkTopologyPcepService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.add.lsp.args.ArgumentsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.add.lsp.args.ArgumentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClient;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -74,41 +85,43 @@ import org.opendaylight.yangtools.yang.common.Uint8;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ManagedTePath {
+public class ManagedTePath implements ConnectedEdgeTrigger, ConnectedVertexTrigger {
 
     private ConfiguredLsp cfgLsp = null;
     private ConfiguredLsp prevLsp = null;
     private final ManagedTeNode teNode;
     private boolean sent = false;
+    private boolean triggerFlag = false;
     private PathType type = PathType.Pcc;
     private final InstanceIdentifier<Topology> pcepTopology;
     private final InstanceIdentifier<PathComputationClient1> pccIdentifier;
 
     private static final Logger LOG = LoggerFactory.getLogger(ManagedTePath.class);
 
-    public ManagedTePath(ManagedTeNode teNode, InstanceIdentifier<Topology> topology) {
+    public ManagedTePath(final ManagedTeNode teNode, final InstanceIdentifier<Topology> topology) {
         this.teNode = requireNonNull(teNode);
-        this.pcepTopology = requireNonNull(topology);
-        this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
+        pcepTopology = requireNonNull(topology);
+        pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
     }
 
-    public ManagedTePath(ManagedTeNode teNode, final ConfiguredLsp lsp, InstanceIdentifier<Topology> topology) {
-        this.cfgLsp = requireNonNull(lsp);
+    public ManagedTePath(final ManagedTeNode teNode, final ConfiguredLsp lsp,
+            final InstanceIdentifier<Topology> topology) {
+        cfgLsp = requireNonNull(lsp);
         this.teNode = requireNonNull(teNode);
-        this.pcepTopology = requireNonNull(topology);
-        this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
+        pcepTopology = requireNonNull(topology);
+        pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
     }
 
-    public ManagedTePath(ManagedTeNode teNode, final ManagedTePath mngPath) {
+    public ManagedTePath(final ManagedTeNode teNode, final ManagedTePath mngPath) {
         checkArgument(mngPath != null, "Managed TE Path is mandatory. Can't be null or empty!");
-        this.cfgLsp = mngPath.getLsp();
-        this.sent = mngPath.isSent();
-        this.type = mngPath.getType();
+        cfgLsp = mngPath.getLsp();
+        sent = mngPath.isSent();
+        type = mngPath.getType();
         this.teNode = requireNonNull(teNode);
-        this.pcepTopology = mngPath.getTopology();
-        this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
+        pcepTopology = mngPath.getTopology();
+        pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
     }
 
@@ -129,12 +142,12 @@ public class ManagedTePath {
     }
 
     public ManagedTePath setConfiguredLsp(final ConfiguredLsp lsp) {
-        this.prevLsp = this.cfgLsp;
-        this.cfgLsp = lsp;
+        prevLsp = cfgLsp;
+        cfgLsp = lsp;
         return this;
     }
 
-    public ManagedTePath setType(PathType type) {
+    public ManagedTePath setType(final PathType type) {
         this.type = type;
         return this;
     }
@@ -144,7 +157,7 @@ public class ManagedTePath {
      *
      */
     public void sync() {
-        this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Sync).build();
+        cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Sync).build();
         updateToDataStore();
     }
 
@@ -152,14 +165,14 @@ public class ManagedTePath {
      * Disabling this TE Path by marking it as Configured. Do not update the Data Store.
      */
     public void disabled() {
-        this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Configured).build();
+        cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Configured).build();
     }
 
     /**
      * Mark this TE Path as Failed.
      */
     public void failed() {
-        this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Failed).build();
+        cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Failed).build();
         updateToDataStore();
     }
 
@@ -226,29 +239,26 @@ public class ManagedTePath {
         return PathStatus.Sync;
     }
 
-    public void addBandwidth(ConnectedGraph graph) {
+    private void configureGraph(final ConnectedGraph graph, final ComputedPath cpath, final Constraints cts,
+            final boolean config) {
         /* Check that Connected Graph is valid */
         if (graph == null) {
             return;
         }
+
         /* Verify that we have a valid Computed Path and that the LSP is in SYNC */
-        if (cfgLsp.getComputedPath().getComputationStatus() != ComputationStatus.Completed
-                || cfgLsp.getPathStatus() != PathStatus.Sync) {
-            return;
-        }
-        /* Verify that a Bandwidth has been requested and reserved */
-        if (cfgLsp.getIntendedPath().getConstraints().getBandwidth() == null) {
+        if (cpath.getComputationStatus() != ComputationStatus.Completed || cfgLsp.getPathStatus() != PathStatus.Sync) {
             return;
         }
 
-        /* Loop the path description to add reserved bandwidth for this LSP */
-        final Long bw = cfgLsp.getIntendedPath().getConstraints().getBandwidth().getValue().longValue();
-        int cos = cfgLsp.getIntendedPath().getConstraints().getClassType() != null
-                ? cfgLsp.getIntendedPath().getConstraints().getClassType().intValue()
-                : 0;
-        final AddressFamily af = cfgLsp.getIntendedPath().getConstraints().getAddressFamily();
-        for (PathDescription path : cfgLsp.getComputedPath().getPathDescription()) {
-            ConnectedEdge edge = null;
+        /* Loop the path description to add reserved bandwidth and triggers for this LSP */
+        final Long bw = cts.getBandwidth() == null ? 0L : cts.getBandwidth().getValue().longValue();
+        int cos = cts.getClassType() == null ? 0 : cts.getClassType().intValue();
+        final AddressFamily af = cts.getAddressFamily();
+        final String lspId = teNode.getId().getValue() + "/" + cfgLsp.getName();
+        ConnectedEdge edge = null;
+        for (PathDescription path : cpath.getPathDescription()) {
+            edge = null;
             switch (af) {
                 case Ipv4:
                 case SrIpv4:
@@ -256,7 +266,7 @@ public class ManagedTePath {
                         edge = graph.getConnectedEdge(new IpAddress(path.getIpv4()));
                     } else if (path.getRemoteIpv4() != null) {
                         edge = graph.getConnectedEdge(new IpAddress(path.getRemoteIpv4()));
-                        if (edge != null) {
+                        if (edgeAttrNotNull(edge)) {
                             edge = graph.getConnectedEdge(edge.getEdge().getEdgeAttributes().getRemoteAddress());
                         }
                     }
@@ -267,98 +277,215 @@ public class ManagedTePath {
                         edge = graph.getConnectedEdge(new IpAddress(path.getIpv6()));
                     } else if (path.getRemoteIpv6() != null) {
                         edge = graph.getConnectedEdge(new IpAddress(path.getRemoteIpv6()));
-                        if (edge != null) {
+                        if (edgeAttrNotNull(edge)) {
                             /* Need to force using IPv6 address as Connected Edge is searched first on IPv4 address */
                             edge = graph.getConnectedEdge(new IpAddress(
-                                    edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv6Address()));
+                                    edge.getEdge().getEdgeAttributes().getRemoteAddress6()));
                         }
                     }
                     break;
                 default:
                     break;
             }
-            if (edge != null) {
-                edge.addBandwidth(bw, cos);
+
+            if (edge == null) {
+                continue;
+            }
+
+            if (config) {
+                if (bw != 0L) {
+                    edge.addBandwidth(bw, cos);
+                }
+                edge.registerTrigger(this, lspId);
+                if (edge.getSource() != null) {
+                    edge.getSource().registerTrigger(this, lspId);
+                }
+            } else {
+                if (bw != 0L) {
+                    edge.delBandwidth(bw, cos);
+                }
+                edge.unRegisterTrigger(this, lspId);
+                if (edge.getSource() != null) {
+                    edge.getSource().unRegisterTrigger(this, lspId);
+                }
+            }
+        }
+        if (edge != null && edge.getDestination() != null) {
+            if (config) {
+                edge.getDestination().registerTrigger(this, lspId);
+            } else {
+                edge.getDestination().unRegisterTrigger(this, lspId);
             }
         }
+
+        /* Finally, reset Trigger Flag to activate them */
+        triggerFlag = false;
     }
 
-    public void delBandwidth(ConnectedGraph graph) {
-        /* Check that Connected Graph is valid */
-        if (graph == null) {
-            return;
+    private static boolean edgeAttrNotNull(final ConnectedEdge edge) {
+        return edge != null && edge.getEdge() != null && edge.getEdge().getEdgeAttributes() != null;
+    }
+
+    public void setGraph(final ConnectedGraph graph) {
+        configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), true);
+    }
+
+    public void unsetGraph(final ConnectedGraph graph) {
+        configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), false);
+    }
+
+    public void updateGraph(final ConnectedGraph graph) {
+        /* First unset Bandwidth and Triggers for the old path if any */
+        if (prevLsp != null) {
+            configureGraph(graph, prevLsp.getComputedPath(), prevLsp.getIntendedPath().getConstraints(), false);
         }
-        /* Verify that we have a valid Computed Path and that the LSP is in SYNC */
-        if (cfgLsp.getComputedPath().getComputationStatus() != ComputationStatus.Completed
-                || cfgLsp.getPathStatus() != PathStatus.Sync) {
-            return;
+
+        /* Then add Bandwidth and Triggers for the current path */
+        configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), true);
+
+        /* And memorize current LSP for latter update */
+        prevLsp = cfgLsp;
+    }
+
+    /**
+     * Reset Triggered Flag.
+     */
+    public void unSetTriggerFlag() {
+        triggerFlag = false;
+    }
+
+    @Override
+    public boolean verifyVertex(final ConnectedVertex next, final Vertex current) {
+        /* Check if there is an on-going trigger */
+        if (triggerFlag) {
+            return false;
         }
-        /* Verify that a Bandwidth has been requested and reserved */
-        if (cfgLsp.getIntendedPath().getConstraints().getBandwidth() == null) {
-            return;
+
+        /* Check if Vertex has been removed */
+        Vertex vertex = next.getVertex();
+        if (vertex == null) {
+            triggerFlag = true;
+            return true;
         }
 
-        /* Loop the path description to delete reserved bandwidth for this LSP */
-        final Long bw = cfgLsp.getIntendedPath().getConstraints().getBandwidth().getValue().longValue();
-        int cos = cfgLsp.getIntendedPath().getConstraints().getClassType() != null
-                ? cfgLsp.getIntendedPath().getConstraints().getClassType().intValue()
-                : 0;
+        /* Check if Vertex changed its Segment Routing Global Block */
         final AddressFamily af = cfgLsp.getIntendedPath().getConstraints().getAddressFamily();
-        for (PathDescription path : cfgLsp.getComputedPath().getPathDescription()) {
-            ConnectedEdge edge = null;
-            switch (af) {
-                case Ipv4:
-                case SrIpv4:
-                    edge = graph.getConnectedEdge(new IpAddress(path.getIpv4()));
-                    break;
-                case Ipv6:
-                case SrIpv6:
-                    edge = graph.getConnectedEdge(new IpAddress(path.getIpv6()));
-                    break;
-                default:
-                    break;
-            }
-            if (edge != null) {
-                edge.delBandwidth(bw, cos);
-            }
+        if ((af == AddressFamily.SrIpv4 || af == AddressFamily.SrIpv6) && !current.getSrgb().equals(vertex.getSrgb())) {
+            LOG.debug("Vertex {} modified its SRGB {} / {}", vertex.getName(), current.getSrgb(), vertex.getSrgb());
+            triggerFlag = true;
+            return true;
         }
+
+        /* All is fine */
+        triggerFlag = false;
+        return false;
     }
 
-    public void updateBandwidth(ConnectedGraph graph) {
-        /* Check that Connected Graph is valid */
-        if (graph == null) {
-            return;
+    @Override
+    public boolean verifyEdge(final ConnectedEdge next, final Edge current) {
+        /* Check if there is an on-going trigger */
+        if (triggerFlag) {
+            return false;
+        }
+
+        /* Check if Edge or Attributes has been removed */
+        Edge edge = next.getEdge();
+        if (edge == null || edge.getEdgeAttributes() == null) {
+            triggerFlag = true;
+            return true;
+        }
+
+        /* Check that Configured LSP has valid constraints */
+        final Constraints constraints = cfgLsp.getIntendedPath().getConstraints();
+        if (constraints == null) {
+            return false;
+        }
+
+        /* Check if Metric is always met */
+        Long metric = 0L;
+        Long delta = 0L;
+        if (constraints.getDelay() != null) {
+            if (edge.getEdgeAttributes().getDelay() != null) {
+                metric = constraints.getDelay().getValue().longValue();
+                delta = edge.getEdgeAttributes().getDelay().getValue().longValue()
+                        - current.getEdgeAttributes().getDelay().getValue().longValue();
+            } else {
+                triggerFlag = true;
+                return true;
+            }
         }
-        /* First remove Bandwidth for the old path if any */
-        if (prevLsp != null && prevLsp.getIntendedPath().getConstraints().getBandwidth() != null) {
-            final Long bw = prevLsp.getIntendedPath().getConstraints().getBandwidth().getValue().longValue();
-            int cos = prevLsp.getIntendedPath().getConstraints().getClassType() != null
-                    ? prevLsp.getIntendedPath().getConstraints().getClassType().intValue()
-                    : 0;
-            final AddressFamily af = prevLsp.getIntendedPath().getConstraints().getAddressFamily();
-            for (PathDescription path : prevLsp.getComputedPath().getPathDescription()) {
-                ConnectedEdge edge = null;
-                switch (af) {
-                    case Ipv4:
-                    case SrIpv4:
-                        edge = graph.getConnectedEdge(new IpAddress(path.getIpv4()));
-                        break;
-                    case Ipv6:
-                    case SrIpv6:
-                        edge = graph.getConnectedEdge(new IpAddress(path.getIpv6()));
-                        break;
-                    default:
-                        break;
-                }
-                if (edge != null) {
-                    edge.delBandwidth(bw, cos);
+        if (constraints.getTeMetric() != null) {
+            if (edge.getEdgeAttributes().getTeMetric() != null) {
+                metric = constraints.getTeMetric().longValue();
+                delta = edge.getEdgeAttributes().getTeMetric().longValue()
+                        - current.getEdgeAttributes().getTeMetric().longValue();
+            } else {
+                triggerFlag = true;
+                return true;
+            }
+        } else if (constraints.getMetric() != null) {
+            if (edge.getEdgeAttributes().getMetric() != null) {
+                metric = constraints.getMetric().longValue();
+                delta = edge.getEdgeAttributes().getMetric().longValue()
+                        - current.getEdgeAttributes().getMetric().longValue();
+            } else {
+                triggerFlag = true;
+                return true;
+            }
+        }
+        if (metric != 0L && cfgLsp.getComputedPath().getComputedMetric() != null
+                && cfgLsp.getComputedPath().getComputedMetric().longValue() + delta > metric) {
+            LOG.debug("Following an update on Edge {} Metric is no longer guaranteed: {} / {}",
+                    edge.getName(),
+                    cfgLsp.getComputedPath().getComputedMetric().longValue() + delta,
+                    metric);
+            triggerFlag = true;
+            return true;
+        }
+
+        /* Check if Bandwidth is always met */
+        if (constraints.getBandwidth() != null) {
+            if (edge.getEdgeAttributes().getMaxLinkBandwidth() == null
+                    || edge.getEdgeAttributes().getMaxResvLinkBandwidth() == null
+                    || edge.getEdgeAttributes().getUnreservedBandwidth() == null) {
+                triggerFlag = true;
+                return true;
+            }
+            Long bandwidth = constraints.getBandwidth().getValue().longValue();
+            Long unrsv = 0L;
+            int cos = 0;
+            for (UnreservedBandwidth unResBw : edge.getEdgeAttributes().getUnreservedBandwidth()) {
+                if (unResBw.getClassType().intValue() == cos) {
+                    unrsv = unResBw.getBandwidth().getValue().longValue();
+                    break;
                 }
             }
+            Long maxBW = edge.getEdgeAttributes().getMaxLinkBandwidth().getValue().longValue();
+            if (bandwidth > List.of(
+                    unrsv,
+                    /* maxBW might be on the list but will always be greater than the next items */
+                    maxBW - next.getCosResvBandwidth(cos),
+                    maxBW - next.getGlobalResvBandwidth(),
+                    edge.getEdgeAttributes().getMaxResvLinkBandwidth().getValue().longValue())
+                    .stream().mapToLong(v -> v)
+                    .min().getAsLong()
+            ) {
+                LOG.debug("Following an update on Edge {}, Reserved bandwidth is no longer guaranteed", edge.getName());
+                triggerFlag = true;
+                return true;
+            }
         }
-        /* Then add Bandwidth for the current path */
-        addBandwidth(graph);
-        /* And memorize current LSP for latter update */
-        prevLsp = cfgLsp;
+
+        /* Check if Edge changed its Adjacency SID */
+        final AddressFamily af = cfgLsp.getIntendedPath().getConstraints().getAddressFamily();
+        if ((af == AddressFamily.SrIpv4 || af == AddressFamily.SrIpv6)
+                && !current.getEdgeAttributes().getAdjSid().equals(edge.getEdgeAttributes().getAdjSid())) {
+            LOG.debug("Edge {} has modified its Adjacency SID", edge.getName());
+            triggerFlag = true;
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -376,12 +503,12 @@ public class ManagedTePath {
             final Ipv4Builder ipBuilder = new Ipv4Builder()
                     .setDestinationIpv4Address(new Ipv4AddressNoZone(iPath.getDestination().getIpv4Address()))
                     .setSourceIpv4Address(new Ipv4AddressNoZone(iPath.getSource().getIpv4Address()));
-            epb.setAddressFamily((new Ipv4CaseBuilder().setIpv4(ipBuilder.build()).build()));
+            epb.setAddressFamily(new Ipv4CaseBuilder().setIpv4(ipBuilder.build()).build());
         } else if (cfgLsp.getIntendedPath().getSource().getIpv6Address() != null) {
             final Ipv6Builder ipBuilder = new Ipv6Builder()
                     .setDestinationIpv6Address(new Ipv6AddressNoZone(iPath.getDestination().getIpv6Address()))
                     .setSourceIpv6Address(new Ipv6AddressNoZone(iPath.getSource().getIpv6Address()));
-            epb.setAddressFamily((new Ipv6CaseBuilder().setIpv6(ipBuilder.build()).build()));
+            epb.setAddressFamily(new Ipv6CaseBuilder().setIpv6(ipBuilder.build()).build());
         } else {
             // In case of ...
             return null;
@@ -404,10 +531,7 @@ public class ManagedTePath {
                 .setAdministrative(true)
                 .setDelegate(true);
 
-        /*
-         * Build Arguments.
-         * Note that TE Metric and Delay are not set because, at least, Juniper Routers don't support them.
-         */
+        /* Build Arguments. */
         final ArgumentsBuilder args = new ArgumentsBuilder()
                 .setEndpointsObj(epb.build())
                 .setEro(MessagesUtil.getEro(cfgLsp.getComputedPath().getPathDescription()))
@@ -416,14 +540,22 @@ public class ManagedTePath {
                         .setPathSetupType(pstBuilder.build())
                         .build());
 
-        /* with Bandwidth and Standard Metric */
+        /* with Bandwidth and Metric if defined */
         if (iPath.getConstraints().getBandwidth() != null) {
             final int ftoi = Float.floatToIntBits(iPath.getConstraints().getBandwidth().getValue().floatValue());
             final byte[] itob = { (byte) (0xFF & ftoi >> 24), (byte) (0xFF & ftoi >> 16), (byte) (0xFF & ftoi >> 8),
                 (byte) (0xFF & ftoi) };
             args.setBandwidth(new BandwidthBuilder().setBandwidth(new Bandwidth(itob)).build());
         }
-        if (iPath.getConstraints().getMetric() != null) {
+        /* Note that Delay are not set because, at least, Juniper Routers don't support them */
+        if (iPath.getConstraints().getTeMetric() != null) {
+            final MetricBuilder metricBuilder = new MetricBuilder()
+                    .setComputed(true)
+                    .setMetricType(Uint8.TWO)
+                    .setValue(new Float32(ByteBuffer.allocate(4)
+                            .putFloat(iPath.getConstraints().getTeMetric().floatValue()).array()));
+            args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
+        } else if (iPath.getConstraints().getMetric() != null) {
             final MetricBuilder metricBuilder = new MetricBuilder()
                     .setComputed(true)
                     .setMetricType(Uint8.ONE)
@@ -459,13 +591,13 @@ public class ManagedTePath {
     /**
      * Call add-lsp RPC to enforce the LSP into the PCC. This action will trigger a PcInitiate message to the PCC.
      *
-     * @param ntps  Network Topology PCEP Service
+     * @param addLsp Add Lsp RPC
      *
      * @return      Add LSP Output to convey the RPC result
      */
-    public ListenableFuture<RpcResult<AddLspOutput>> addPath(final NetworkTopologyPcepService ntps) {
+    public ListenableFuture<RpcResult<AddLspOutput>> addPath(final AddLsp addLsp) {
         /* Check if we could add this path */
-        if ((type != PathType.Initiated) || !teNode.isSync()) {
+        if (type != PathType.Initiated || !teNode.isSync()) {
             return null;
         }
 
@@ -475,9 +607,9 @@ public class ManagedTePath {
         }
 
         sent = true;
-        final ListenableFuture<RpcResult<AddLspOutput>> enforce = ntps.addLsp(getAddLspInput());
-        LOG.info("Call Add LSP to {} with {}", ntps, enforce);
-        Futures.addCallback(enforce, new FutureCallback<RpcResult<AddLspOutput>>() {
+        final var enforce = addLsp.invoke(getAddLspInput());
+        LOG.info("Call Add LSP to {} with {}", addLsp, enforce);
+        Futures.addCallback(enforce, new FutureCallback<>() {
             @Override
             public void onSuccess(final RpcResult<AddLspOutput> result) {
                 if (result.isSuccessful()) {
@@ -504,7 +636,7 @@ public class ManagedTePath {
      *
      * @return  new Update LSP Input
      */
-    private UpdateLspInput getUpdateLspInput() {
+    private @NonNull UpdateLspInput getUpdateLspInput() {
         /* Create Path Setup Type */
         final IntendedPath iPath = cfgLsp.getIntendedPath();
         final PathSetupTypeBuilder pstBuilder = new PathSetupTypeBuilder();
@@ -524,9 +656,9 @@ public class ManagedTePath {
                 .setDelegate(true);
 
         /* Build Arguments */
-        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730
             .update.lsp.args.ArgumentsBuilder args;
-        args = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
+        args = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730
             .update.lsp.args.ArgumentsBuilder()
                 .addAugmentation(new Arguments3Builder()
                     .setLsp(lspBuilder.build())
@@ -534,13 +666,29 @@ public class ManagedTePath {
                     .build())
                 .setEro(MessagesUtil.getEro(cfgLsp.getComputedPath().getPathDescription()));
 
-        /*  with Bandwidth if defined, but not other Metrics as some routers don't support them */
+        /*  with Bandwidth and Metric if defined */
         if (iPath.getConstraints().getBandwidth() != null) {
             final int ftoi = Float.floatToIntBits(iPath.getConstraints().getBandwidth().getValue().floatValue());
             final byte[] itob = { (byte) (0xFF & ftoi >> 24), (byte) (0xFF & ftoi >> 16), (byte) (0xFF & ftoi >> 8),
                 (byte) (0xFF & ftoi) };
             args.setBandwidth(new BandwidthBuilder().setBandwidth(new Bandwidth(itob)).build());
         }
+        /* Note that Delay are not set because, at least, Juniper Routers don't support them */
+        if (iPath.getConstraints().getTeMetric() != null) {
+            final MetricBuilder metricBuilder = new MetricBuilder()
+                    .setComputed(true)
+                    .setMetricType(Uint8.TWO)
+                    .setValue(new Float32(ByteBuffer.allocate(4)
+                            .putFloat(iPath.getConstraints().getTeMetric().floatValue()).array()));
+            args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
+        } else if (iPath.getConstraints().getMetric() != null) {
+            final MetricBuilder metricBuilder = new MetricBuilder()
+                    .setComputed(true)
+                    .setMetricType(Uint8.ONE)
+                    .setValue(new Float32(ByteBuffer.allocate(4)
+                            .putFloat(iPath.getConstraints().getMetric().floatValue()).array()));
+            args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
+        }
 
         /*
          * NOTE: Seems that ClassType is not supported by some routers. Skip it for the moment.
@@ -568,14 +716,14 @@ public class ManagedTePath {
     /**
      * Call update-lsp RPC to enforce the LSP into the PCC. This action will trigger a PcUpdate message to the PCC.
      *
-     * @param ntps  Network Topology PCEP Service
+     * @param updateLsp  Update LSP RPC
      *
      * @return      Update LSP Output to convey the RPC result
      */
-    public ListenableFuture<RpcResult<UpdateLspOutput>> updatePath(final NetworkTopologyPcepService ntps) {
+    public ListenableFuture<RpcResult<UpdateLspOutput>> updatePath(final UpdateLsp updateLsp) {
 
         /* Check if we could update this path */
-        if ((type != PathType.Initiated && type != PathType.Delegated) || !teNode.isSync()) {
+        if (type != PathType.Initiated && type != PathType.Delegated || !teNode.isSync()) {
             return null;
         }
 
@@ -586,9 +734,9 @@ public class ManagedTePath {
 
         sent = true;
         final NodeId id = teNode.getId();
-        final ListenableFuture<RpcResult<UpdateLspOutput>> enforce = ntps.updateLsp(getUpdateLspInput());
-        LOG.info("Call Update LSP to {} with {}", ntps, enforce);
-        Futures.addCallback(enforce, new FutureCallback<RpcResult<UpdateLspOutput>>() {
+        final var enforce = updateLsp.invoke(getUpdateLspInput());
+        LOG.info("Call Update LSP to {} with {}", updateLsp, enforce);
+        Futures.addCallback(enforce, new FutureCallback<>() {
             @Override
             public void onSuccess(final RpcResult<UpdateLspOutput> result) {
                 if (result.isSuccessful()) {
@@ -614,14 +762,14 @@ public class ManagedTePath {
      * Call remove-lsp RPC to remove the LSP from the PCC. This action will trigger a PcInitiate message to the PCC
      * with 'R' bit set.
      *
-     * @param ntps  Network Topology PCEP Service
+     * @param removeLsp Remove Lsp RPC
      *
      * @return      Remove LSP Output to convey the RPC result
      */
-    public ListenableFuture<RpcResult<RemoveLspOutput>> removePath(final NetworkTopologyPcepService ntps) {
+    public ListenableFuture<RpcResult<RemoveLspOutput>> removePath(final RemoveLsp removeLsp) {
 
         /* Check if we could remove this path */
-        if ((type != PathType.Initiated) || !teNode.isSync() || cfgLsp.getPathStatus() != PathStatus.Sync) {
+        if (type != PathType.Initiated || !teNode.isSync() || cfgLsp.getPathStatus() != PathStatus.Sync) {
             return null;
         }
 
@@ -632,8 +780,8 @@ public class ManagedTePath {
                 .setName(cfgLsp.getName())
                 .setNetworkTopologyRef(new NetworkTopologyRef(pcepTopology))
                 .build();
-        final ListenableFuture<RpcResult<RemoveLspOutput>> enforce = ntps.removeLsp(rli);
-        LOG.info("Call Remove LSP to {} with {}", ntps, enforce);
+        final ListenableFuture<RpcResult<RemoveLspOutput>> enforce = removeLsp.invoke(rli);
+        LOG.info("Call Remove LSP to {} with {}", removeLsp, enforce);
         Futures.addCallback(enforce, new FutureCallback<RpcResult<RemoveLspOutput>>() {
             @Override
             public void onSuccess(final RpcResult<RemoveLspOutput> result) {
@@ -739,4 +887,5 @@ public class ManagedTePath {
         CodeHelpers.appendValue(helper, "Sent", sent);
         return helper.toString();
     }
+
 }