68e0465b55e3826b8bc8779105ba395c8a528e21
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / ManagedTePath.java
1 /*
2  * Copyright (c) 2021 Orange. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.bgpcep.pcep.server.provider;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.base.MoreObjects;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.nio.ByteBuffer;
19 import java.util.Collections;
20 import java.util.List;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.graph.ConnectedEdge;
23 import org.opendaylight.graph.ConnectedEdgeTrigger;
24 import org.opendaylight.graph.ConnectedGraph;
25 import org.opendaylight.graph.ConnectedVertex;
26 import org.opendaylight.graph.ConnectedVertexTrigger;
27 import org.opendaylight.mdsal.binding.api.WriteTransaction;
28 import org.opendaylight.mdsal.common.api.CommitInfo;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Edge;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Vertex;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidth;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ieee754.rev130819.Float32;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.rev140113.NetworkTopologyRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.AddressFamily;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ComputationStatus;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.descriptions.PathDescription;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments2Builder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments3Builder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.LspBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathComputationClient1;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathStatus;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPath;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPath;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.intended.path.Constraints;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.BandwidthBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv4CaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv6CaseBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.ipv4._case.Ipv4Builder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.ipv6._case.Ipv6Builder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObjBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.MetricsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.metric.object.MetricBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupTypeBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.NetworkTopologyPcepService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.add.lsp.args.ArgumentsBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
76 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
77 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
79 import org.opendaylight.yangtools.yang.binding.CodeHelpers;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.common.RpcResult;
82 import org.opendaylight.yangtools.yang.common.Uint8;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 public class ManagedTePath implements ConnectedEdgeTrigger, ConnectedVertexTrigger {
87
88     private ConfiguredLsp cfgLsp = null;
89     private ConfiguredLsp prevLsp = null;
90     private final ManagedTeNode teNode;
91     private boolean sent = false;
92     private boolean triggerFlag = false;
93     private PathType type = PathType.Pcc;
94     private final InstanceIdentifier<Topology> pcepTopology;
95     private final InstanceIdentifier<PathComputationClient1> pccIdentifier;
96
97     private static final Logger LOG = LoggerFactory.getLogger(ManagedTePath.class);
98
99     public ManagedTePath(ManagedTeNode teNode, InstanceIdentifier<Topology> topology) {
100         this.teNode = requireNonNull(teNode);
101         this.pcepTopology = requireNonNull(topology);
102         this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
103                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
104     }
105
106     public ManagedTePath(ManagedTeNode teNode, final ConfiguredLsp lsp, InstanceIdentifier<Topology> topology) {
107         this.cfgLsp = requireNonNull(lsp);
108         this.teNode = requireNonNull(teNode);
109         this.pcepTopology = requireNonNull(topology);
110         this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
111                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
112     }
113
114     public ManagedTePath(ManagedTeNode teNode, final ManagedTePath mngPath) {
115         checkArgument(mngPath != null, "Managed TE Path is mandatory. Can't be null or empty!");
116         this.cfgLsp = mngPath.getLsp();
117         this.sent = mngPath.isSent();
118         this.type = mngPath.getType();
119         this.teNode = requireNonNull(teNode);
120         this.pcepTopology = mngPath.getTopology();
121         this.pccIdentifier = pcepTopology.child(Node.class, new NodeKey(teNode.getId())).augmentation(Node1.class)
122                 .child(PathComputationClient.class).augmentation(PathComputationClient1.class);
123     }
124
125     public ConfiguredLsp getLsp() {
126         return cfgLsp;
127     }
128
129     public ManagedTeNode getManagedTeNode() {
130         return teNode;
131     }
132
133     public PathType getType() {
134         return type;
135     }
136
137     public InstanceIdentifier<Topology> getTopology() {
138         return pcepTopology;
139     }
140
141     public ManagedTePath setConfiguredLsp(final ConfiguredLsp lsp) {
142         this.prevLsp = this.cfgLsp;
143         this.cfgLsp = lsp;
144         return this;
145     }
146
147     public ManagedTePath setType(PathType type) {
148         this.type = type;
149         return this;
150     }
151
152     /**
153      * Mark this TE Path as synchronized and update the Data Store accordingly.
154      *
155      */
156     public void sync() {
157         this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Sync).build();
158         updateToDataStore();
159     }
160
161     /**
162      * Disabling this TE Path by marking it as Configured. Do not update the Data Store.
163      */
164     public void disabled() {
165         this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Configured).build();
166     }
167
168     /**
169      * Mark this TE Path as Failed.
170      */
171     public void failed() {
172         this.cfgLsp = new ConfiguredLspBuilder(cfgLsp).setPathStatus(PathStatus.Failed).build();
173         updateToDataStore();
174     }
175
176     public boolean isSent() {
177         return sent;
178     }
179
180     /**
181      * Compare the current TE Path against the reported LSP to determine if there are in Sync, need Update or
182      * considered as in Failure if already updated.
183      *
184      * @param lsp   LSP that corresponds to the reported LSP
185      *
186      * @return      new LSP status
187      */
188     public PathStatus checkReportedPath(final ConfiguredLsp lsp) {
189         /* Check if this path has not been already verified */
190         if (cfgLsp.getPathStatus() == PathStatus.Sync) {
191             return PathStatus.Sync;
192         }
193
194         /* Check Source, Destination and routing method which must be the same */
195         final IntendedPath iPath = lsp.getIntendedPath();
196         final IntendedPath rPath = lsp.getIntendedPath();
197         PathStatus newStatus = sent ? PathStatus.Failed : PathStatus.Updated;
198         if (!iPath.getSource().equals(rPath.getSource()) || !iPath.getDestination().equals(rPath.getDestination())) {
199             return PathStatus.Failed;
200         }
201
202         /* Check constraints ... */
203         final Constraints icts = iPath.getConstraints();
204         final Constraints rcts = rPath.getConstraints();
205         if (!icts.getAddressFamily().equals(rcts.getAddressFamily())) {
206             return newStatus;
207         }
208         if (icts.getBandwidth() != null && !icts.getBandwidth().equals(rcts.getBandwidth())) {
209             return newStatus;
210         }
211         /*
212          * ClassType, TE metric and Delay are not supported by all routers: need
213          * to check them only if there are all present
214          */
215         if (icts.getClassType() != null && rcts.getClassType() != null
216                         && !icts.getClassType().equals(rcts.getClassType())) {
217             return newStatus;
218         }
219         if (icts.getTeMetric() != null && rcts.getTeMetric() != null
220                 && !icts.getTeMetric().equals(rcts.getTeMetric())) {
221             return newStatus;
222         }
223         if (icts.getDelay() != null && rcts.getDelay() != null && !icts.getDelay().equals(rcts.getDelay())) {
224             return newStatus;
225         }
226
227         /* ... and Path to determine if an update is required */
228         if (lsp.getComputedPath().getComputationStatus() != ComputationStatus.Completed) {
229             return PathStatus.Failed;
230         }
231         if (!lsp.getComputedPath().getPathDescription().equals(lsp.getComputedPath().getPathDescription())) {
232             return newStatus;
233         }
234
235         /* All is conform. LSP is in sync with expected result. */
236         return PathStatus.Sync;
237     }
238
239     private void configureGraph(ConnectedGraph graph, ComputedPath cpath, Constraints cts, boolean config) {
240         /* Check that Connected Graph is valid */
241         if (graph == null) {
242             return;
243         }
244
245         /* Verify that we have a valid Computed Path and that the LSP is in SYNC */
246         if (cpath.getComputationStatus() != ComputationStatus.Completed || cfgLsp.getPathStatus() != PathStatus.Sync) {
247             return;
248         }
249
250         /* Loop the path description to add reserved bandwidth and triggers for this LSP */
251         final Long bw = cts.getBandwidth() == null ? 0L : cts.getBandwidth().getValue().longValue();
252         int cos = cts.getClassType() == null ? 0 : cts.getClassType().intValue();
253         final AddressFamily af = cts.getAddressFamily();
254         final String lspId = teNode.getId().getValue() + "/" + cfgLsp.getName();
255         ConnectedEdge edge = null;
256         for (PathDescription path : cpath.getPathDescription()) {
257             edge = null;
258             switch (af) {
259                 case Ipv4:
260                 case SrIpv4:
261                     if (path.getIpv4() != null) {
262                         edge = graph.getConnectedEdge(new IpAddress(path.getIpv4()));
263                     } else if (path.getRemoteIpv4() != null) {
264                         edge = graph.getConnectedEdge(new IpAddress(path.getRemoteIpv4()));
265                         if (edgeAttrNotNull(edge)) {
266                             edge = graph.getConnectedEdge(edge.getEdge().getEdgeAttributes().getRemoteAddress());
267                         }
268                     }
269                     break;
270                 case Ipv6:
271                 case SrIpv6:
272                     if (path.getIpv6() != null) {
273                         edge = graph.getConnectedEdge(new IpAddress(path.getIpv6()));
274                     } else if (path.getRemoteIpv6() != null) {
275                         edge = graph.getConnectedEdge(new IpAddress(path.getRemoteIpv6()));
276                         if (edgeAttrNotNull(edge)) {
277                             /* Need to force using IPv6 address as Connected Edge is searched first on IPv4 address */
278                             edge = graph.getConnectedEdge(new IpAddress(
279                                     edge.getEdge().getEdgeAttributes().getRemoteAddress().getIpv6Address()));
280                         }
281                     }
282                     break;
283                 default:
284                     break;
285             }
286
287             if (edge == null) {
288                 continue;
289             }
290
291             if (config) {
292                 if (bw != 0L) {
293                     edge.addBandwidth(bw, cos);
294                 }
295                 edge.registerTrigger(this, lspId);
296                 if (edge.getSource() != null) {
297                     edge.getSource().registerTrigger(this, lspId);
298                 }
299             } else {
300                 if (bw != 0L) {
301                     edge.delBandwidth(bw, cos);
302                 }
303                 edge.unRegisterTrigger(this, lspId);
304                 if (edge.getSource() != null) {
305                     edge.getSource().unRegisterTrigger(this, lspId);
306                 }
307             }
308         }
309         if (edge != null && edge.getDestination() != null) {
310             if (config) {
311                 edge.getDestination().registerTrigger(this, lspId);
312             } else {
313                 edge.getDestination().unRegisterTrigger(this, lspId);
314             }
315         }
316
317         /* Finally, reset Trigger Flag to activate them */
318         triggerFlag = false;
319     }
320
321     private boolean edgeAttrNotNull(ConnectedEdge edge) {
322         return edge != null && edge.getEdge() != null && edge.getEdge().getEdgeAttributes() != null;
323     }
324
325     public void setGraph(ConnectedGraph graph) {
326         configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), true);
327     }
328
329     public void unsetGraph(ConnectedGraph graph) {
330         configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), false);
331     }
332
333     public void updateGraph(ConnectedGraph graph) {
334         /* First unset Bandwidth and Triggers for the old path if any */
335         if (prevLsp != null) {
336             configureGraph(graph, prevLsp.getComputedPath(), prevLsp.getIntendedPath().getConstraints(), false);
337         }
338
339         /* Then add Bandwidth and Triggers for the current path */
340         configureGraph(graph, cfgLsp.getComputedPath(), cfgLsp.getIntendedPath().getConstraints(), true);
341
342         /* And memorize current LSP for latter update */
343         prevLsp = cfgLsp;
344     }
345
346     /**
347      * Reset Triggered Flag.
348      */
349     public void unSetTriggerFlag() {
350         triggerFlag = false;
351     }
352
353     @Override
354     public boolean verifyVertex(@Nullable ConnectedVertex next, @Nullable Vertex current) {
355         /* Check if there is an on-going trigger */
356         if (triggerFlag) {
357             return false;
358         }
359
360         /* Check if Vertex has been removed */
361         Vertex vertex = next.getVertex();
362         if (vertex == null) {
363             triggerFlag = true;
364             return true;
365         }
366
367         /* Check if Vertex changed its Segment Routing Global Block */
368         final AddressFamily af = cfgLsp.getIntendedPath().getConstraints().getAddressFamily();
369         if ((af == AddressFamily.SrIpv4 || af == AddressFamily.SrIpv6) && !current.getSrgb().equals(vertex.getSrgb())) {
370             LOG.debug("Vertex {} modified its SRGB {} / {}", vertex.getName(), current.getSrgb(), vertex.getSrgb());
371             triggerFlag = true;
372             return true;
373         }
374
375         /* All is fine */
376         triggerFlag = false;
377         return false;
378     }
379
380     @Override
381     public boolean verifyEdge(@Nullable ConnectedEdge next, @Nullable Edge current) {
382         /* Check if there is an on-going trigger */
383         if (triggerFlag) {
384             return false;
385         }
386
387         /* Check if Edge or Attributes has been removed */
388         Edge edge = next.getEdge();
389         if (edge == null || edge.getEdgeAttributes() == null) {
390             triggerFlag = true;
391             return true;
392         }
393
394         /* Check that Configured LSP has valid constraints */
395         final Constraints constraints = cfgLsp.getIntendedPath().getConstraints();
396         if (constraints == null) {
397             return false;
398         }
399
400         /* Check if Metric is always met */
401         Long metric = 0L;
402         Long delta = 0L;
403         if (constraints.getDelay() != null) {
404             if (edge.getEdgeAttributes().getDelay() != null) {
405                 metric = constraints.getDelay().getValue().longValue();
406                 delta = edge.getEdgeAttributes().getDelay().getValue().longValue()
407                         - current.getEdgeAttributes().getDelay().getValue().longValue();
408             } else {
409                 triggerFlag = true;
410                 return true;
411             }
412         }
413         if (constraints.getTeMetric() != null) {
414             if (edge.getEdgeAttributes().getTeMetric() != null) {
415                 metric = constraints.getTeMetric().longValue();
416                 delta = edge.getEdgeAttributes().getTeMetric().longValue()
417                         - current.getEdgeAttributes().getTeMetric().longValue();
418             } else {
419                 triggerFlag = true;
420                 return true;
421             }
422         } else if (constraints.getMetric() != null) {
423             if (edge.getEdgeAttributes().getMetric() != null) {
424                 metric = constraints.getMetric().longValue();
425                 delta = edge.getEdgeAttributes().getMetric().longValue()
426                         - current.getEdgeAttributes().getMetric().longValue();
427             } else {
428                 triggerFlag = true;
429                 return true;
430             }
431         }
432         if (metric != 0L && cfgLsp.getComputedPath().getComputedMetric() != null
433                 && cfgLsp.getComputedPath().getComputedMetric().longValue() + delta > metric) {
434             LOG.debug("Following an update on Edge {} Metric is no longer guaranteed: {} / {}",
435                     edge.getName(),
436                     cfgLsp.getComputedPath().getComputedMetric().longValue() + delta,
437                     metric);
438             triggerFlag = true;
439             return true;
440         }
441
442         /* Check if Bandwidth is always met */
443         if (constraints.getBandwidth() != null) {
444             if (edge.getEdgeAttributes().getMaxLinkBandwidth() == null
445                     || edge.getEdgeAttributes().getMaxResvLinkBandwidth() == null
446                     || edge.getEdgeAttributes().getUnreservedBandwidth() == null) {
447                 triggerFlag = true;
448                 return true;
449             }
450             Long bandwidth = constraints.getBandwidth().getValue().longValue();
451             Long unrsv = 0L;
452             int cos = 0;
453             for (UnreservedBandwidth unResBw : edge.getEdgeAttributes().getUnreservedBandwidth()) {
454                 if (unResBw.getClassType().intValue() == cos) {
455                     unrsv = unResBw.getBandwidth().getValue().longValue();
456                     break;
457                 }
458             }
459             Long maxBW = edge.getEdgeAttributes().getMaxLinkBandwidth().getValue().longValue();
460             if (bandwidth > List.of(
461                     unrsv,
462                     /* maxBW might be on the list but will always be greater than the next items */
463                     maxBW - next.getCosResvBandwidth(cos),
464                     maxBW - next.getGlobalResvBandwidth(),
465                     edge.getEdgeAttributes().getMaxResvLinkBandwidth().getValue().longValue())
466                     .stream().mapToLong(v -> v)
467                     .min().getAsLong()
468             ) {
469                 LOG.debug("Following an update on Edge {}, Reserved bandwidth is no longer guaranteed", edge.getName());
470                 triggerFlag = true;
471                 return true;
472             }
473         }
474
475         /* Check if Edge changed its Adjacency SID */
476         final AddressFamily af = cfgLsp.getIntendedPath().getConstraints().getAddressFamily();
477         if ((af == AddressFamily.SrIpv4 || af == AddressFamily.SrIpv6)
478                 && !current.getEdgeAttributes().getAdjSid().equals(edge.getEdgeAttributes().getAdjSid())) {
479             LOG.debug("Edge {} has modified its Adjacency SID", edge.getName());
480             triggerFlag = true;
481             return true;
482         }
483
484         return false;
485     }
486
487     /**
488      * Convert LSP as Add LSP Input class to enforce it into the PCC through a call to add-lsp RPCs.
489      *
490      * @return  new Add LSP Input
491      */
492     private AddLspInput getAddLspInput() {
493         /* Create EndPoint Object */
494         final IntendedPath iPath = cfgLsp.getIntendedPath();
495         final EndpointsObjBuilder epb = new EndpointsObjBuilder()
496                 .setIgnore(false)
497                 .setProcessingRule(true);
498         if (iPath.getSource().getIpv4Address() != null) {
499             final Ipv4Builder ipBuilder = new Ipv4Builder()
500                     .setDestinationIpv4Address(new Ipv4AddressNoZone(iPath.getDestination().getIpv4Address()))
501                     .setSourceIpv4Address(new Ipv4AddressNoZone(iPath.getSource().getIpv4Address()));
502             epb.setAddressFamily((new Ipv4CaseBuilder().setIpv4(ipBuilder.build()).build()));
503         } else if (cfgLsp.getIntendedPath().getSource().getIpv6Address() != null) {
504             final Ipv6Builder ipBuilder = new Ipv6Builder()
505                     .setDestinationIpv6Address(new Ipv6AddressNoZone(iPath.getDestination().getIpv6Address()))
506                     .setSourceIpv6Address(new Ipv6AddressNoZone(iPath.getSource().getIpv6Address()));
507             epb.setAddressFamily((new Ipv6CaseBuilder().setIpv6(ipBuilder.build()).build()));
508         } else {
509             // In case of ...
510             return null;
511         }
512
513         /* Create Path Setup Type */
514         final PathSetupTypeBuilder pstBuilder = new PathSetupTypeBuilder();
515         switch (iPath.getConstraints().getAddressFamily()) {
516             case SrIpv4:
517             case SrIpv6:
518                 pstBuilder.setPst(Uint8.ONE);
519                 break;
520             default:
521                 pstBuilder.setPst(Uint8.ZERO);
522                 break;
523         }
524
525         /* Create LSP */
526         final LspBuilder lspBuilder = new LspBuilder()
527                 .setAdministrative(true)
528                 .setDelegate(true);
529
530         /* Build Arguments. */
531         final ArgumentsBuilder args = new ArgumentsBuilder()
532                 .setEndpointsObj(epb.build())
533                 .setEro(MessagesUtil.getEro(cfgLsp.getComputedPath().getPathDescription()))
534                 .addAugmentation(new Arguments2Builder()
535                         .setLsp(lspBuilder.build())
536                         .setPathSetupType(pstBuilder.build())
537                         .build());
538
539         /* with Bandwidth and Metric if defined */
540         if (iPath.getConstraints().getBandwidth() != null) {
541             final int ftoi = Float.floatToIntBits(iPath.getConstraints().getBandwidth().getValue().floatValue());
542             final byte[] itob = { (byte) (0xFF & ftoi >> 24), (byte) (0xFF & ftoi >> 16), (byte) (0xFF & ftoi >> 8),
543                 (byte) (0xFF & ftoi) };
544             args.setBandwidth(new BandwidthBuilder().setBandwidth(new Bandwidth(itob)).build());
545         }
546         /* Note that Delay are not set because, at least, Juniper Routers don't support them */
547         if (iPath.getConstraints().getTeMetric() != null) {
548             final MetricBuilder metricBuilder = new MetricBuilder()
549                     .setComputed(true)
550                     .setMetricType(Uint8.TWO)
551                     .setValue(new Float32(ByteBuffer.allocate(4)
552                             .putFloat(iPath.getConstraints().getTeMetric().floatValue()).array()));
553             args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
554         } else if (iPath.getConstraints().getMetric() != null) {
555             final MetricBuilder metricBuilder = new MetricBuilder()
556                     .setComputed(true)
557                     .setMetricType(Uint8.ONE)
558                     .setValue(new Float32(
559                             ByteBuffer.allocate(4).putFloat(iPath.getConstraints().getMetric().floatValue()).array()));
560             args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
561         }
562
563         /*
564          * NOTE: Seems that ClassType is not supported by some routers. Skip it for the moment.
565          */
566         /* With Class Type if defined
567         if (iPath.getConstraints().getClassType() != null) {
568             args.setClassType(
569                 new ClassTypeBuilder()
570                     .setClassType(new ClassType(iPath.getConstraints().getClassType()))
571                     .setIgnore(false)
572                     .setProcessingRule(true)
573                     .build());
574         }
575         */
576
577         /* Finally, build addLSP input */
578         return new AddLspInputBuilder()
579                 .setNode(teNode.getId())
580                 .setName(cfgLsp.getName())
581                 .setArguments(args.build())
582                 .setNetworkTopologyRef(new NetworkTopologyRef(pcepTopology))
583                 .build();
584     }
585
586
587     /**
588      * Call add-lsp RPC to enforce the LSP into the PCC. This action will trigger a PcInitiate message to the PCC.
589      *
590      * @param ntps  Network Topology PCEP Service
591      *
592      * @return      Add LSP Output to convey the RPC result
593      */
594     public ListenableFuture<RpcResult<AddLspOutput>> addPath(final NetworkTopologyPcepService ntps) {
595         /* Check if we could add this path */
596         if ((type != PathType.Initiated) || !teNode.isSync()) {
597             return null;
598         }
599
600         /* Check if we have a valid Path */
601         if (cfgLsp.getComputedPath().getComputationStatus() != ComputationStatus.Completed) {
602             return null;
603         }
604
605         sent = true;
606         final ListenableFuture<RpcResult<AddLspOutput>> enforce = ntps.addLsp(getAddLspInput());
607         LOG.info("Call Add LSP to {} with {}", ntps, enforce);
608         Futures.addCallback(enforce, new FutureCallback<RpcResult<AddLspOutput>>() {
609             @Override
610             public void onSuccess(final RpcResult<AddLspOutput> result) {
611                 if (result.isSuccessful()) {
612                     LOG.debug("Enforce LSP success {}", result.getResult());
613                 } else {
614                     LOG.debug("Unable to enforce LSP {} on Node {}: Got error {}", cfgLsp.getName(), teNode.getId(),
615                             result.getErrors());
616                 }
617                 sent = false;
618             }
619
620             @Override
621             public void onFailure(final Throwable throwable) {
622                 LOG.warn("Failed enforce LSP {} on Node {}", cfgLsp.getName(), teNode.getId());
623                 sent = false;
624             }
625         }, MoreExecutors.directExecutor());
626
627         return enforce;
628     }
629
630     /**
631      * Convert LSP as Update LSP Input class to update it into the PCC through a call to update-lsp RPCs.
632      *
633      * @return  new Update LSP Input
634      */
635     private UpdateLspInput getUpdateLspInput() {
636         /* Create Path Setup Type */
637         final IntendedPath iPath = cfgLsp.getIntendedPath();
638         final PathSetupTypeBuilder pstBuilder = new PathSetupTypeBuilder();
639         switch (iPath.getConstraints().getAddressFamily()) {
640             case SrIpv4:
641             case SrIpv6:
642                 pstBuilder.setPst(Uint8.ONE);
643                 break;
644             default:
645                 pstBuilder.setPst(Uint8.ZERO);
646                 break;
647         }
648
649         /* Create LSP */
650         final LspBuilder lspBuilder = new LspBuilder()
651                 .setAdministrative(true)
652                 .setDelegate(true);
653
654         /* Build Arguments */
655         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
656             .update.lsp.args.ArgumentsBuilder args;
657         args = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
658             .update.lsp.args.ArgumentsBuilder()
659                 .addAugmentation(new Arguments3Builder()
660                     .setLsp(lspBuilder.build())
661                     .setPathSetupType(pstBuilder.build())
662                     .build())
663                 .setEro(MessagesUtil.getEro(cfgLsp.getComputedPath().getPathDescription()));
664
665         /*  with Bandwidth and Metric if defined */
666         if (iPath.getConstraints().getBandwidth() != null) {
667             final int ftoi = Float.floatToIntBits(iPath.getConstraints().getBandwidth().getValue().floatValue());
668             final byte[] itob = { (byte) (0xFF & ftoi >> 24), (byte) (0xFF & ftoi >> 16), (byte) (0xFF & ftoi >> 8),
669                 (byte) (0xFF & ftoi) };
670             args.setBandwidth(new BandwidthBuilder().setBandwidth(new Bandwidth(itob)).build());
671         }
672         /* Note that Delay are not set because, at least, Juniper Routers don't support them */
673         if (iPath.getConstraints().getTeMetric() != null) {
674             final MetricBuilder metricBuilder = new MetricBuilder()
675                     .setComputed(true)
676                     .setMetricType(Uint8.TWO)
677                     .setValue(new Float32(ByteBuffer.allocate(4)
678                             .putFloat(iPath.getConstraints().getTeMetric().floatValue()).array()));
679             args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
680         } else if (iPath.getConstraints().getMetric() != null) {
681             final MetricBuilder metricBuilder = new MetricBuilder()
682                     .setComputed(true)
683                     .setMetricType(Uint8.ONE)
684                     .setValue(new Float32(ByteBuffer.allocate(4)
685                             .putFloat(iPath.getConstraints().getMetric().floatValue()).array()));
686             args.setMetrics(Collections.singletonList(new MetricsBuilder().setMetric(metricBuilder.build()).build()));
687         }
688
689         /*
690          * NOTE: Seems that ClassType is not supported by some routers. Skip it for the moment.
691          */
692         /* With Class Type if defined
693         if (iPath.getConstraints().getClassType() != null) {
694             args.setClassType(
695                 new ClassTypeBuilder()
696                     .setClassType(new ClassType(iPath.getConstraints().getClassType()))
697                     .setIgnore(false)
698                     .setProcessingRule(true)
699                     .build());
700         }
701         */
702
703         /* Finally, build updateLSP input */
704         return new UpdateLspInputBuilder()
705                 .setNode(teNode.getId())
706                 .setName(cfgLsp.getName())
707                 .setArguments(args.build())
708                 .setNetworkTopologyRef(new NetworkTopologyRef(pcepTopology))
709                 .build();
710     }
711
712     /**
713      * Call update-lsp RPC to enforce the LSP into the PCC. This action will trigger a PcUpdate message to the PCC.
714      *
715      * @param ntps  Network Topology PCEP Service
716      *
717      * @return      Update LSP Output to convey the RPC result
718      */
719     public ListenableFuture<RpcResult<UpdateLspOutput>> updatePath(final NetworkTopologyPcepService ntps) {
720
721         /* Check if we could update this path */
722         if ((type != PathType.Initiated && type != PathType.Delegated) || !teNode.isSync()) {
723             return null;
724         }
725
726         /* Check if we have a valid ERO */
727         if (cfgLsp.getComputedPath().getComputationStatus() != ComputationStatus.Completed) {
728             return null;
729         }
730
731         sent = true;
732         final NodeId id = teNode.getId();
733         final ListenableFuture<RpcResult<UpdateLspOutput>> enforce = ntps.updateLsp(getUpdateLspInput());
734         LOG.info("Call Update LSP to {} with {}", ntps, enforce);
735         Futures.addCallback(enforce, new FutureCallback<RpcResult<UpdateLspOutput>>() {
736             @Override
737             public void onSuccess(final RpcResult<UpdateLspOutput> result) {
738                 if (result.isSuccessful()) {
739                     LOG.debug("Update LSP success {}", result.getResult());
740                 } else {
741                     LOG.debug("Unable to update LSP {} on Node {}: Got error {}", cfgLsp.getName(), id,
742                             result.getErrors());
743                 }
744                 sent = false;
745             }
746
747             @Override
748             public void onFailure(final Throwable throwable) {
749                 LOG.warn("Failed update LSP {} on Node {}", cfgLsp.getName(), id);
750                 sent = false;
751             }
752         }, MoreExecutors.directExecutor());
753
754         return enforce;
755     }
756
757     /**
758      * Call remove-lsp RPC to remove the LSP from the PCC. This action will trigger a PcInitiate message to the PCC
759      * with 'R' bit set.
760      *
761      * @param ntps  Network Topology PCEP Service
762      *
763      * @return      Remove LSP Output to convey the RPC result
764      */
765     public ListenableFuture<RpcResult<RemoveLspOutput>> removePath(final NetworkTopologyPcepService ntps) {
766
767         /* Check if we could remove this path */
768         if ((type != PathType.Initiated) || !teNode.isSync() || cfgLsp.getPathStatus() != PathStatus.Sync) {
769             return null;
770         }
771
772         sent = true;
773         final NodeId id = teNode.getId();
774         final RemoveLspInput rli = new RemoveLspInputBuilder()
775                 .setNode(id)
776                 .setName(cfgLsp.getName())
777                 .setNetworkTopologyRef(new NetworkTopologyRef(pcepTopology))
778                 .build();
779         final ListenableFuture<RpcResult<RemoveLspOutput>> enforce = ntps.removeLsp(rli);
780         LOG.info("Call Remove LSP to {} with {}", ntps, enforce);
781         Futures.addCallback(enforce, new FutureCallback<RpcResult<RemoveLspOutput>>() {
782             @Override
783             public void onSuccess(final RpcResult<RemoveLspOutput> result) {
784                 if (result.isSuccessful()) {
785                     LOG.debug("Delete LSP success {}", result.getResult());
786                 } else {
787                     LOG.debug("Unable to delete LSP {} on Node {}: Got error {}", cfgLsp.getName(), id,
788                             result.getErrors());
789                 }
790                 sent = false;
791             }
792
793             @Override
794             public void onFailure(final Throwable throwable) {
795                 LOG.warn("Failed delete LSP {} on Node {}", cfgLsp.getName(), id);
796                 sent = false;
797             }
798         }, MoreExecutors.directExecutor());
799
800         return enforce;
801     }
802
803     /**
804      * Add LSP components to the Operational Data Store.
805      */
806     public synchronized void addToDataStore() {
807         /* Check if we could add this path */
808         if (!teNode.isSync()) {
809             return;
810         }
811
812         final WriteTransaction trans = teNode.getTransaction();
813         trans.put(LogicalDatastoreType.OPERATIONAL, pccIdentifier.child(ConfiguredLsp.class, cfgLsp.key()), cfgLsp);
814         trans.commit().addCallback(new FutureCallback<CommitInfo>() {
815             @Override
816             public void onSuccess(final CommitInfo result) {
817                 LOG.debug("Configured LSP {} has been published in operational datastore ", cfgLsp.getName());
818             }
819
820             @Override
821             public void onFailure(final Throwable throwable) {
822                 LOG.error("Cannot write Configured LSP {} to the operational datastore (transaction: {})",
823                         cfgLsp.getName(), trans.getIdentifier());
824             }
825         }, MoreExecutors.directExecutor());
826     }
827
828     /**
829      * Update LSP components to the Data Store.
830      */
831     public synchronized void updateToDataStore() {
832         /* Check if we could update this path */
833         if (!teNode.isSync()) {
834             return;
835         }
836
837         final WriteTransaction trans = teNode.getTransaction();
838         trans.merge(LogicalDatastoreType.OPERATIONAL, pccIdentifier.child(ConfiguredLsp.class, cfgLsp.key()), cfgLsp);
839         trans.commit().addCallback(new FutureCallback<CommitInfo>() {
840             @Override
841             public void onSuccess(final CommitInfo result) {
842                 LOG.debug("Configured LSP {} has been updated in operational datastore ", cfgLsp.getName());
843             }
844
845             @Override
846             public void onFailure(final Throwable throwable) {
847                 LOG.error("Cannot update Configured LSP {} to the operational datastore (transaction: {})",
848                         cfgLsp.getName(), trans.getIdentifier());
849             }
850         }, MoreExecutors.directExecutor());
851     }
852
853     /**
854      * Remove LSP components to the Data Store.
855      */
856     public synchronized void removeFromDataStore() {
857         /* Check if we could remove this path */
858         if (!teNode.isSync()) {
859             return;
860         }
861
862         final WriteTransaction trans = teNode.getTransaction();
863         trans.delete(LogicalDatastoreType.OPERATIONAL, pccIdentifier.child(ConfiguredLsp.class, cfgLsp.key()));
864         trans.commit().addCallback(new FutureCallback<CommitInfo>() {
865             @Override
866             public void onSuccess(final CommitInfo result) {
867                 LOG.debug("Configured LSP {} has been deleted in operational datastore ", cfgLsp.getName());
868             }
869
870             @Override
871             public void onFailure(final Throwable throwable) {
872                 LOG.error("Cannot delete Configured LSP {} from the operational datastore (transaction: {})",
873                         cfgLsp.getName(), trans.getIdentifier());
874             }
875         }, MoreExecutors.directExecutor());
876     }
877
878     @Override
879     public String toString() {
880         final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper("ManagedTePath");
881         CodeHelpers.appendValue(helper, "ConfiguredLsp", cfgLsp);
882         CodeHelpers.appendValue(helper, "PathType", type);
883         CodeHelpers.appendValue(helper, "Sent", sent);
884         return helper.toString();
885     }
886
887 }