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