import org.opendaylight.protocol.pcep.PCEPTerminationReason;
import org.opendaylight.protocol.pcep.TerminationReason;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Stateful1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.LspObject;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.StatefulTlv1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.MessageHeader;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Object;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.ProtocolVersion;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.PathKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.common.Uint8;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Base class for PCEP topology providers. It handles the common tasks involved in managing a PCEP server (PCE)
* endpoint, and exposing a network topology based on it. It needs to be subclassed to form a fully functional block,
* where the subclass provides handling of incoming messages.
- *
- * @param <S> identifier type of requests
- * @param <L> identifier type for LSPs
*/
-public abstract class AbstractTopologySessionListener<S, L> implements TopologySessionListener, TopologySessionStats {
+public abstract class AbstractTopologySessionListener implements TopologySessionListener, TopologySessionStats {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTopologySessionListener.class);
- static final String MISSING_XML_TAG = "Mandatory XML tags are missing.";
- static final MessageHeader MESSAGE_HEADER = new MessageHeader() {
- private final ProtocolVersion version = new ProtocolVersion(Uint8.ONE);
-
- @Override
- public Class<MessageHeader> implementedInterface() {
- return MessageHeader.class;
- }
-
- @Override
- public ProtocolVersion getVersion() {
- return version;
- }
- };
+ private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
+ private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
+ private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
@GuardedBy("this")
- final Map<L, String> lsps = new HashMap<>();
+ final Map<PlspId, String> lsps = new HashMap<>();
@GuardedBy("this")
SessionStateImpl listenerState;
@GuardedBy("this")
- private final Map<S, PCEPRequest> requests = new HashMap<>();
+ private final Map<SrpIdNumber, PCEPRequest> requests = new HashMap<>();
@GuardedBy("this")
private final Map<String, ReportedLsp> lspData = new ConcurrentHashMap<>();
private final ServerSessionManager serverSessionManager;
.setIpAddress(IetfInetUtil.INSTANCE.ipAddressNoZoneFor(peerAddress));
// Let subclass fill the details
- onSessionUp(pccBuilder, peerAddress, psession.getRemoteTlvs());
+ updateStatefulCapabilities(pccBuilder, peerAddress, psession.getRemoteTlvs());
synced.set(isSynchronized());
}
}
- protected abstract void onSessionUp(PathComputationClientBuilder pccBuilder, InetAddress peerAddress,
- @Nullable Tlvs remoteTlvs);
+ @Holding("this")
+ private void updateStatefulCapabilities(final PathComputationClientBuilder pccBuilder,
+ final InetAddress peerAddress, final @Nullable Tlvs remoteTlvs) {
+ if (remoteTlvs != null) {
+ final Tlvs1 statefulTlvs = remoteTlvs.augmentation(Tlvs1.class);
+ if (statefulTlvs != null) {
+ final Stateful stateful = statefulTlvs.getStateful();
+ if (stateful != null) {
+ statefulCapability.set(true);
+ final var updateCap = stateful.getLspUpdateCapability();
+ if (updateCap != null) {
+ lspUpdateCapability.set(updateCap);
+ }
+ final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
+ if (stateful1 != null) {
+ final var initiation = stateful1.getInitiation();
+ if (initiation != null) {
+ initiationCapability.set(initiation);
+ }
+ }
+
+ pccBuilder.setReportedLsp(Map.of());
+ if (isSynchronized()) {
+ pccBuilder.setStateSync(PccSyncState.Synchronized);
+ } else if (isTriggeredInitialSynchro()) {
+ pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
+ } else if (isIncrementalSynchro()) {
+ pccBuilder.setStateSync(PccSyncState.IncrementalSync);
+ } else {
+ pccBuilder.setStateSync(PccSyncState.InitialResync);
+ }
+ pccBuilder.setStatefulTlv(new StatefulTlvBuilder()
+ .addAugmentation(new StatefulTlv1Builder(statefulTlvs).build())
+ .build());
+ return;
+ }
+ }
+ }
+ LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
+ }
synchronized void updatePccState(final PccSyncState pccSyncState) {
if (nodeState == null) {
syncOptimization = null;
// Clear all requests we know about
- for (final Entry<S, PCEPRequest> e : requests.entrySet()) {
- final PCEPRequest r = e.getValue();
- switch (r.getState()) {
+ for (final Entry<SrpIdNumber, PCEPRequest> e : requests.entrySet()) {
+ // FIXME: exhaustive when we have JDK17+
+ switch (e.getValue().cancel()) {
case DONE:
// Done is done, nothing to do
LOG.trace("Request {} was done when session went down.", e.getKey());
// Peer has not acked: results in failure
LOG.info("Request {} was incomplete when session went down, failing the instruction",
e.getKey());
- r.done(OperationResults.NOACK);
break;
case UNSENT:
// Peer has not been sent to the peer: results in cancellation
LOG.debug("Request {} was not sent when session went down, cancelling the instruction",
e.getKey());
- r.done(OperationResults.UNSENT);
break;
default:
break;
}
}
- final synchronized PCEPRequest removeRequest(final S id) {
+ final synchronized PCEPRequest removeRequest(final SrpIdNumber id) {
final PCEPRequest ret = requests.remove(id);
if (ret != null && listenerState != null) {
listenerState.processRequestStats(ret.getElapsedMillis());
return ret;
}
- final synchronized ListenableFuture<OperationResult> sendMessage(final Message message, final S requestId,
+ final synchronized ListenableFuture<OperationResult> sendMessage(final Message message, final SrpIdNumber requestId,
final Metadata metadata) {
final var sendFuture = session.sendMessage(message);
listenerState.updateStatefulSentMsg(message);
synchronized (AbstractTopologySessionListener.this) {
requests.remove(requestId);
}
- req.done(OperationResults.UNSENT);
+ req.cancel();
LOG.info("Failed to send request {}, instruction cancelled", requestId, future.cause());
} else {
- req.sent();
+ req.markUnacked();
LOG.trace("Request {} sent to peer (object {})", requestId, req);
}
});
return req.getFuture();
}
- private void setupTimeoutHandler(final S requestId, final PCEPRequest req, final short timeout) {
+ private void setupTimeoutHandler(final SrpIdNumber requestId, final PCEPRequest req, final short timeout) {
final Timer timer = req.getTimer();
timer.schedule(new TimerTask() {
@Override
synchronized (AbstractTopologySessionListener.this) {
requests.remove(requestId);
}
- req.done();
+ req.cancel();
LOG.info("Request {} timed-out waiting for response", requestId);
}
}, TimeUnit.SECONDS.toMillis(timeout));
* @param solicited True if the update was solicited
* @param remove True if this is an LSP path removal
*/
- protected final synchronized void updateLsp(final MessageContext ctx, final L id, final String lspName,
+ protected final synchronized void updateLsp(final MessageContext ctx, final PlspId id, final String lspName,
final ReportedLspBuilder rlb, final boolean solicited, final boolean remove) {
final String name;
* @param ctx Message Context
* @param id Revision-specific LSP identifier
*/
- protected final synchronized void removeLsp(final MessageContext ctx, final L id) {
+ protected final synchronized void removeLsp(final MessageContext ctx, final PlspId id) {
final String name = lsps.remove(id);
LOG.debug("LSP {} removed", name);
ctx.trans.delete(LogicalDatastoreType.OPERATIONAL, lspIdentifier(name));
}
@Holding("this")
- final String lookupLspName(final L id) {
+ final String lookupLspName(final PlspId id) {
return lsps.get(requireNonNull(id, "ID parameter null."));
}
protected abstract Object validateReportedLsp(Optional<ReportedLsp> rep, LspId input);
- protected abstract void loadLspData(Node node, Map<String, ReportedLsp> lspData, Map<L, String> lsps,
+ protected abstract void loadLspData(Node node, Map<String, ReportedLsp> lspData, Map<PlspId, String> lsps,
boolean incrementalSynchro);
final boolean isLspDbPersisted() {
}
@Override
- public int getDelegatedLspsCount() {
+ public final int getDelegatedLspsCount() {
return Math.toIntExact(lspData.values().stream()
.map(ReportedLsp::getPath).filter(pathList -> pathList != null && !pathList.isEmpty())
// pick the first path, as delegate status should be same in each path
}
@Override
- public boolean isSessionSynchronized() {
+ public final boolean isSessionSynchronized() {
return synced.get();
}
+ @Override
+ public final boolean isInitiationCapability() {
+ return initiationCapability.get();
+ }
+
+ @Override
+ public final boolean isStatefulCapability() {
+ return statefulCapability.get();
+ }
+
+ @Override
+ public final boolean isLspUpdateCapability() {
+ return lspUpdateCapability.get();
+ }
+
+
@Override
public synchronized ListenableFuture<RpcResult<Void>> tearDownSession(final TearDownSessionInput input) {
close();
private void notifyRequests() {
for (final PCEPRequest r : requests) {
- r.done(OperationResults.SUCCESS);
+ r.finish(OperationResults.SUCCESS);
}
}
}