2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.bgpcep.pcep.topology.provider;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.Iterables;
13 import com.google.common.collect.Maps;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import io.netty.util.concurrent.FutureListener;
20 import java.net.InetAddress;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.List;
26 import java.util.Map.Entry;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Timer;
30 import java.util.TimerTask;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicBoolean;
34 import org.checkerframework.checker.lock.qual.GuardedBy;
35 import org.checkerframework.checker.lock.qual.Holding;
36 import org.eclipse.jdt.annotation.NonNull;
37 import org.eclipse.jdt.annotation.Nullable;
38 import org.opendaylight.bgpcep.pcep.topology.provider.session.stats.SessionStateImpl;
39 import org.opendaylight.bgpcep.pcep.topology.provider.session.stats.TopologySessionStats;
40 import org.opendaylight.mdsal.binding.api.WriteTransaction;
41 import org.opendaylight.mdsal.common.api.CommitInfo;
42 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
43 import org.opendaylight.protocol.pcep.PCEPCloseTermination;
44 import org.opendaylight.protocol.pcep.PCEPSession;
45 import org.opendaylight.protocol.pcep.PCEPTerminationReason;
46 import org.opendaylight.protocol.pcep.TerminationReason;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Stateful1;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.LspObject;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.StatefulTlv1Builder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Object;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1Builder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TearDownSessionInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.lsp.metadata.Metadata;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.PathKey;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
76 import org.opendaylight.yangtools.yang.binding.DataObject;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
84 * Base class for PCEP topology providers. It handles the common tasks involved in managing a PCEP server (PCE)
85 * endpoint, and exposing a network topology based on it. It needs to be subclassed to form a fully functional block,
86 * where the subclass provides handling of incoming messages.
88 public abstract class AbstractTopologySessionListener implements TopologySessionListener, TopologySessionStats {
89 private static final Logger LOG = LoggerFactory.getLogger(AbstractTopologySessionListener.class);
91 private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
92 private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
93 private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
96 final Map<PlspId, String> lsps = new HashMap<>();
98 SessionStateImpl listenerState;
101 private final Map<SrpIdNumber, PCEPRequest> requests = new HashMap<>();
103 private final Map<String, ReportedLsp> lspData = new ConcurrentHashMap<>();
104 private final ServerSessionManager serverSessionManager;
105 private InstanceIdentifier<PathComputationClient> pccIdentifier;
107 private TopologyNodeState nodeState;
108 private final AtomicBoolean synced = new AtomicBoolean(false);
110 private PCEPSession session;
112 private SyncOptimization syncOptimization;
114 private boolean triggeredResyncInProcess;
116 AbstractTopologySessionListener(final ServerSessionManager serverSessionManager) {
117 this.serverSessionManager = requireNonNull(serverSessionManager);
121 public final void onSessionUp(final PCEPSession psession) {
122 synchronized (serverSessionManager) {
123 synchronized (this) {
125 * The session went up. Look up the router in Inventory model, create it if it
126 * is not there (marking that fact for later deletion), and mark it as
127 * synchronizing. Also create it in the topology model, with empty LSP list.
129 final InetAddress peerAddress = psession.getRemoteAddress();
131 syncOptimization = new SyncOptimization(psession);
132 final boolean haveLspDbVersion = syncOptimization.isDbVersionPresent();
134 final TopologyNodeState state =
135 serverSessionManager.takeNodeState(peerAddress, this, haveLspDbVersion);
137 // takeNodeState(..) may fail when the server session manager is being restarted
138 // due to configuration change
140 LOG.error("Unable to fetch topology node state for PCEP session. Closing session {}", psession);
141 psession.close(TerminationReason.UNKNOWN);
142 onSessionTerminated(psession, new PCEPCloseTermination(TerminationReason.UNKNOWN));
146 if (session != null || nodeState != null) {
147 LOG.error("PCEP session is already up with {}. Closing session {}", peerAddress, psession);
148 psession.close(TerminationReason.UNKNOWN);
149 onSessionTerminated(psession, new PCEPCloseTermination(TerminationReason.UNKNOWN));
155 LOG.trace("Peer {} resolved to topology node {}", peerAddress, state.getNodeId());
157 // Our augmentation in the topology node
158 final PathComputationClientBuilder pccBuilder = new PathComputationClientBuilder()
159 .setIpAddress(IetfInetUtil.INSTANCE.ipAddressNoZoneFor(peerAddress));
161 // Let subclass fill the details
162 updateStatefulCapabilities(pccBuilder, peerAddress, psession.getRemoteTlvs());
164 synced.set(isSynchronized());
166 final InstanceIdentifier<Node1> topologyAugment = state.getNodeId().augmentation(Node1.class);
167 pccIdentifier = topologyAugment.child(PathComputationClient.class);
169 if (haveLspDbVersion) {
170 final Node initialNodeState = state.getInitialNodeState();
171 if (initialNodeState != null) {
172 loadLspData(initialNodeState, lspData, lsps, isIncrementalSynchro());
173 pccBuilder.setReportedLsp(
174 initialNodeState.augmentation(Node1.class).getPathComputationClient().getReportedLsp());
177 state.storeNode(topologyAugment,
178 new Node1Builder().setPathComputationClient(pccBuilder.build()).build(), psession);
180 listenerState = new SessionStateImpl(this, psession);
181 serverSessionManager.bind(state.getNodeId(), listenerState);
182 LOG.info("Session with {} attached to topology node {}", peerAddress, state.getNodeId());
188 private void updateStatefulCapabilities(final PathComputationClientBuilder pccBuilder,
189 final InetAddress peerAddress, final @Nullable Tlvs remoteTlvs) {
190 if (remoteTlvs != null) {
191 final Tlvs1 statefulTlvs = remoteTlvs.augmentation(Tlvs1.class);
192 if (statefulTlvs != null) {
193 final Stateful stateful = statefulTlvs.getStateful();
194 if (stateful != null) {
195 statefulCapability.set(true);
196 final var updateCap = stateful.getLspUpdateCapability();
197 if (updateCap != null) {
198 lspUpdateCapability.set(updateCap);
200 final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
201 if (stateful1 != null) {
202 final var initiation = stateful1.getInitiation();
203 if (initiation != null) {
204 initiationCapability.set(initiation);
208 pccBuilder.setReportedLsp(Map.of());
209 if (isSynchronized()) {
210 pccBuilder.setStateSync(PccSyncState.Synchronized);
211 } else if (isTriggeredInitialSynchro()) {
212 pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
213 } else if (isIncrementalSynchro()) {
214 pccBuilder.setStateSync(PccSyncState.IncrementalSync);
216 pccBuilder.setStateSync(PccSyncState.InitialResync);
218 pccBuilder.setStatefulTlv(new StatefulTlvBuilder()
219 .addAugmentation(new StatefulTlv1Builder(statefulTlvs).build())
225 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
228 synchronized void updatePccState(final PccSyncState pccSyncState) {
229 if (nodeState == null) {
230 LOG.info("Server Session Manager is closed.");
231 session.close(TerminationReason.UNKNOWN);
234 final MessageContext ctx = new MessageContext(nodeState.getChain().newWriteOnlyTransaction());
235 updatePccNode(ctx, new PathComputationClientBuilder().setStateSync(pccSyncState).build());
236 if (pccSyncState != PccSyncState.Synchronized) {
238 triggeredResyncInProcess = true;
240 // All set, commit the modifications
241 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
243 public void onSuccess(final CommitInfo result) {
244 LOG.trace("Pcc Internal state for session {} updated successfully", session);
248 public void onFailure(final Throwable cause) {
249 LOG.error("Failed to update Pcc internal state for session {}", session, cause);
250 session.close(TerminationReason.UNKNOWN);
252 }, MoreExecutors.directExecutor());
255 synchronized boolean isTriggeredSyncInProcess() {
256 return triggeredResyncInProcess;
260 * Tear down the given PCEP session. It's OK to call this method even after the session
261 * is already down. It always clear up the current session status.
263 @SuppressWarnings("checkstyle:IllegalCatch")
264 private void tearDown(final PCEPSession psession) {
265 requireNonNull(psession);
266 synchronized (serverSessionManager) {
267 synchronized (this) {
268 serverSessionManager.releaseNodeState(nodeState, psession.getRemoteAddress(), isLspDbPersisted());
272 if (session != null) {
276 } catch (final Exception e) {
277 LOG.error("Session {} cannot be closed.", psession, e);
280 listenerState = null;
281 syncOptimization = null;
283 // Clear all requests we know about
284 for (final Entry<SrpIdNumber, PCEPRequest> e : requests.entrySet()) {
285 final PCEPRequest r = e.getValue();
286 switch (r.getState()) {
288 // Done is done, nothing to do
289 LOG.trace("Request {} was done when session went down.", e.getKey());
292 // Peer has not acked: results in failure
293 LOG.info("Request {} was incomplete when session went down, failing the instruction",
295 r.done(OperationResults.NOACK);
298 // Peer has not been sent to the peer: results in cancellation
299 LOG.debug("Request {} was not sent when session went down, cancelling the instruction",
301 r.done(OperationResults.UNSENT);
313 public final void onSessionDown(final PCEPSession psession, final Exception exception) {
314 LOG.warn("Session {} went down unexpectedly", psession, exception);
319 public final void onSessionTerminated(final PCEPSession psession, final PCEPTerminationReason reason) {
320 LOG.info("Session {} terminated by peer with reason {}", psession, reason);
325 public final synchronized void onMessage(final PCEPSession psession, final Message message) {
326 if (nodeState == null) {
327 LOG.warn("Topology node state is null. Unhandled message {} on session {}", message, psession);
328 psession.close(TerminationReason.UNKNOWN);
331 final MessageContext ctx = new MessageContext(nodeState.getChain().newWriteOnlyTransaction());
333 if (onMessage(ctx, message)) {
334 LOG.warn("Unhandled message {} on session {}", message, psession);
335 //cancel not supported, submit empty transaction
336 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
338 public void onSuccess(final CommitInfo result) {
339 LOG.trace("Successful commit");
343 public void onFailure(final Throwable trw) {
344 LOG.error("Failed commit", trw);
346 }, MoreExecutors.directExecutor());
350 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
352 public void onSuccess(final CommitInfo result) {
353 LOG.trace("Internal state for session {} updated successfully", psession);
354 ctx.notifyRequests();
359 public void onFailure(final Throwable throwable) {
360 LOG.error("Failed to update internal state for session {}, closing it", psession, throwable);
361 ctx.notifyRequests();
362 psession.close(TerminationReason.UNKNOWN);
364 }, MoreExecutors.directExecutor());
368 * Perform revision-specific message processing when a message arrives.
370 * @param ctx Message processing context
371 * @param message Protocol message
372 * @return True if the message type is not handle.
374 protected abstract boolean onMessage(MessageContext ctx, Message message);
377 public void close() {
378 synchronized (serverSessionManager) {
379 synchronized (this) {
381 if (session != null) {
382 LOG.info("Closing session {}", session);
383 session.close(TerminationReason.UNKNOWN);
389 @Holding({"this.serverSessionManager", "this"})
390 private void clearNodeState() {
391 if (nodeState != null) {
392 serverSessionManager.unbind(nodeState.getNodeId());
393 LOG.debug("Clear Node state: {}", nodeState.getNodeId());
398 final synchronized PCEPRequest removeRequest(final SrpIdNumber id) {
399 final PCEPRequest ret = requests.remove(id);
400 if (ret != null && listenerState != null) {
401 listenerState.processRequestStats(ret.getElapsedMillis());
403 LOG.trace("Removed request {} object {}", id, ret);
407 final synchronized ListenableFuture<OperationResult> sendMessage(final Message message, final SrpIdNumber requestId,
408 final Metadata metadata) {
409 final var sendFuture = session.sendMessage(message);
410 listenerState.updateStatefulSentMsg(message);
411 final PCEPRequest req = new PCEPRequest(metadata);
412 requests.put(requestId, req);
413 final short rpcTimeout = serverSessionManager.getRpcTimeout();
414 LOG.trace("RPC response timeout value is {} seconds", rpcTimeout);
415 if (rpcTimeout > 0) {
416 setupTimeoutHandler(requestId, req, rpcTimeout);
419 sendFuture.addListener((FutureListener<Void>) future -> {
420 if (!future.isSuccess()) {
421 synchronized (AbstractTopologySessionListener.this) {
422 requests.remove(requestId);
424 req.done(OperationResults.UNSENT);
425 LOG.info("Failed to send request {}, instruction cancelled", requestId, future.cause());
428 LOG.trace("Request {} sent to peer (object {})", requestId, req);
432 return req.getFuture();
435 private void setupTimeoutHandler(final SrpIdNumber requestId, final PCEPRequest req, final short timeout) {
436 final Timer timer = req.getTimer();
437 timer.schedule(new TimerTask() {
440 synchronized (AbstractTopologySessionListener.this) {
441 requests.remove(requestId);
444 LOG.info("Request {} timed-out waiting for response", requestId);
446 }, TimeUnit.SECONDS.toMillis(timeout));
447 LOG.trace("Set up response timeout handler for request {}", requestId);
451 * Update an LSP in the data store.
453 * @param ctx Message context
454 * @param id Revision-specific LSP identifier
455 * @param lspName LSP name
456 * @param rlb Reported LSP builder
457 * @param solicited True if the update was solicited
458 * @param remove True if this is an LSP path removal
460 protected final synchronized void updateLsp(final MessageContext ctx, final PlspId id, final String lspName,
461 final ReportedLspBuilder rlb, final boolean solicited, final boolean remove) {
464 if (lspName == null) {
467 LOG.error("PLSPID {} seen for the first time, not reporting the LSP", id);
474 LOG.debug("Saved LSP {} with name {}", id, name);
477 final ReportedLsp previous = lspData.get(name);
478 // if no previous report about the lsp exist, just proceed
479 if (previous != null) {
480 final Map<PathKey, Path> updatedPaths = makeBeforeBreak(rlb, previous, name, remove);
481 // if all paths or the last path were deleted, delete whole tunnel
482 if (updatedPaths.isEmpty()) {
483 LOG.debug("All paths were removed, removing LSP with {}.", id);
487 rlb.setPath(updatedPaths);
489 rlb.withKey(new ReportedLspKey(name));
492 // If this is an unsolicited update. We need to make sure we retain the metadata already present
494 nodeState.setLspMetadata(name, rlb.getMetadata());
496 rlb.setMetadata(nodeState.getLspMetadata(name));
499 final ReportedLsp rl = rlb.build();
500 ctx.trans.put(LogicalDatastoreType.OPERATIONAL, pccIdentifier.child(ReportedLsp.class, rlb.key()), rl);
501 LOG.debug("LSP {} updated to MD-SAL", name);
503 lspData.put(name, rl);
506 private static Map<PathKey, Path> makeBeforeBreak(final ReportedLspBuilder rlb, final ReportedLsp previous,
507 final String name, final boolean remove) {
508 // just one path should be reported
509 final Path path = Iterables.getOnlyElement(rlb.getPath().values());
510 final var reportedLspId = path.getLspId();
511 final List<Path> updatedPaths;
512 //lspId = 0 and remove = false -> tunnel is down, still exists but no path is signaled
513 //remove existing tunnel's paths now, as explicit path remove will not come
514 if (!remove && reportedLspId.getValue().toJava() == 0) {
515 updatedPaths = new ArrayList<>();
516 LOG.debug("Remove previous paths {} to this lsp name {}", previous.getPath(), name);
518 // check previous report for existing paths
519 final Collection<Path> prev = previous.nonnullPath().values();
520 updatedPaths = new ArrayList<>(prev);
521 LOG.debug("Found previous paths {} to this lsp name {}", updatedPaths, name);
522 for (final Path prevPath : prev) {
523 //we found reported path in previous reports
524 if (prevPath.getLspId().getValue().toJava() == 0 || prevPath.getLspId().equals(reportedLspId)) {
525 LOG.debug("Match on lsp-id {}", prevPath.getLspId().getValue());
526 // path that was reported previously and does have the same lsp-id, path will be updated
527 final boolean r = updatedPaths.remove(prevPath);
528 LOG.trace("Request removed? {}", r);
532 // if the path does not exist in previous report, add it to path list, it's a new ERO
533 // only one path will be added
534 //lspId is 0 means confirmation message that shouldn't be added (because we have no means of deleting it later)
535 LOG.trace("Adding new path {} to {}", path, updatedPaths);
536 updatedPaths.add(path);
538 if (reportedLspId.getValue().toJava() == 0) {
539 // if lsp-id also 0, remove all paths
540 LOG.debug("Removing all paths.");
541 updatedPaths.clear();
543 // path is marked to be removed
544 LOG.debug("Removing path {} from {}", path, updatedPaths);
545 final boolean r = updatedPaths.remove(path);
546 LOG.trace("Request removed? {}", r);
549 LOG.debug("Setting new paths {} to lsp {}", updatedPaths, name);
550 return Maps.uniqueIndex(updatedPaths, Path::key);
554 * Indicate that the peer has completed state synchronization.
556 * @param ctx Message context
558 protected final synchronized void stateSynchronizationAchieved(final MessageContext ctx) {
559 if (synced.getAndSet(true)) {
560 LOG.debug("State synchronization achieved while synchronizing, not updating state");
564 triggeredResyncInProcess = false;
565 updatePccNode(ctx, new PathComputationClientBuilder().setStateSync(PccSyncState.Synchronized).build());
567 // The node has completed synchronization, cleanup metadata no longer reported back
568 nodeState.cleanupExcept(lsps.values());
569 LOG.debug("Session {} achieved synchronized state", session);
572 protected final synchronized void updatePccNode(final MessageContext ctx, final PathComputationClient pcc) {
573 ctx.trans.merge(LogicalDatastoreType.OPERATIONAL, pccIdentifier, pcc);
576 protected final @NonNull InstanceIdentifier<ReportedLsp> lspIdentifier(final String name) {
577 return pccIdentifier.child(ReportedLsp.class, new ReportedLspKey(name));
581 * Remove LSP from the database.
583 * @param ctx Message Context
584 * @param id Revision-specific LSP identifier
586 protected final synchronized void removeLsp(final MessageContext ctx, final PlspId id) {
587 final String name = lsps.remove(id);
588 LOG.debug("LSP {} removed", name);
589 ctx.trans.delete(LogicalDatastoreType.OPERATIONAL, lspIdentifier(name));
590 lspData.remove(name);
594 final String lookupLspName(final PlspId id) {
595 return lsps.get(requireNonNull(id, "ID parameter null."));
599 * Reads operational data on this node. Doesn't attempt to read the data,
600 * if the node does not exist. In this case returns null.
602 * @param id InstanceIdentifier of the node
603 * @return null if the node does not exists, or operational data
605 final synchronized <T extends DataObject> FluentFuture<Optional<T>> readOperationalData(
606 final InstanceIdentifier<T> id) {
607 return nodeState == null ? null : nodeState.readOperationalData(id);
610 protected abstract Object validateReportedLsp(Optional<ReportedLsp> rep, LspId input);
612 protected abstract void loadLspData(Node node, Map<String, ReportedLsp> lspData, Map<PlspId, String> lsps,
613 boolean incrementalSynchro);
615 final boolean isLspDbPersisted() {
616 return syncOptimization != null && syncOptimization.isSyncAvoidanceEnabled();
620 * Is Incremental synchronization if LSP-DB-VERSION are included,
621 * LSP-DB-VERSION TLV values doesnt match, and LSP-SYNC-CAPABILITY is enabled.
623 final synchronized boolean isIncrementalSynchro() {
624 return syncOptimization != null && syncOptimization.isSyncAvoidanceEnabled()
625 && syncOptimization.isDeltaSyncEnabled();
628 final synchronized boolean isTriggeredInitialSynchro() {
629 return syncOptimization != null && syncOptimization.isTriggeredInitSyncEnabled();
632 final synchronized boolean isTriggeredReSyncEnabled() {
633 return syncOptimization != null && syncOptimization.isTriggeredReSyncEnabled();
636 protected final synchronized boolean isSynchronized() {
637 return syncOptimization != null && syncOptimization.doesLspDbMatch();
641 public final int getDelegatedLspsCount() {
642 return Math.toIntExact(lspData.values().stream()
643 .map(ReportedLsp::getPath).filter(pathList -> pathList != null && !pathList.isEmpty())
644 // pick the first path, as delegate status should be same in each path
645 .map(pathList -> pathList.values().iterator().next())
646 .map(path -> path.augmentation(Path1.class)).filter(Objects::nonNull)
647 .map(LspObject::getLsp).filter(Objects::nonNull)
648 .filter(Lsp::getDelegate)
653 public final boolean isSessionSynchronized() {
658 public final boolean isInitiationCapability() {
659 return initiationCapability.get();
663 public final boolean isStatefulCapability() {
664 return statefulCapability.get();
668 public final boolean isLspUpdateCapability() {
669 return lspUpdateCapability.get();
674 public synchronized ListenableFuture<RpcResult<Void>> tearDownSession(final TearDownSessionInput input) {
676 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
679 static final class MessageContext {
680 private final Collection<PCEPRequest> requests = new ArrayList<>();
681 private final WriteTransaction trans;
683 private MessageContext(final WriteTransaction trans) {
684 this.trans = requireNonNull(trans);
687 void resolveRequest(final PCEPRequest req) {
691 private void notifyRequests() {
692 for (final PCEPRequest r : requests) {
693 r.done(OperationResults.SUCCESS);