Bump upstreams
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / PathManagerProvider.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 com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.util.concurrent.FutureCallback;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Map;
18 import javax.annotation.PreDestroy;
19 import org.opendaylight.graph.ConnectedEdge;
20 import org.opendaylight.graph.ConnectedEdgeTrigger;
21 import org.opendaylight.graph.ConnectedGraph;
22 import org.opendaylight.graph.ConnectedGraphTrigger;
23 import org.opendaylight.graph.ConnectedVertex;
24 import org.opendaylight.graph.ConnectedVertexTrigger;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.RpcService;
27 import org.opendaylight.mdsal.binding.api.TransactionChain;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Edge;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Vertex;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ComputationStatus;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathStatus;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathType;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PcepNodeConfig;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPathBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPath;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPathBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.intended.path.ConstraintsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLsp;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLsp;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLsp;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.Empty;
50 import org.osgi.service.component.annotations.Deactivate;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 /**
55  * This Class implements the Path Manager in charge of Managed TE Node and Managed TE Path.
56  *
57  * @author Olivier Dugeon
58  */
59
60 public final class PathManagerProvider implements FutureCallback<Empty>, AutoCloseable, ConnectedGraphTrigger {
61     private static final Logger LOG = LoggerFactory.getLogger(PathManagerProvider.class);
62     private final InstanceIdentifier<Topology> pcepTopology;
63     private final DataBroker dataBroker;
64     private final DefaultPceServerProvider pceServerProvider;
65     private final AddLsp addLsp;
66     private final UpdateLsp updateLsp;
67     private final RemoveLsp removeLsp;
68     private TransactionChain chain = null;
69     private ConnectedGraph tedGraph = null;
70
71     private final Map<NodeId, ManagedTeNode> mngNodes = new HashMap<>();
72
73     public PathManagerProvider(final DataBroker dataBroker,
74             final KeyedInstanceIdentifier<Topology, TopologyKey> topology, final RpcService rpcService,
75             final DefaultPceServerProvider pceServerProvider) {
76         this.dataBroker = requireNonNull(dataBroker);
77         this.pceServerProvider = requireNonNull(pceServerProvider);
78         addLsp = rpcService.getRpc(AddLsp.class);
79         updateLsp = rpcService.getRpc(UpdateLsp.class);
80         removeLsp = rpcService.getRpc(RemoveLsp.class);
81         pcepTopology = requireNonNull(topology);
82         initTransactionChain();
83         tedGraph = getGraph();
84         LOG.info("Path Manager Server started for topology {}", topology.getKey().getTopologyId().getValue());
85     }
86
87     /**
88      * Remove the Path Manager Server and destroy the transaction chain.
89      */
90     @Override
91     @Deactivate
92     @PreDestroy
93     public void close() {
94         tedGraph = pceServerProvider.getTedGraph();
95         if (tedGraph != null) {
96             tedGraph.unRegisterTrigger(this, InstanceIdentifier.keyOf(pcepTopology));
97         }
98         destroyTransactionChain();
99     }
100
101     private ConnectedGraph getGraph() {
102         if (tedGraph == null) {
103             tedGraph = pceServerProvider.getTedGraph();
104             if (tedGraph != null) {
105                 tedGraph.registerTrigger(this, InstanceIdentifier.keyOf(pcepTopology));
106             }
107         }
108         return tedGraph;
109     }
110
111     /**
112      * Reset a transaction chain by closing the current chain and starting a new one.
113      */
114     private synchronized void initTransactionChain() {
115         LOG.debug("Initializing transaction chain for Path Manager Server {}", this);
116         checkState(chain == null, "Transaction chain has to be closed before being initialized");
117         chain = dataBroker.createMergingTransactionChain();
118         chain.addCallback(this);
119     }
120
121     /**
122      * Destroy the current transaction chain.
123      */
124     private synchronized void destroyTransactionChain() {
125         if (chain != null) {
126             LOG.debug("Destroy transaction chain for Path Manager {}", this);
127             chain = null;
128         }
129     }
130
131     /**
132      * Reset the transaction chain only so that the PingPong transaction chain
133      * will become usable again. However, there will be data loss if we do not
134      * apply the previous failed transaction again
135      */
136     protected synchronized void resetTransactionChain() {
137         LOG.debug("Resetting transaction chain for Path Manager");
138         destroyTransactionChain();
139         initTransactionChain();
140     }
141
142     @Override
143     public synchronized void onFailure(final Throwable cause) {
144         LOG.error("Path Manager Provider for {}", pcepTopology, cause);
145     }
146
147     @Override
148     public void onSuccess(final Empty value) {
149         LOG.info("Path Manager Provider for {} shut down", pcepTopology);
150     }
151
152     /**
153      * Setup Managed TE Path to existing Managed Node.
154      *
155      * @param teNode    Managed TE Node where the TE Path will be enforced
156      * @param lsp       TE Path to be inserted in the Managed Node
157      *
158      * @return          Newly created Managed TE Path
159      */
160     private ManagedTePath addManagedTePath(final ManagedTeNode teNode, final ConfiguredLsp lsp) {
161         checkArgument(teNode != null, "Provided Managed TE Node is a null object");
162         checkArgument(lsp != null, "Provided TE Path is a null object");
163
164         LOG.info("Setup TE Path {} for Node {}", lsp.getName(), teNode.getId());
165
166         final PathComputationImpl pci = (PathComputationImpl) pceServerProvider.getPathComputation();
167         /* Create Corresponding Managed LSP */
168         final ManagedTePath mngLsp =
169             new ManagedTePath(
170                     teNode,
171                     /* Complete the LSP with the Computed Route */
172                     new ConfiguredLspBuilder(lsp)
173                         .setPathStatus(PathStatus.Configured)
174                         .setComputedPath(
175                             pci == null
176                                 ? new ComputedPathBuilder().setComputationStatus(ComputationStatus.Failed).build()
177                                 : pci.computeTePath(lsp.getIntendedPath()))
178                         .build(),
179                     pcepTopology)
180                 .setType(PathType.Initiated);
181
182         /* Store this new Managed TE Node */
183         teNode.addManagedTePath(mngLsp);
184
185         /* Then, setup Path on PCC if it is synchronized */
186         if (teNode.isSync()) {
187             mngLsp.addPath(addLsp);
188         }
189
190         LOG.debug("Added new Managed LSP: {}", mngLsp);
191         return mngLsp;
192     }
193
194     /**
195      * Update TE Path to existing Managed Node.
196      *
197      * @param mngPath  Managed TE Path to be updated
198      * @param tePath   New TE Path to be updated in the Managed Node
199      */
200     private ConfiguredLsp updateManagedTePath(final ManagedTePath mngPath, final ConfiguredLsp tePath) {
201         checkArgument(mngPath != null, "Provided Managed TE Path is a null object");
202         checkArgument(tePath != null, "Provided TE Path is a null object");
203
204         final ManagedTeNode teNode = mngPath.getManagedTeNode();
205         final IntendedPath iPath = tePath.getIntendedPath();
206         final IntendedPath oPath = mngPath.getLsp().getIntendedPath();
207         IntendedPathBuilder ipb = new IntendedPathBuilder(iPath);
208
209         LOG.info("Update TE Path {} for Node {}", mngPath.getLsp().getName(), teNode.getId());
210
211         /* Check that Source and Destination have not been modified and revert to old value instead */
212         if (!iPath.getSource().equals(oPath.getSource())) {
213             LOG.warn("Source IP Address {}/{} of TE Path has been modified. Revert to initial one",
214                     iPath.getSource(), oPath.getSource());
215             ipb.setSource(oPath.getSource());
216         }
217         if (!iPath.getDestination().equals(oPath.getDestination())) {
218             LOG.warn("Destination IP Address {}/{} of TE Path has been modified. Revert to initial one",
219                     iPath.getDestination(), oPath.getDestination());
220             ipb.setDestination(oPath.getDestination());
221         }
222
223         /* Same for Address Family i.e. refused to change a TE Path from RSVP-TE to Segment Routing and vice versa */
224         if (!iPath.getConstraints().getAddressFamily().equals(oPath.getConstraints().getAddressFamily())) {
225             LOG.warn("Address Family {}/{} of TE Path has been modified. Revert to initial one",
226                     iPath.getConstraints().getAddressFamily(), oPath.getConstraints().getAddressFamily());
227             ipb.setConstraints(new ConstraintsBuilder(iPath.getConstraints())
228                     .setAddressFamily(oPath.getConstraints().getAddressFamily()).build());
229         }
230
231         /* Create updated TE Path */
232         final PathComputationImpl pci = (PathComputationImpl) pceServerProvider.getPathComputation();
233         mngPath.setConfiguredLsp(
234             new ConfiguredLspBuilder(tePath)
235                 .setIntendedPath(ipb.build())
236                 .setPathStatus(PathStatus.Updated)
237                 /* Complete it with the new Computed Route */
238                 .setComputedPath(
239                     pci == null
240                         ? new ComputedPathBuilder().setComputationStatus(ComputationStatus.Failed).build()
241                         : pci.computeTePath(tePath.getIntendedPath()))
242                 .build());
243
244         /* Finally, update the new TE Path for this Node ID */
245         mngPath.updateToDataStore();
246
247         /* Finally, update Path on PCC if it is synchronized and we computed a valid path */
248         if (teNode.isSync()) {
249             mngPath.updatePath(updateLsp);
250         }
251
252         LOG.debug("Updated Managed Paths: {}", mngPath);
253         return mngPath.getLsp();
254     }
255
256
257     /**
258      * Update Computed Path to an existing Managed TE Path.
259      *
260      * @param mngPath  Managed TE Path to be updated
261      */
262     private void updateComputedPath(final ManagedTePath mngPath, final boolean add) {
263         checkArgument(mngPath != null, "Provided Managed TE Path is a null object");
264
265         final ManagedTeNode teNode = mngPath.getManagedTeNode();
266
267         LOG.info("Update Computed Path for Managed TE Path {}", mngPath.getLsp().getName());
268
269         /* Update the TE Path with the new computed path */
270         final PathComputationImpl pci = (PathComputationImpl) pceServerProvider.getPathComputation();
271         mngPath.setConfiguredLsp(
272             new ConfiguredLspBuilder(mngPath.getLsp())
273                 .setPathStatus(PathStatus.Updated)
274                 .setComputedPath(
275                     /* Compute new Route */
276                     pci == null
277                         ? new ComputedPathBuilder().setComputationStatus(ComputationStatus.Failed).build()
278                         : pci.computeTePath(mngPath.getLsp().getIntendedPath()))
279                 .build());
280
281         if (add) {
282             mngPath.addToDataStore();
283         } else {
284             mngPath.updateToDataStore();
285         }
286
287         /* Finally, update Path on PCC if it is synchronized and computed path is valid */
288         if (teNode.isSync()) {
289             if (add) {
290                 mngPath.addPath(addLsp);
291             } else {
292                 mngPath.updatePath(updateLsp);
293             }
294         } else {
295             mngPath.unSetTriggerFlag();
296         }
297
298         LOG.debug("Computed new path: {}", mngPath.getLsp().getComputedPath());
299     }
300
301     /**
302      * Create a new Managed TE Path.
303      *
304      * @param id        Managed TE Node Identifier to which the TE path is attached.
305      * @param cfgLsp    TE Path.
306      *
307      * @return          new or updated TE Path i.e. original TE Path augmented by a valid computed route.
308      */
309     public ConfiguredLsp createManagedTePath(final NodeId id, final ConfiguredLsp cfgLsp) {
310         checkArgument(id != null, "Provided Node ID is a null object");
311         checkArgument(cfgLsp != null, "Provided TE Path is a null object");
312
313         /* Check that Managed Node is registered */
314         final ManagedTeNode teNode = mngNodes.get(id);
315         if (teNode == null) {
316             LOG.warn("Managed TE Node {} is not registered. Cancel transaction!", id);
317             return null;
318         }
319
320         /* Check if TE Path already exist or not */
321         ManagedTePath tePath = teNode.getManagedTePath(cfgLsp.key());
322         if (tePath != null) {
323             updateManagedTePath(tePath, cfgLsp);
324             tePath.updateToDataStore();
325         } else {
326             tePath = addManagedTePath(teNode, cfgLsp);
327             tePath.addToDataStore();
328         }
329
330         return tePath.getLsp();
331     }
332
333     /**
334      * Remove TE Path to existing Managed Node. This method is called when a TE Path is deleted.
335      *
336      * @param id   Managed Node ID where the TE Path is stored
337      * @param key  TE Path, as Key, to be removed
338      */
339     private void removeTePath(final NodeId id, final ConfiguredLspKey key) {
340         LOG.info("Remove TE Path {} for Node {}", key, id);
341
342         /* Check that Managed Node is registered */
343         final ManagedTeNode teNode = mngNodes.get(id);
344         if (teNode == null) {
345             LOG.warn("Managed TE Node {} is not registered. Cancel transaction!", id);
346             return;
347         }
348
349         /* Get corresponding TE Path from the TE Node */
350         ManagedTePath mngPath = teNode.getManagedTePath(key);
351         if (mngPath == null) {
352             LOG.warn("Doesn't found Managed TE Path {} for TE Node {}. Abort delete operation", key, id);
353             return;
354         }
355
356         /*
357          * Delete TE Path on PCC node if it is synchronized, TE Path is Initiated and is enforced on the PCC.
358          * TE Path will be removed from Data Store once received the PcReport.
359          */
360         if (teNode.isSync() && mngPath.getType() == PathType.Initiated
361                 && mngPath.getLsp().getPathStatus() == PathStatus.Sync) {
362             mngPath.removePath(removeLsp);
363         }
364
365         /*
366          * If TE Path is not Initiated or there is a failure to remove it on PCC,
367          * remove immediately TE Path from the Data Store.
368          */
369         if (!mngPath.isSent()) {
370             unregisterTePath(id, key);
371         }
372     }
373
374     /**
375      * Remove TE Path to existing Managed Node if TE Path has been initiated by the PCE server.
376      *
377      * @param id   Managed Node ID where the TE Path is stored
378      * @param key  TE Path, as Key, to be removed
379      */
380     public void deleteManagedTePath(final NodeId id, final ConfiguredLspKey key) {
381         checkArgument(id != null, "Provided Node ID is a null object");
382         checkArgument(key != null, "Provided TE Path Key is a null object");
383
384         /* Check that Managed Node is registered */
385         final ManagedTeNode teNode = mngNodes.get(id);
386         if (teNode == null) {
387             LOG.warn("Managed TE Node {} is not registered. Cancel transaction!", id);
388             return;
389         }
390
391         ManagedTePath mngPath = teNode.getManagedTePath(key);
392         if (mngPath == null) {
393             LOG.warn("Managed TE Path {} for TE Node {} doesn't exist", key, id);
394             return;
395         }
396
397         /*
398          * Start by sending corresponding Message to PCC if TE Path is initiated.
399          * TE Path will be removed when PCC confirm the deletion with PcReport.
400          * If TE Path is not initiated, the TE Path should be removed by the PCC
401          * by sending appropriate PcReport which is handle in unregisterTePath.
402          */
403         if (teNode.isSync() && mngPath.getType() == PathType.Initiated) {
404             removeTePath(id, key);
405         } else {
406             LOG.warn("Managed TE Path {} for TE Node {} is not managed by this PCE. Remove only configuration",
407                     key, id);
408         }
409     }
410
411     /**
412      * Register Reported LSP as a TE Path for the PCC identified by its Node ID.
413      *
414      * @param id        Node ID of the Managed Node (PCC) which report this LSP
415      * @param rptPath   Reported TE Path
416      *
417      * @return          Newly created or Updated Managed TE Path
418      */
419     public ManagedTePath registerTePath(final NodeId id, final ConfiguredLsp rptPath, final PathType ptype) {
420         checkArgument(id != null, "Provided Node ID is a null object");
421
422         /* Verify we got a valid reported TE Path */
423         if (rptPath == null) {
424             return null;
425         }
426
427         /* Check that Managed Node is registered */
428         final ManagedTeNode teNode = mngNodes.get(id);
429         if (teNode == null) {
430             LOG.warn("Managed TE Node {} is not registered. Cancel transaction!", id);
431             return null;
432         }
433
434         LOG.info("Registered TE Path {} for Node {}", rptPath, id);
435
436         /* Look for existing corresponding Managed TE Path */
437         final ManagedTePath curPath = teNode.getManagedTePath(rptPath.key());
438
439         if (curPath == null) {
440             final ManagedTePath newPath = new ManagedTePath(teNode, pcepTopology).setType(ptype);
441             /* Check if ERO needs to be updated i.e. Path Description is empty */
442             if (rptPath.getComputedPath().getPathDescription() == null) {
443                 /* Finally, update the new TE Path for this Node ID */
444                 final PathComputationImpl pci = (PathComputationImpl) pceServerProvider.getPathComputation();
445                 newPath.setConfiguredLsp(
446                     new ConfiguredLspBuilder(rptPath)
447                         .setPathStatus(PathStatus.Updated)
448                         .setComputedPath(
449                             /* Complete the TE Path with Computed Route */
450                             pci == null
451                                 ? new ComputedPathBuilder().setComputationStatus(ComputationStatus.Failed).build()
452                                 : pci.computeTePath(rptPath.getIntendedPath()))
453                         .build());
454                 /* and update Path on PCC if it is synchronized */
455                 if (teNode.isSync()) {
456                     newPath.updatePath(updateLsp);
457                 }
458             } else {
459                 /* Mark this TE Path as Synchronous and add it to the Managed TE Path */
460                 newPath.setConfiguredLsp(new ConfiguredLspBuilder(rptPath).setPathStatus(PathStatus.Sync).build());
461             }
462
463             /* Update Reserved Bandwidth and Add triggers in the Connected Graph */
464             newPath.setGraph(getGraph());
465
466             /* Store this new reported TE Path */
467             teNode.addManagedTePath(newPath);
468
469             LOG.debug("Created new Managed TE Path: {}", newPath);
470             return newPath;
471         }
472
473         /*
474          * If PCE restart, it will consider all configured TE Path as Initiated, while some of configurations
475          * concern only Delegate Path. Thus, It is necessary to verify the Path Type and correct them:
476          * i.e. a reported TE Path, if not Initiated, will overwrite an Initiated configured TE Path.
477          */
478         if (curPath.getType() == PathType.Initiated && ptype != PathType.Initiated) {
479             LOG.debug("Reset Path Type to {} for Managed TE Path {}", ptype, curPath.getLsp().getName());
480             curPath.setType(ptype);
481         }
482
483         /* Check this TE Path against current configuration */
484         final PathStatus newStatus = curPath.checkReportedPath(rptPath);
485         LOG.debug("Managed TE Path {} got new status {}", curPath.getLsp().getName(), newStatus);
486
487         /* Check if we should stop here. i.e. the Path is failed */
488         if (newStatus == PathStatus.Failed) {
489             curPath.setConfiguredLsp(new ConfiguredLspBuilder(rptPath).setPathStatus(PathStatus.Failed).build());
490             curPath.updateToDataStore();
491             /* Path is in failure. Reset Trigger Flag to authorize future path re-computation */
492             curPath.unSetTriggerFlag();
493             LOG.debug("Managed TE Path {} is in Failure", curPath);
494             return curPath;
495         }
496
497         /* Check if Current Path has no valid route while Reported Path has one */
498         if (curPath.getLsp().getComputedPath().getPathDescription() == null
499                 && rptPath.getComputedPath().getPathDescription() != null) {
500             curPath.setConfiguredLsp(new ConfiguredLspBuilder(rptPath).setPathStatus(PathStatus.Sync).build());
501             curPath.updateGraph(getGraph());
502             curPath.updateToDataStore();
503             LOG.debug("Updated Managed TE Path with reported LSP: {}", curPath);
504             return curPath;
505         }
506
507         /* Check if we need to update the TE Path */
508         if (teNode.isSync() && newStatus == PathStatus.Updated) {
509             curPath.updatePath(updateLsp);
510             LOG.debug("Updated Managed TE Path {} on NodeId {}", curPath, id);
511             return curPath;
512         }
513
514         /* Check if TE Path becoming in SYNC */
515         if (newStatus == PathStatus.Sync && curPath.getLsp().getPathStatus() != PathStatus.Sync) {
516             curPath.sync();
517             curPath.updateGraph(getGraph());
518             LOG.debug("Sync Managed TE Path {} on NodeId {}", curPath, id);
519             return curPath;
520         }
521
522         /* Managed Path is already in SYNC, nothing to do */
523         return curPath;
524     }
525
526     /**
527      * Remove TE Path from Operational Data Store and Path Manager.
528      *
529      * @param id    Node ID of the Managed Node which own this TE Path
530      * @param key   TE Path name
531      */
532     public void unregisterTePath(final NodeId id, final ConfiguredLspKey key) {
533         checkArgument(id != null, "Provided Node ID is a null object");
534         checkArgument(key != null, "Provided TE Path Key is a null object");
535
536         /* Verify that Node is managed by the PCE Server */
537         final ManagedTeNode teNode = mngNodes.get(id);
538         if (teNode == null) {
539             LOG.warn("There is no Managed TE Node entry for this PCC {}", id);
540             return;
541         }
542
543         /* Remove the TE Path and associated Bandwidth if any */
544         final ManagedTePath tePath = teNode.removeManagedTePath(key);
545         if (tePath != null) {
546             tePath.unsetGraph(getGraph());
547         }
548     }
549
550     /**
551      * Indicate that the TE Path is failed following reception of a PCE Error message.
552      *
553      * @param id    Node ID of the Managed Node which own this TE Path
554      * @param key   TE Path name
555      */
556     public void setTePathFailed(final NodeId id, final ConfiguredLspKey key) {
557         checkArgument(id != null, "Provided Node ID is a null object");
558         checkArgument(key != null, "Provided TE Path Key is a null object");
559
560         /* Verify that Node is managed by the PCE Server */
561         final ManagedTeNode teNode = mngNodes.get(id);
562         if (teNode == null) {
563             LOG.warn("There is no Managed TE Node entry for this PCC {}", id);
564             return;
565         }
566
567         /* Get Corresponding TE Path */
568         ManagedTePath mngPath = teNode.getManagedTePath(key);
569         if (mngPath != null) {
570             mngPath.failed();
571         } else {
572             LOG.warn("TE Path {} for Node {} doesn't exist", key, id);
573         }
574     }
575
576     /**
577      * Check if a Managed TE Node is controlled by the Path Manager.
578      *
579      * @param id    Node ID of the Managed TE Node
580      *
581      * @return      True if Managed TE Node exist, false otherwise
582      */
583     public boolean checkManagedTeNode(final NodeId id) {
584         return mngNodes.get(id) != null;
585     }
586
587     /**
588      * Create new Managed TE Node. This method is called by a new Managed Node is created in the Configuration
589      * Data Store. All TE Path associated to this Managed Node are also created. A new Managed Node, with TE Paths
590      * augmented with valid computed routes, is stored in the Operational Data Store.
591      *
592      * @param nodeId  Managed TE Node Identifier
593      * @param pccNode Path Computation Client
594      *
595      * @return        New Managed TE Node.
596      */
597     public synchronized ManagedTeNode createManagedTeNode(final NodeId nodeId, final PcepNodeConfig pccNode) {
598         checkArgument(pccNode != null, "Provided Managed TE Node is a null object");
599
600         /* First, create new Managed TE Node */
601         ManagedTeNode teNode = new ManagedTeNode(nodeId, chain);
602         mngNodes.put(nodeId, teNode);
603
604         /* Then, create all TE Paths for this Managed Node */
605         if (pccNode.getConfiguredLsp() != null) {
606             for (ConfiguredLsp tePath: pccNode.getConfiguredLsp().values()) {
607                 addManagedTePath(teNode, tePath);
608             }
609         }
610
611         LOG.info("Created new Managed TE Node {}", nodeId);
612
613         return teNode;
614     }
615
616     /**
617      * Register a PCC as a new Managed TE Node. This method is called by the PCEP Topology Listener when a new PCC
618      * connects to the PCE Server.
619      *
620      * @param id    Node ID of the PCC
621      *
622      * @return      current or new Managed TE Node
623      */
624     public synchronized ManagedTeNode registerManagedTeNode(final NodeId id) {
625         checkArgument(id != null, "Provided Managed Node ID is a null object");
626
627         ManagedTeNode teNode = mngNodes.get(id);
628         /* Create new Managed TE Node if not already exist */
629         if (teNode == null) {
630             teNode = new ManagedTeNode(id, chain);
631             mngNodes.put(id, teNode);
632             LOG.debug("Created new Managed TE Node: {}", teNode);
633         }
634         return teNode;
635     }
636
637     /**
638      * Synchronized Managed TE Node. Once PCC finished initial report of all LSP, its state change to Synchronized.
639      * This function update the Managed TE Node status, and then parse all reported LSPs to determine if:
640      *  - There is missing LSPs that need to be setup
641      *  - There is LSPs that need to be updated
642      *
643      * @param id    Node ID of the Managed TE Node
644      */
645     public void syncManagedTeNode(final NodeId id) {
646         checkArgument(id != null, "Provided Managed Node ID is a null object");
647
648         /* Verify that Node is managed by the PCE Server */
649         final ManagedTeNode teNode = mngNodes.get(id);
650         if (teNode == null) {
651             LOG.warn("There is no Managed TE Node entry for this PCC {}", id);
652             return;
653         }
654
655         if (teNode.isSync()) {
656             LOG.debug("PCC {} is already synchronised", id);
657             return;
658         }
659
660         /* First, mark the Node as Synchronous */
661         teNode.sync();
662
663         /*
664          * PCC is synchronized, browse all Managed TE Path to check if:
665          *  - some are missing i.e. apply previously initiated paths that have been created before the PCC connects
666          *  - some need update i.e. apply previous modifications
667          * And for eligible Managed TE Path, give it a last chance to obtain a valid computed path. This is mandatory
668          * when ODL restart: Path Manager Configuration is read before a valid TED is available.
669          */
670         if (teNode.getTePaths() != null && !teNode.getTePaths().isEmpty()) {
671             for (ManagedTePath mngPath : teNode.getTePaths().values()) {
672                 switch (mngPath.getLsp().getPathStatus()) {
673                     case Updated:
674                         if (mngPath.getLsp().getComputedPath().getComputationStatus() != ComputationStatus.Completed) {
675                             updateComputedPath(mngPath, false);
676                         } else {
677                             mngPath.updatePath(updateLsp);
678                         }
679                         break;
680                     case Configured:
681                         if (mngPath.getLsp().getComputedPath().getComputationStatus() != ComputationStatus.Completed) {
682                             updateComputedPath(mngPath, true);
683                         } else {
684                             mngPath.addPath(addLsp);
685                         }
686                         break;
687                     default:
688                         break;
689                 }
690             }
691         }
692     }
693
694     /**
695      * Delete Managed TE Node. This method is called when a Managed Node is removed from the Configuration Data Store.
696      * All initiated Managed TE Path own by this PCC are removed and corresponding Managed Node is removed from the
697      * Operational Data Store if it is not connected.
698      *
699      * @param nodeId  Managed Node Identifier
700      */
701     public void deleteManagedTeNode(final NodeId nodeId) {
702         checkArgument(nodeId != null, "Provided Node Identifie is a null object");
703
704         /* Verify that Node is managed by the PCE Server */
705         final ManagedTeNode teNode = mngNodes.get(nodeId);
706         if (teNode == null) {
707             LOG.warn("Unknown Managed TE Node {}. Abort!", nodeId);
708             return;
709         }
710
711         /* Remove all associated TE Paths that are managed by the PCE */
712         for (ManagedTePath mngPath : teNode.getTePaths().values()) {
713             if (mngPath.getType() == PathType.Initiated) {
714                 removeTePath(nodeId, mngPath.getLsp().key());
715             }
716         }
717
718         /* Remove Managed Node from PCE Server if it is not connected */
719         if (!teNode.isSync()) {
720             mngNodes.remove(nodeId);
721         } else {
722             LOG.warn("Node {} is still connected. Keep Node in PCE Server.", nodeId);
723         }
724     }
725
726     /**
727      * Call when a PCC disconnect from the PCE to disable the corresponding Managed TE Node.
728      *
729      * @param id    Managed Node ID
730      */
731     public void disableManagedTeNode(final NodeId id) {
732         checkArgument(id != null, "Provided Node ID is a null object");
733
734         /* Verify that Node is managed by the PCE Server */
735         final ManagedTeNode teNode = mngNodes.get(id);
736         if (teNode == null) {
737             LOG.warn("Unknown Managed TE Node {}. Abort!", id);
738             return;
739         }
740
741         /* And mark the Node as disable */
742         teNode.disable();
743     }
744
745     @Override
746     public void verifyVertex(final Collection<ConnectedVertexTrigger> triggers, final ConnectedVertex current,
747             final Vertex next) {
748         for (ConnectedVertexTrigger trigger : triggers) {
749             if (trigger.verifyVertex(current, next)) {
750                 updateComputedPath((ManagedTePath )trigger, false);
751             }
752         }
753     }
754
755     @Override
756     public void verifyEdge(final Collection<ConnectedEdgeTrigger> triggers, final ConnectedEdge current,
757             final Edge next) {
758         for (ConnectedEdgeTrigger trigger : triggers) {
759             if (trigger.verifyEdge(current, next)) {
760                 updateComputedPath((ManagedTePath )trigger, false);
761             }
762         }
763     }
764 }