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.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import io.netty.util.Timeout;
19 import io.netty.util.concurrent.Future;
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.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import org.checkerframework.checker.lock.qual.GuardedBy;
33 import org.checkerframework.checker.lock.qual.Holding;
34 import org.eclipse.jdt.annotation.NonNull;
35 import org.eclipse.jdt.annotation.Nullable;
36 import org.opendaylight.bgpcep.pcep.topology.provider.session.stats.SessionStateImpl;
37 import org.opendaylight.bgpcep.pcep.topology.provider.session.stats.TopologySessionStats;
38 import org.opendaylight.mdsal.binding.api.WriteTransaction;
39 import org.opendaylight.mdsal.common.api.CommitInfo;
40 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
41 import org.opendaylight.protocol.pcep.PCEPCloseTermination;
42 import org.opendaylight.protocol.pcep.PCEPSession;
43 import org.opendaylight.protocol.pcep.PCEPTerminationReason;
44 import org.opendaylight.protocol.pcep.TerminationReason;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Stateful1;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.LspObject;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.StatefulTlv1Builder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Object;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.LspId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.Node1;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.Node1Builder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.OperationResult;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.PccSyncState;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.TearDownSessionInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.lsp.metadata.Metadata;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClient;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClientBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLsp;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLspKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.reported.lsp.Path;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.reported.lsp.PathKey;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
74 import org.opendaylight.yangtools.yang.binding.DataObject;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.common.RpcResult;
77 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
82 * Base class for PCEP topology providers. It handles the common tasks involved in managing a PCEP server (PCE)
83 * endpoint, and exposing a network topology based on it. It needs to be subclassed to form a fully functional block,
84 * where the subclass provides handling of incoming messages.
86 public abstract class AbstractTopologySessionListener implements TopologySessionListener, TopologySessionStats {
87 private static final Logger LOG = LoggerFactory.getLogger(AbstractTopologySessionListener.class);
89 private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
90 private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
91 private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
94 final Map<PlspId, String> lsps = new HashMap<>();
96 SessionStateImpl listenerState;
98 // FIXME: clarify lifecycle rules of this map, most notably the interaction of multiple SrpIdNumbers
100 private final Map<SrpIdNumber, PCEPRequest> requests = new HashMap<>();
102 private final Map<String, ReportedLsp> lspData = new ConcurrentHashMap<>();
103 private final ServerSessionManager serverSessionManager;
104 private InstanceIdentifier<PathComputationClient> pccIdentifier;
106 private TopologyNodeState nodeState;
107 private final AtomicBoolean synced = new AtomicBoolean(false);
109 private PCEPSession session;
111 private SyncOptimization syncOptimization;
113 private boolean triggeredResyncInProcess;
115 AbstractTopologySessionListener(final ServerSessionManager serverSessionManager) {
116 this.serverSessionManager = requireNonNull(serverSessionManager);
120 public final void onSessionUp(final PCEPSession psession) {
121 synchronized (serverSessionManager) {
122 synchronized (this) {
124 * The session went up. Look up the router in Inventory model, create it if it
125 * is not there (marking that fact for later deletion), and mark it as
126 * synchronizing. Also create it in the topology model, with empty LSP list.
128 final InetAddress peerAddress = psession.getRemoteAddress();
130 syncOptimization = new SyncOptimization(psession);
131 final boolean haveLspDbVersion = syncOptimization.isDbVersionPresent();
133 final TopologyNodeState state =
134 serverSessionManager.takeNodeState(peerAddress, this, haveLspDbVersion);
136 // takeNodeState(..) may fail when the server session manager is being restarted
137 // due to configuration change
139 LOG.error("Unable to fetch topology node state for PCEP session. Closing session {}", psession);
140 psession.close(TerminationReason.UNKNOWN);
141 onSessionTerminated(psession, new PCEPCloseTermination(TerminationReason.UNKNOWN));
145 if (session != null || nodeState != null) {
146 LOG.error("PCEP session is already up with {}. Closing session {}", peerAddress, psession);
147 psession.close(TerminationReason.UNKNOWN);
148 onSessionTerminated(psession, new PCEPCloseTermination(TerminationReason.UNKNOWN));
154 LOG.trace("Peer {} resolved to topology node {}", peerAddress, state.getNodeId());
156 // Our augmentation in the topology node
157 final PathComputationClientBuilder pccBuilder = new PathComputationClientBuilder()
158 .setIpAddress(IetfInetUtil.INSTANCE.ipAddressNoZoneFor(peerAddress));
160 // Let subclass fill the details
161 updateStatefulCapabilities(pccBuilder, peerAddress, psession.getRemoteTlvs());
163 synced.set(isSynchronized());
165 final InstanceIdentifier<Node1> topologyAugment = state.getNodeId().augmentation(Node1.class);
166 pccIdentifier = topologyAugment.child(PathComputationClient.class);
168 if (haveLspDbVersion) {
169 final Node initialNodeState = state.getInitialNodeState();
170 if (initialNodeState != null) {
171 loadLspData(initialNodeState, lspData, lsps, isIncrementalSynchro());
172 pccBuilder.setReportedLsp(
173 initialNodeState.augmentation(Node1.class).getPathComputationClient().getReportedLsp());
176 state.storeNode(topologyAugment,
177 new Node1Builder().setPathComputationClient(pccBuilder.build()).build(), psession);
179 listenerState = new SessionStateImpl(this, psession);
180 serverSessionManager.bind(state.getNodeId(), listenerState);
181 LOG.info("Session with {} attached to topology node {}", peerAddress, state.getNodeId());
187 private void updateStatefulCapabilities(final PathComputationClientBuilder pccBuilder,
188 final InetAddress peerAddress, final @Nullable Tlvs remoteTlvs) {
189 if (remoteTlvs != null) {
190 final Tlvs1 statefulTlvs = remoteTlvs.augmentation(Tlvs1.class);
191 if (statefulTlvs != null) {
192 final Stateful stateful = statefulTlvs.getStateful();
193 if (stateful != null) {
194 statefulCapability.set(true);
195 final var updateCap = stateful.getLspUpdateCapability();
196 if (updateCap != null) {
197 lspUpdateCapability.set(updateCap);
199 final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
200 if (stateful1 != null) {
201 final var initiation = stateful1.getInitiation();
202 if (initiation != null) {
203 initiationCapability.set(initiation);
207 pccBuilder.setReportedLsp(Map.of());
208 if (isSynchronized()) {
209 pccBuilder.setStateSync(PccSyncState.Synchronized);
210 } else if (isTriggeredInitialSynchro()) {
211 pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
212 } else if (isIncrementalSynchro()) {
213 pccBuilder.setStateSync(PccSyncState.IncrementalSync);
215 pccBuilder.setStateSync(PccSyncState.InitialResync);
217 pccBuilder.setStatefulTlv(new StatefulTlvBuilder()
218 .addAugmentation(new StatefulTlv1Builder(statefulTlvs).build())
224 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
227 synchronized void updatePccState(final PccSyncState pccSyncState) {
228 if (nodeState == null) {
229 LOG.info("Server Session Manager is closed.");
230 session.close(TerminationReason.UNKNOWN);
233 final MessageContext ctx = new MessageContext(nodeState.getChain().newWriteOnlyTransaction());
234 updatePccNode(ctx, new PathComputationClientBuilder().setStateSync(pccSyncState).build());
235 if (pccSyncState != PccSyncState.Synchronized) {
237 triggeredResyncInProcess = true;
239 // All set, commit the modifications
240 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
242 public void onSuccess(final CommitInfo result) {
243 LOG.trace("Pcc Internal state for session {} updated successfully", session);
247 public void onFailure(final Throwable cause) {
248 LOG.error("Failed to update Pcc internal state for session {}", session, cause);
249 session.close(TerminationReason.UNKNOWN);
251 }, MoreExecutors.directExecutor());
254 synchronized boolean isTriggeredSyncInProcess() {
255 return triggeredResyncInProcess;
259 * Tear down the given PCEP session. It's OK to call this method even after the session
260 * is already down. It always clear up the current session status.
262 @SuppressWarnings("checkstyle:IllegalCatch")
263 private void tearDown(final PCEPSession psession) {
264 requireNonNull(psession);
265 synchronized (serverSessionManager) {
266 synchronized (this) {
267 serverSessionManager.releaseNodeState(nodeState, psession.getRemoteAddress(), isLspDbPersisted());
271 if (session != null) {
275 } catch (final Exception e) {
276 LOG.error("Session {} cannot be closed.", psession, e);
279 listenerState = null;
280 syncOptimization = null;
287 public final void onSessionDown(final PCEPSession psession, final Exception exception) {
288 LOG.warn("Session {} went down unexpectedly", psession, exception);
293 public final void onSessionTerminated(final PCEPSession psession, final PCEPTerminationReason reason) {
294 LOG.info("Session {} terminated by peer with reason {}", psession, reason);
299 public final synchronized void onMessage(final PCEPSession psession, final Message message) {
300 if (nodeState == null) {
301 LOG.warn("Topology node state is null. Unhandled message {} on session {}", message, psession);
302 psession.close(TerminationReason.UNKNOWN);
305 final MessageContext ctx = new MessageContext(nodeState.getChain().newWriteOnlyTransaction());
307 if (onMessage(ctx, message)) {
308 LOG.warn("Unhandled message {} on session {}", message, psession);
309 //cancel not supported, submit empty transaction
310 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
312 public void onSuccess(final CommitInfo result) {
313 LOG.trace("Successful commit");
317 public void onFailure(final Throwable trw) {
318 LOG.error("Failed commit", trw);
320 }, MoreExecutors.directExecutor());
324 ctx.trans.commit().addCallback(new FutureCallback<CommitInfo>() {
326 public void onSuccess(final CommitInfo result) {
327 LOG.trace("Internal state for session {} updated successfully", psession);
328 ctx.notifyRequests();
333 public void onFailure(final Throwable throwable) {
334 LOG.error("Failed to update internal state for session {}, closing it", psession, throwable);
335 ctx.notifyRequests();
336 psession.close(TerminationReason.UNKNOWN);
338 }, MoreExecutors.directExecutor());
342 * Perform revision-specific message processing when a message arrives.
344 * @param ctx Message processing context
345 * @param message Protocol message
346 * @return True if the message type is not handle.
348 protected abstract boolean onMessage(MessageContext ctx, Message message);
350 // Non-final for mocking
352 public void close() {
353 synchronized (serverSessionManager) {
354 synchronized (this) {
356 if (session != null) {
357 LOG.info("Closing session {}", session);
358 session.close(TerminationReason.UNKNOWN);
361 listenerState = null;
362 syncOptimization = null;
368 @Holding({"this.serverSessionManager", "this"})
369 private void clearNodeState() {
370 if (nodeState != null) {
371 serverSessionManager.unbind(nodeState.getNodeId());
372 LOG.debug("Clear Node state: {}", nodeState.getNodeId());
377 @Holding({"this.serverSessionManager", "this"})
378 private void clearRequests() {
379 // Clear all requests we know about
380 for (final Entry<SrpIdNumber, PCEPRequest> e : requests.entrySet()) {
381 // FIXME: exhaustive when we have JDK17+
382 switch (e.getValue().cancel()) {
384 // Done is done, nothing to do
385 LOG.trace("Request {} was done when session went down.", e.getKey());
388 // Peer has not acked: results in failure
389 LOG.info("Request {} was incomplete when session went down, failing the instruction",
393 // Peer has not been sent to the peer: results in cancellation
394 LOG.debug("Request {} was not sent when session went down, cancelling the instruction",
404 final synchronized PCEPRequest removeRequest(final SrpIdNumber id) {
405 final PCEPRequest ret = requests.remove(id);
406 if (ret != null && listenerState != null) {
407 listenerState.processRequestStats(ret.getElapsedMillis());
409 LOG.trace("Removed request {} object {}", id, ret);
413 final synchronized ListenableFuture<OperationResult> sendMessage(final Message message, final SrpIdNumber requestId,
414 final Metadata metadata) {
415 final var sendFuture = session.sendMessage(message);
416 listenerState.updateStatefulSentMsg(message);
418 final short rpcTimeout = serverSessionManager.getRpcTimeout();
419 LOG.trace("RPC response timeout value is {} seconds", rpcTimeout);
421 final Timeout timeout;
422 if (rpcTimeout > 0) {
423 // Note: the timeout is held back by us holding the 'this' monitor, which timeoutExpired re-acquires
424 timeout = serverSessionManager.timer().newTimeout(ignored -> timeoutExpired(requestId),
425 rpcTimeout, TimeUnit.SECONDS);
426 LOG.trace("Set up response timeout handler for request {}", requestId);
431 final PCEPRequest req = new PCEPRequest(metadata, timeout);
432 requests.put(requestId, req);
434 sendFuture.addListener(future -> sendCompleted(future, requestId, req));
435 return req.getFuture();
438 private void sendCompleted(final Future<?> future, final SrpIdNumber requestId, final PCEPRequest req) {
439 if (!future.isSuccess()) {
440 // FIXME: use concurrent operations and re-validate request vs. id
441 synchronized (AbstractTopologySessionListener.this) {
442 requests.remove(requestId);
445 LOG.info("Failed to send request {}, instruction cancelled", requestId, future.cause());
448 LOG.trace("Request {} sent to peer (object {})", requestId, req);
452 private void timeoutExpired(final SrpIdNumber requestId) {
453 final PCEPRequest req;
454 synchronized (this) {
455 req = requests.remove(requestId);
459 LOG.info("Request {} timed-out waiting for response", requestId);
465 * Update an LSP in the data store.
467 * @param ctx Message context
468 * @param id Revision-specific LSP identifier
469 * @param lspName LSP name
470 * @param rlb Reported LSP builder
471 * @param solicited True if the update was solicited
472 * @param remove True if this is an LSP path removal
474 protected final synchronized void updateLsp(final MessageContext ctx, final PlspId id, final String lspName,
475 final ReportedLspBuilder rlb, final boolean solicited, final boolean remove) {
478 if (lspName == null) {
481 LOG.error("PLSPID {} seen for the first time, not reporting the LSP", id);
488 LOG.debug("Saved LSP {} with name {}", id, name);
491 final ReportedLsp previous = lspData.get(name);
492 // if no previous report about the lsp exist, just proceed
493 if (previous != null) {
494 final Map<PathKey, Path> updatedPaths = makeBeforeBreak(rlb, previous, name, remove);
495 // if all paths or the last path were deleted, delete whole tunnel
496 if (updatedPaths.isEmpty()) {
497 LOG.debug("All paths were removed, removing LSP with {}.", id);
501 rlb.setPath(updatedPaths);
503 rlb.withKey(new ReportedLspKey(name));
506 // If this is an unsolicited update. We need to make sure we retain the metadata already present
508 nodeState.setLspMetadata(name, rlb.getMetadata());
510 rlb.setMetadata(nodeState.getLspMetadata(name));
513 final ReportedLsp rl = rlb.build();
514 ctx.trans.put(LogicalDatastoreType.OPERATIONAL, pccIdentifier.child(ReportedLsp.class, rlb.key()), rl);
515 LOG.debug("LSP {} updated to MD-SAL", name);
517 lspData.put(name, rl);
520 private static Map<PathKey, Path> makeBeforeBreak(final ReportedLspBuilder rlb, final ReportedLsp previous,
521 final String name, final boolean remove) {
522 // just one path should be reported
523 final Path path = Iterables.getOnlyElement(rlb.getPath().values());
524 final var reportedLspId = path.getLspId();
525 final List<Path> updatedPaths;
526 //lspId = 0 and remove = false -> tunnel is down, still exists but no path is signaled
527 //remove existing tunnel's paths now, as explicit path remove will not come
528 if (!remove && reportedLspId.getValue().toJava() == 0) {
529 updatedPaths = new ArrayList<>();
530 LOG.debug("Remove previous paths {} to this lsp name {}", previous.getPath(), name);
532 // check previous report for existing paths
533 final Collection<Path> prev = previous.nonnullPath().values();
534 updatedPaths = new ArrayList<>(prev);
535 LOG.debug("Found previous paths {} to this lsp name {}", updatedPaths, name);
536 for (final Path prevPath : prev) {
537 //we found reported path in previous reports
538 if (prevPath.getLspId().getValue().toJava() == 0 || prevPath.getLspId().equals(reportedLspId)) {
539 LOG.debug("Match on lsp-id {}", prevPath.getLspId().getValue());
540 // path that was reported previously and does have the same lsp-id, path will be updated
541 final boolean r = updatedPaths.remove(prevPath);
542 LOG.trace("Request removed? {}", r);
546 // if the path does not exist in previous report, add it to path list, it's a new ERO
547 // only one path will be added
548 //lspId is 0 means confirmation message that shouldn't be added (because we have no means of deleting it later)
549 LOG.trace("Adding new path {} to {}", path, updatedPaths);
550 updatedPaths.add(path);
552 if (reportedLspId.getValue().toJava() == 0) {
553 // if lsp-id also 0, remove all paths
554 LOG.debug("Removing all paths.");
555 updatedPaths.clear();
557 // path is marked to be removed
558 LOG.debug("Removing path {} from {}", path, updatedPaths);
559 final boolean r = updatedPaths.remove(path);
560 LOG.trace("Request removed? {}", r);
563 LOG.debug("Setting new paths {} to lsp {}", updatedPaths, name);
564 return Maps.uniqueIndex(updatedPaths, Path::key);
568 * Indicate that the peer has completed state synchronization.
570 * @param ctx Message context
572 protected final synchronized void stateSynchronizationAchieved(final MessageContext ctx) {
573 if (synced.getAndSet(true)) {
574 LOG.debug("State synchronization achieved while synchronizing, not updating state");
578 triggeredResyncInProcess = false;
579 updatePccNode(ctx, new PathComputationClientBuilder().setStateSync(PccSyncState.Synchronized).build());
581 // The node has completed synchronization, cleanup metadata no longer reported back
582 nodeState.cleanupExcept(lsps.values());
583 LOG.debug("Session {} achieved synchronized state", session);
586 protected final synchronized void updatePccNode(final MessageContext ctx, final PathComputationClient pcc) {
587 ctx.trans.merge(LogicalDatastoreType.OPERATIONAL, pccIdentifier, pcc);
590 protected final @NonNull InstanceIdentifier<ReportedLsp> lspIdentifier(final String name) {
591 return pccIdentifier.child(ReportedLsp.class, new ReportedLspKey(name));
595 * Remove LSP from the database.
597 * @param ctx Message Context
598 * @param id Revision-specific LSP identifier
600 protected final synchronized void removeLsp(final MessageContext ctx, final PlspId id) {
601 final String name = lsps.remove(id);
602 LOG.debug("LSP {} removed", name);
603 ctx.trans.delete(LogicalDatastoreType.OPERATIONAL, lspIdentifier(name));
604 lspData.remove(name);
608 final String lookupLspName(final PlspId id) {
609 return lsps.get(requireNonNull(id, "ID parameter null."));
613 * Reads operational data on this node. Doesn't attempt to read the data,
614 * if the node does not exist. In this case returns null.
616 * @param id InstanceIdentifier of the node
617 * @return null if the node does not exists, or operational data
619 final synchronized <T extends DataObject> FluentFuture<Optional<T>> readOperationalData(
620 final InstanceIdentifier<T> id) {
621 return nodeState == null ? null : nodeState.readOperationalData(id);
624 protected abstract Object validateReportedLsp(Optional<ReportedLsp> rep, LspId input);
626 protected abstract void loadLspData(Node node, Map<String, ReportedLsp> lspData, Map<PlspId, String> lsps,
627 boolean incrementalSynchro);
629 final boolean isLspDbPersisted() {
630 return syncOptimization != null && syncOptimization.isSyncAvoidanceEnabled();
634 * Is Incremental synchronization if LSP-DB-VERSION are included,
635 * LSP-DB-VERSION TLV values doesnt match, and LSP-SYNC-CAPABILITY is enabled.
637 final synchronized boolean isIncrementalSynchro() {
638 return syncOptimization != null && syncOptimization.isSyncAvoidanceEnabled()
639 && syncOptimization.isDeltaSyncEnabled();
642 final synchronized boolean isTriggeredInitialSynchro() {
643 return syncOptimization != null && syncOptimization.isTriggeredInitSyncEnabled();
646 final synchronized boolean isTriggeredReSyncEnabled() {
647 return syncOptimization != null && syncOptimization.isTriggeredReSyncEnabled();
650 protected final synchronized boolean isSynchronized() {
651 return syncOptimization != null && syncOptimization.doesLspDbMatch();
655 public final int getDelegatedLspsCount() {
656 return Math.toIntExact(lspData.values().stream()
657 .map(ReportedLsp::getPath).filter(pathList -> pathList != null && !pathList.isEmpty())
658 // pick the first path, as delegate status should be same in each path
659 .map(pathList -> pathList.values().iterator().next())
660 .map(path -> path.augmentation(Path1.class)).filter(Objects::nonNull)
661 .map(LspObject::getLsp).filter(Objects::nonNull)
662 .filter(Lsp::getDelegate)
667 public final boolean isSessionSynchronized() {
672 public final boolean isInitiationCapability() {
673 return initiationCapability.get();
677 public final boolean isStatefulCapability() {
678 return statefulCapability.get();
682 public final boolean isLspUpdateCapability() {
683 return lspUpdateCapability.get();
688 public synchronized ListenableFuture<RpcResult<Void>> tearDownSession(final TearDownSessionInput input) {
690 return RpcResultBuilder.<Void>success().buildFuture();
693 static final class MessageContext {
694 private final Collection<PCEPRequest> requests = new ArrayList<>();
695 private final WriteTransaction trans;
697 private MessageContext(final WriteTransaction trans) {
698 this.trans = requireNonNull(trans);
701 void resolveRequest(final PCEPRequest req) {
705 private void notifyRequests() {
706 for (final PCEPRequest r : requests) {
707 r.finish(OperationResults.SUCCESS);