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