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