Move MISSING_XML_TAG and MESSAGE_HEADER
[bgpcep.git] / pcep / topology / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / AbstractTopologySessionListener.java
index df1be1c1bc96ed82c9d260acb33611639860bc87..6190db4f5c347a6a180614146d15b4e8888fa8a6 100644 (file)
@@ -45,13 +45,17 @@ import org.opendaylight.protocol.pcep.PCEPSession;
 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;
@@ -65,6 +69,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology
 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;
@@ -72,7 +77,6 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 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;
 
@@ -80,35 +84,21 @@ 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;
@@ -169,7 +159,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
                     .setIpAddress(IetfInetUtil.INSTANCE.ipAddressNoZoneFor(peerAddress));
 
                 // Let subclass fill the details
-                onSessionUp(pccBuilder, peerAddress, psession.getRemoteTlvs());
+                updateStatefulCapabilities(pccBuilder, peerAddress, psession.getRemoteTlvs());
 
                 synced.set(isSynchronized());
 
@@ -194,8 +184,46 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
         }
     }
 
-    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) {
@@ -253,7 +281,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
                 syncOptimization = null;
 
                 // Clear all requests we know about
-                for (final Entry<S, PCEPRequest> e : requests.entrySet()) {
+                for (final Entry<SrpIdNumber, PCEPRequest> e : requests.entrySet()) {
                     final PCEPRequest r = e.getValue();
                     switch (r.getState()) {
                         case DONE:
@@ -367,7 +395,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
         }
     }
 
-    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());
@@ -376,7 +404,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
         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);
@@ -404,7 +432,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
         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
@@ -429,7 +457,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
      * @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;
@@ -555,7 +583,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
      * @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));
@@ -563,7 +591,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
     }
 
     @Holding("this")
-    final String lookupLspName(final L id) {
+    final String lookupLspName(final PlspId id) {
         return lsps.get(requireNonNull(id, "ID parameter null."));
     }
 
@@ -581,7 +609,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
 
     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() {
@@ -610,7 +638,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
     }
 
     @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
@@ -622,10 +650,26 @@ public abstract class AbstractTopologySessionListener<S, L> implements TopologyS
     }
 
     @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();