BUG-139: State Synchronization Avoidance Procedure 61/26461/10
authorMilos Fabian <milfabia@cisco.com>
Tue, 11 Aug 2015 06:30:03 +0000 (08:30 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 8 Oct 2015 17:12:14 +0000 (17:12 +0000)
-PCC node persistance:
-keep node in topology when session goes down and
syn. avoidance was enabled (PCE is aware of LSP DB version)
-PCC node retrieval:
-load node when session goes up again and if PCE or PCC
propagate LSP DB version number in Open msg.
-set LSP DB version number
-if PCEP session is sync-avoidance-enabled, PCC send LSP DB version in every
report message, DB version number is kept in PCC node by PCE
-get LSP DB version number
-PCE (sync avoidance enabled) tries to get stored LSP DB version from topology's node and use it Open message
-skip synchronization
-if PCE and PCC LSP DB version match, synchronization is skipped, otherwise perform synchronization
-perform synchronization
-mark all LSPs as stale, PCC perform synchronization (unmark reported LSPs), remove LSPs that remained marked as stale

-ref.: https://tools.ietf.org/html/draft-ietf-pce-stateful-sync-optimizations-02#section-3.2

Change-Id: Idf7b3f29fac1c470d5fcae18b329a5b78f7ebbee
Signed-off-by: Milos Fabian <milfabia@cisco.com>
14 files changed:
pcep/segment-routing/src/test/java/org/opendaylight/protocol/pcep/segment/routing/TopologyProviderTest.java
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractTopologySessionListener.java
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposal.java [new file with mode: 0644]
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPTopologyProvider.java
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListener.java
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimization.java [new file with mode: 0644]
pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/TopologyNodeState.java
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/AbstractPCEPSessionTest.java
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposalTest.java [new file with mode: 0644]
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/StateSynchronizationAvoidanceProcedureTest.java [new file with mode: 0644]
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/Stateful07TopologySessionListenerTest.java
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimizationTest.java [new file with mode: 0644]
pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/TopologyProgrammingTest.java

index 6d3ee8429bc614c07e00fc87bd2a7b97427cc670..d8a0f0d9b831c4d7295f7927a74f7a0006336d83 100644 (file)
@@ -18,6 +18,7 @@ import org.junit.Test;
 import org.opendaylight.bgpcep.pcep.topology.provider.AbstractPCEPSessionTest;
 import org.opendaylight.bgpcep.pcep.topology.provider.AbstractTopologySessionListener;
 import org.opendaylight.bgpcep.pcep.topology.provider.Stateful07TopologySessionListenerFactory;
+import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Path1;
@@ -52,6 +53,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 public class TopologyProviderTest extends AbstractPCEPSessionTest<Stateful07TopologySessionListenerFactory> {
 
     private AbstractTopologySessionListener<SrpIdNumber, PlspId> listener;
+    private PCEPSession session;
 
     @Override
     @SuppressWarnings("unchecked")
@@ -59,6 +61,7 @@ public class TopologyProviderTest extends AbstractPCEPSessionTest<Stateful07Topo
     public void setUp() throws Exception {
         super.setUp();
         this.listener = (AbstractTopologySessionListener<SrpIdNumber, PlspId>) getSessionListener();
+        this.session = getPCEPSession(getLocalPref(), getRemotePref());
     }
 
     @Test
index c078ee74d8899b1c924f0f92253fdcb5056c1b85..bf9452804c8bf804d97cbf737a9cde0026fed119 100644 (file)
@@ -51,6 +51,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.rev131024.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.Path;
+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.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -117,6 +118,7 @@ public abstract class AbstractTopologySessionListener<S, L> implements PCEPSessi
     private TopologyNodeState nodeState;
     private boolean synced = false;
     private PCEPSession session;
+    private SyncOptimization syncOptimization;
 
     private ListenerStateRuntimeRegistration registration;
     private final SessionListenerState listenerState;
@@ -136,20 +138,41 @@ public abstract class AbstractTopologySessionListener<S, L> implements PCEPSessi
          */
         final InetAddress peerAddress = session.getRemoteAddress();
 
-        final TopologyNodeState state = this.serverSessionManager.takeNodeState(peerAddress, this);
+        syncOptimization  = new SyncOptimization(session);
+
+        final TopologyNodeState state = this.serverSessionManager.takeNodeState(peerAddress, this, isLspDbRetreived());
+
+        this.session = session;
+        this.nodeState = state;
 
         LOG.trace("Peer {} resolved to topology node {}", peerAddress, state.getNodeId());
-        this.synced = false;
 
         // Our augmentation in the topology node
         final PathComputationClientBuilder pccBuilder = new PathComputationClientBuilder();
-        pccBuilder.setIpAddress(IpAddressBuilder.getDefaultInstance(peerAddress.getHostAddress()));
 
         onSessionUp(session, pccBuilder);
+        this.synced = isSynchronized();
 
-        final Node1 ta = new Node1Builder().setPathComputationClient(pccBuilder.build()).build();
+        pccBuilder.setIpAddress(IpAddressBuilder.getDefaultInstance(peerAddress.getHostAddress()));
         final InstanceIdentifier<Node1> topologyAugment = state.getNodeId().augmentation(Node1.class);
         this.pccIdentifier = topologyAugment.child(PathComputationClient.class);
+        final Node initialNodeState = state.getInitialNodeState();
+        final boolean isNodePresent = isLspDbRetreived() && initialNodeState != null;
+        if (isNodePresent) {
+            loadLspData(initialNodeState, lspData, lsps);
+            pccBuilder.setReportedLsp(initialNodeState.getAugmentation(Node1.class).getPathComputationClient().getReportedLsp());
+        }
+        writeNode(pccBuilder, state, topologyAugment);
+        this.listenerState.init(session);
+        if (this.serverSessionManager.getRuntimeRootRegistration().isPresent()) {
+            this.registration = this.serverSessionManager.getRuntimeRootRegistration().get().register(this);
+        }
+        LOG.info("Session with {} attached to topology node {}", session.getRemoteAddress(), state.getNodeId());
+    }
+
+    private void writeNode(final PathComputationClientBuilder pccBuilder, final TopologyNodeState state,
+            final InstanceIdentifier<Node1> topologyAugment) {
+        final Node1 ta = new Node1Builder().setPathComputationClient(pccBuilder.build()).build();
 
         final ReadWriteTransaction trans = state.rwTransaction();
         trans.put(LogicalDatastoreType.OPERATIONAL, topologyAugment, ta);
@@ -168,21 +191,14 @@ public abstract class AbstractTopologySessionListener<S, L> implements PCEPSessi
                 session.close(TerminationReason.UNKNOWN);
             }
         });
-
-        this.session = session;
-        this.nodeState = state;
-        this.listenerState.init(session);
-        if (this.serverSessionManager.getRuntimeRootRegistration().isPresent()) {
-            this.registration = this.serverSessionManager.getRuntimeRootRegistration().get().register(this);
-        }
-        LOG.info("Session with {} attached to topology node {}", session.getRemoteAddress(), state.getNodeId());
     }
 
     @GuardedBy("this")
     private void tearDown(final PCEPSession session) {
-        this.serverSessionManager.releaseNodeState(this.nodeState, session);
+        this.serverSessionManager.releaseNodeState(this.nodeState, session, isLspDbPersisted());
         this.nodeState = null;
         this.session = null;
+        this.syncOptimization = null;
         unregister();
 
         // Clear all requests we know about
@@ -403,17 +419,25 @@ public abstract class AbstractTopologySessionListener<S, L> implements PCEPSessi
 
         // Update synchronization flag
         this.synced = true;
-        ctx.trans.merge(LogicalDatastoreType.OPERATIONAL, this.pccIdentifier, new PathComputationClientBuilder().setStateSync(PccSyncState.Synchronized).build());
+        updatePccNode(ctx, new PathComputationClientBuilder().setStateSync(PccSyncState.Synchronized).build());
 
         // The node has completed synchronization, cleanup metadata no longer reported back
         this.nodeState.cleanupExcept(this.lsps.values());
         LOG.debug("Session {} achieved synchronized state", this.session);
     }
 
+    protected final synchronized void updatePccNode(final MessageContext ctx, final PathComputationClient pcc) {
+        ctx.trans.merge(LogicalDatastoreType.OPERATIONAL, this.pccIdentifier, pcc);
+    }
+
     protected final InstanceIdentifier<ReportedLsp> lspIdentifier(final String name) {
         return this.pccIdentifier.child(ReportedLsp.class, new ReportedLspKey(name));
     }
 
+    protected final InstanceIdentifier<PathComputationClient> getPccIdentifier() {
+        return this.pccIdentifier;
+    }
+
     /**
      * Remove LSP from the database.
      *
@@ -459,6 +483,29 @@ public abstract class AbstractTopologySessionListener<S, L> implements PCEPSessi
 
     protected abstract Object validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input);
 
+    protected abstract void loadLspData(final Node node, final Map<String, ReportedLsp> lspData, final Map<L, String> lsps);
+
+    protected final boolean isLspDbPersisted() {
+        if (syncOptimization != null) {
+            return syncOptimization.isSyncAvoidanceEnabled();
+        }
+        return false;
+    }
+
+    protected final boolean isLspDbRetreived() {
+        if (syncOptimization != null) {
+            return syncOptimization.isDbVersionPresent();
+        }
+        return false;
+    }
+
+    protected final boolean isSynchronized() {
+        if (syncOptimization != null) {
+            return syncOptimization.doesLspDbMatch();
+        }
+        return false;
+    }
+
     protected SessionListenerState getSessionListenerState() {
         return this.listenerState;
     }
diff --git a/pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposal.java b/pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposal.java
new file mode 100644 (file)
index 0000000..0d8b88b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.PathComputationClient1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PCEPStatefulPeerProposal {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PCEPStatefulPeerProposal.class);
+
+    private final DataBroker dataBroker;
+    private final InstanceIdentifier<Topology> topologyId;
+
+    private PCEPStatefulPeerProposal(final DataBroker dataBroker, final InstanceIdentifier<Topology> topologyId) {
+        this.dataBroker = Preconditions.checkNotNull(dataBroker);
+        this.topologyId = Preconditions.checkNotNull(topologyId);
+    }
+
+    public static PCEPStatefulPeerProposal createStatefulPeerProposal(final DataBroker dataBroker,
+            final InstanceIdentifier<Topology> topologyId) {
+        return new PCEPStatefulPeerProposal(dataBroker, topologyId);
+    }
+
+    void setPeerProposal(final NodeId nodeId, final TlvsBuilder openTlvsBuilder) {
+        if (isSynOptimizationEnabled(openTlvsBuilder)) {
+            final ListenableFuture<Optional<LspDbVersion>> future = this.dataBroker.newReadOnlyTransaction().read(
+                    LogicalDatastoreType.OPERATIONAL,
+                    topologyId.child(Node.class, new NodeKey(nodeId)).augmentation(Node1.class)
+                            .child(PathComputationClient.class).augmentation(PathComputationClient1.class)
+                            .child(LspDbVersion.class));
+            Futures.addCallback(future, new FutureCallback<Optional<LspDbVersion>>() {
+                @Override
+                public void onSuccess(final Optional<LspDbVersion> result) {
+                    if (result.isPresent()) {
+                        openTlvsBuilder.addAugmentation(Tlvs3.class, new Tlvs3Builder().setLspDbVersion(result.get())
+                                .build());
+                    }
+                }
+
+                @Override
+                public void onFailure(final Throwable t) {
+                    LOG.warn("Failed to read toplogy {}.", InstanceIdentifier.keyOf(topologyId), t);
+                }
+            });
+        }
+    }
+
+    private static boolean isSynOptimizationEnabled(final TlvsBuilder openTlvsBuilder) {
+        final Tlvs1 statefulTlv = openTlvsBuilder.getAugmentation(Tlvs1.class);
+        if (statefulTlv != null && statefulTlv.getStateful() != null) {
+            return statefulTlv.getStateful().getAugmentation(Stateful1.class) != null;
+        }
+        return false;
+    }
+
+}
index ef7e34da54b4d77c5a48364afeb323a86a4b4ff4..6a5ef4737e0268e217c3660078beda3e63432aba 100644 (file)
@@ -60,7 +60,7 @@ public final class PCEPTopologyProvider extends DefaultTopologyReference impleme
         if (runtimeRootRegistrator.isPresent()) {
             manager.registerRuntimeRootRegistartion(runtimeRootRegistrator.get());
         }
-        final ChannelFuture f = dispatcher.createServer(address, keys, manager, null);
+        final ChannelFuture f = dispatcher.createServer(address, keys, manager, manager);
         f.get();
 
         final BindingAwareBroker.RoutedRpcRegistration<NetworkTopologyPcepService> element = rpcRegistry.addRoutedRpcImplementation(
index 2282a14b1adf7d84b4f9ce6cf54c08c1e267c12f..3fbe5c8cfccffe5407aa61fcb6d1e856796b01ca 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -23,9 +24,11 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.protocol.pcep.PCEPPeerProposal;
 import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.protocol.pcep.PCEPSessionListener;
 import org.opendaylight.protocol.pcep.PCEPSessionListenerFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspArgs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.EnsureLspOperationalInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.OperationResult;
@@ -47,7 +50,7 @@ import org.slf4j.LoggerFactory;
 /**
  *
  */
-final class ServerSessionManager implements PCEPSessionListenerFactory, AutoCloseable, TopologySessionRPCs, PCEPTopologyProviderRuntimeMXBean {
+final class ServerSessionManager implements PCEPSessionListenerFactory, AutoCloseable, TopologySessionRPCs, PCEPTopologyProviderRuntimeMXBean, PCEPPeerProposal {
     private static final Logger LOG = LoggerFactory.getLogger(ServerSessionManager.class);
     private static final long DEFAULT_HOLD_STATE_NANOS = TimeUnit.MINUTES.toNanos(5);
 
@@ -56,6 +59,7 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, AutoClos
     private final TopologySessionListenerFactory listenerFactory;
     private final InstanceIdentifier<Topology> topology;
     private final DataBroker broker;
+    private final PCEPStatefulPeerProposal peerProposal;
     private Optional<PCEPTopologyProviderRuntimeRegistration> runtimeRootRegistration = Optional.absent();
 
     public ServerSessionManager(final DataBroker broker, final InstanceIdentifier<Topology> topology,
@@ -63,6 +67,7 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, AutoClos
         this.broker = Preconditions.checkNotNull(broker);
         this.topology = Preconditions.checkNotNull(topology);
         this.listenerFactory = Preconditions.checkNotNull(listenerFactory);
+        this.peerProposal = PCEPStatefulPeerProposal.createStatefulPeerProposal(this.broker, this.topology);
 
         // Now create the base topology
         final TopologyKey k = InstanceIdentifier.keyOf(topology);
@@ -78,13 +83,13 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, AutoClos
         return new NodeId("pcc://" + addr.getHostAddress());
     }
 
-    synchronized void releaseNodeState(final TopologyNodeState nodeState, final PCEPSession session) {
+    synchronized void releaseNodeState(final TopologyNodeState nodeState, final PCEPSession session, final boolean persistNode) {
         LOG.debug("Node {} unbound", nodeState.getNodeId());
         this.nodes.remove(createNodeId(session.getRemoteAddress()));
-        nodeState.released();
+        nodeState.released(persistNode);
     }
 
-    synchronized TopologyNodeState takeNodeState(final InetAddress address, final TopologySessionListener sessionListener) {
+    synchronized TopologyNodeState takeNodeState(final InetAddress address, final TopologySessionListener sessionListener, final boolean retrieveNode) {
         final NodeId id = createNodeId(address);
 
         LOG.debug("Node {} requested by listener {}", id, sessionListener);
@@ -97,7 +102,7 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, AutoClos
         }
         // FIXME: else check for conflicting session
 
-        ret.taken();
+        ret.taken(retrieveNode);
         this.nodes.put(id, sessionListener);
         LOG.debug("Node {} bound to listener {}", id, sessionListener);
         return ret;
@@ -165,4 +170,10 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, AutoClos
     public Optional<PCEPTopologyProviderRuntimeRegistration> getRuntimeRootRegistration() {
         return this.runtimeRootRegistration;
     }
+
+    @Override
+    public void setPeerSpecificProposal(final InetSocketAddress address, final TlvsBuilder openBuilder) {
+        Preconditions.checkNotNull(address);
+        peerProposal.setPeerProposal(createNodeId(address.getAddress()), openBuilder);
+    }
 }
index 3d0f62a64d0f6e6e2b15b5c8bd01d9e9b70572e5..b85367fbefcd3bebf29f6326d4b4ac7ea9843191 100644 (file)
@@ -19,10 +19,15 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.controller.config.yang.pcep.topology.provider.PeerCapabilities;
 import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.PathComputationClient1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.PathComputationClient1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersion;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.PcinitiateBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1Builder;
@@ -64,15 +69,18 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspArgs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.EnsureLspOperationalInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.LspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.OperationResult;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.PccSyncState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.RemoveLspArgs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.UpdateLspArgs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClientBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLsp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.Path;
+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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -82,6 +90,9 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener<
 
     private final AtomicLong requestId = new AtomicLong(1L);
 
+    @GuardedBy("this")
+    private final List<PlspId> staleLsps = new ArrayList<>();
+
     /**
      * Creates a new stateful topology session listener for given server session manager.
      *
@@ -101,7 +112,11 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener<
             if (stateful != null) {
                 getSessionListenerState().setPeerCapabilities(getCapabilities(stateful));
                 pccBuilder.setReportedLsp(Collections.<ReportedLsp> emptyList());
-                pccBuilder.setStateSync(PccSyncState.InitialResync);
+                if (isSynchronized()) {
+                    pccBuilder.setStateSync(PccSyncState.Synchronized);
+                } else {
+                    pccBuilder.setStateSync(PccSyncState.InitialResync);
+                }
                 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(StatefulTlv1.class,
                     new StatefulTlv1Builder(tlvs.getAugmentation(Tlvs1.class)).build()).build());
             } else {
@@ -170,6 +185,7 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener<
         final Lsp lsp = report.getLsp();
         final PlspId plspid = lsp.getPlspId();
         if (!lsp.isSync() && (lsp.getPlspId() == null || plspid.getValue() == 0)) {
+            purgeStaleLsps(ctx);
             stateSynchronizationAchieved(ctx);
             return true;
         }
@@ -189,14 +205,30 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener<
         rlb.setPath(Collections.singletonList(buildPath(report, srp, lsp)));
 
         String name = lookupLspName(plspid);
-        if (report.getLsp().getTlvs() != null && report.getLsp().getTlvs().getSymbolicPathName() != null) {
-            name = Charsets.UTF_8.decode(ByteBuffer.wrap(report.getLsp().getTlvs().getSymbolicPathName().getPathName().getValue())).toString();
+        if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
+            name = Charsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName().getValue())).toString();
+        }
+        //get LspDB from LSP and write it to pcc's node
+        final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
+        if (lspDbVersion != null) {
+            updatePccNode(ctx, new PathComputationClientBuilder().addAugmentation(PathComputationClient1.class,
+                    new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
         }
         updateLsp(ctx, plspid, name, rlb, solicited, lsp.isRemove());
+        unmarkStaleLsp(plspid, lsp.isSync());
+
         LOG.debug("LSP {} updated", lsp);
         return true;
     }
 
+    private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.Tlvs tlvs = lsp.getTlvs();
+        if (tlvs != null && tlvs.getAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1.class) != null) {
+            return tlvs.getAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1.class).getLspDbVersion();
+        }
+        return null;
+    }
+
     private Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder();
         if (report.getPath() != null) {
@@ -533,4 +565,36 @@ class Stateful07TopologySessionListener extends AbstractTopologySessionListener<
         }
         return capa;
     }
+
+    @Override
+    protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData, final Map<PlspId, String> lsps) {
+        //load node's lsps from DS
+        final PathComputationClient pcc = node.getAugmentation(Node1.class).getPathComputationClient();
+        final List<ReportedLsp> reportedLsps = pcc.getReportedLsp();
+        for (final ReportedLsp reportedLsp : reportedLsps) {
+            final String lspName = reportedLsp.getName();
+            lspData.put(lspName, reportedLsp);
+            if (!reportedLsp.getPath().isEmpty()) {
+                final Path1 path1 = reportedLsp.getPath().get(0).getAugmentation(Path1.class);
+                if (path1 != null) {
+                    final PlspId plspId = path1.getLsp().getPlspId();
+                    staleLsps.add(plspId);
+                    lsps.put(plspId, lspName);
+                }
+            }
+        }
+    }
+
+    private synchronized void unmarkStaleLsp(final PlspId plspId, final boolean sync) {
+        if (!sync) {
+            staleLsps.remove(plspId);
+        }
+    }
+
+    private synchronized void purgeStaleLsps(final MessageContext ctx) {
+        for (final PlspId plspId : staleLsps) {
+            removeLsp(ctx, plspId);
+        }
+        staleLsps.clear();
+    }
 }
diff --git a/pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimization.java b/pcep/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimization.java
new file mode 100644 (file)
index 0000000..4429979
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.protocol.pcep.PCEPSession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.Tlvs;
+
+final class SyncOptimization {
+
+    private final boolean dbVersionMatch;
+    private final boolean isSyncAvoidanceEnabled;
+    private final boolean isDbVersionPresent;
+
+    public SyncOptimization(final PCEPSession session) {
+        Preconditions.checkNotNull(session);
+        final Tlvs remote = session.getRemoteTlvs();
+        final Tlvs local = session.localSessionCharacteristics();
+        final LspDbVersion localLspDbVersion = getLspDbVersion(local);
+        final LspDbVersion remoteLspDbVersion = getLspDbVersion(remote);
+        this.dbVersionMatch = compareLspDbVersion(localLspDbVersion, remoteLspDbVersion);
+        this.isSyncAvoidanceEnabled = isSyncAvoidance(local) && isSyncAvoidance(remote);
+        this.isDbVersionPresent = localLspDbVersion != null || remoteLspDbVersion != null;
+    }
+
+    public boolean doesLspDbMatch() {
+        return dbVersionMatch;
+    }
+
+    public boolean isSyncAvoidanceEnabled() {
+        return isSyncAvoidanceEnabled;
+    }
+
+    public boolean isDbVersionPresent() {
+        return isDbVersionPresent;
+    }
+
+    private static LspDbVersion getLspDbVersion(final Tlvs openTlvs) {
+        if (openTlvs != null) {
+            final Tlvs3 tlvs3 = openTlvs.getAugmentation(Tlvs3.class);
+            if (tlvs3 != null && tlvs3.getLspDbVersion() != null
+                    && tlvs3.getLspDbVersion().getLspDbVersionValue() != null) {
+                return tlvs3.getLspDbVersion();
+            }
+        }
+        return null;
+    }
+
+    private static boolean compareLspDbVersion(final LspDbVersion local, final LspDbVersion remote) {
+        if (local != null && remote != null) {
+            return local.equals(remote);
+        }
+        return false;
+    }
+
+    private static boolean isSyncAvoidance(final Tlvs openTlvs) {
+        if (openTlvs != null) {
+            final Tlvs1 tlvs1 = openTlvs.getAugmentation(Tlvs1.class);
+            if (tlvs1 != null && tlvs1.getStateful() != null) {
+                final Stateful1 stateful1 = tlvs1.getStateful().getAugmentation(Stateful1.class);
+                if (stateful1 != null && stateful1.isIncludeDbVersion() != null) {
+                    return stateful1.isIncludeDbVersion();
+                }
+            }
+        }
+        return false;
+    }
+
+}
index d75908706a5f52567b44a597796373b185a03c76..9104abda11d6ddd303673e63cba772a199b8ec0a 100644 (file)
@@ -46,6 +46,8 @@ final class TopologyNodeState implements AutoCloseable, TransactionChainListener
     private final BindingTransactionChain chain;
     private final long holdStateNanos;
     private long lastReleased = 0;
+    //cache initial node state, if any node was persisted
+    private Node initialNodeState = null;
 
     public TopologyNodeState(final DataBroker broker, final InstanceIdentifier<Topology> topology, final NodeId id, final long holdStateNanos) {
         Preconditions.checkArgument(holdStateNanos >= 0);
@@ -83,38 +85,61 @@ final class TopologyNodeState implements AutoCloseable, TransactionChainListener
         }
     }
 
-    public synchronized void released() {
+    public synchronized void released(final boolean persist) {
         // The session went down. Undo all the Topology changes we have done.
-        final WriteTransaction trans = beginTransaction();
-
-        trans.delete(LogicalDatastoreType.OPERATIONAL, this.nodeId);
-
-        Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(final Void result) {
-                LOG.trace("Internal state for node {} cleaned up successfully", nodeId);
-            }
-
-            @Override
-            public void onFailure(final Throwable t) {
-                LOG.error("Failed to cleanup internal state for session {}", nodeId, t);
-            }
-        });
+        // We might want to persist topology node for later re-use.
+        if (!persist) {
+            final WriteTransaction trans = beginTransaction();
+            trans.delete(LogicalDatastoreType.OPERATIONAL, this.nodeId);
+            Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(final Void result) {
+                    LOG.trace("Internal state for node {} cleaned up successfully", nodeId);
+                }
+
+                @Override
+                public void onFailure(final Throwable t) {
+                    LOG.error("Failed to cleanup internal state for session {}", nodeId, t);
+                }
+            });
+        }
 
         lastReleased = System.nanoTime();
     }
 
-    public synchronized void taken() {
+    public synchronized void taken(final boolean retrieveNode) {
         final long now = System.nanoTime();
 
         if (now - lastReleased > holdStateNanos) {
             metadata.clear();
         }
 
-        final Node node = new NodeBuilder().setKey(nodeId.getKey()).setNodeId(nodeId.getKey().getNodeId()).build();
-        final WriteTransaction t = chain.newWriteOnlyTransaction();
-        t.put(LogicalDatastoreType.OPERATIONAL, nodeId, node);
-        t.submit();
+        //try to get the topology's node
+        if (retrieveNode) {
+            Futures.addCallback(readOperationalData(nodeId), new FutureCallback<Optional<Node>>() {
+
+                @Override
+                public void onSuccess(final Optional<Node> result) {
+                    if (!result.isPresent()) {
+                        putTopologyNode();
+                    } else {
+                        //cache retrieved node
+                        initialNodeState = result.get();
+                    }
+                }
+
+                @Override
+                public void onFailure(final Throwable t) {
+                    LOG.error("Failed to get topology node {}", nodeId, t);
+                }
+            });
+        } else {
+            putTopologyNode();
+        }
+    }
+
+    public synchronized Node getInitialNodeState() {
+        return initialNodeState;
     }
 
     WriteTransaction beginTransaction() {
@@ -147,4 +172,11 @@ final class TopologyNodeState implements AutoCloseable, TransactionChainListener
         chain.close();
     }
 
+    private void putTopologyNode() {
+        final Node node = new NodeBuilder().setKey(nodeId.getKey()).setNodeId(nodeId.getKey().getNodeId()).build();
+        final WriteTransaction t = beginTransaction();
+        t.put(LogicalDatastoreType.OPERATIONAL, nodeId, node);
+        t.submit();
+    }
+
 }
\ No newline at end of file
index 7cbff7b204fbad9a08bf794f972d0c49d8ba63f6..7df8c6f0d67815e0eca20751ecede6bcb747c43f 100644 (file)
@@ -40,9 +40,9 @@ import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.protocol.pcep.PCEPSessionListener;
 import org.opendaylight.protocol.pcep.impl.DefaultPCEPSessionNegotiator;
-import org.opendaylight.protocol.pcep.impl.PCEPSessionImpl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.Ero;
@@ -80,8 +80,6 @@ public abstract class AbstractPCEPSessionTest<T extends TopologySessionListenerF
 
     protected List<Notification> receivedMsgs;
 
-    protected PCEPSessionImpl session;
-
     @Mock
     private EventLoop eventLoop;
 
@@ -98,10 +96,14 @@ public abstract class AbstractPCEPSessionTest<T extends TopologySessionListenerF
 
     private final Open localPrefs = new OpenBuilder().setDeadTimer((short) 30).setKeepalive((short) 10).setSessionId((short) 0).build();
 
+    private final Open remotePrefs = localPrefs;
+
     protected ServerSessionManager manager;
 
     protected NetworkTopologyPcepService topologyRpcs;
 
+    private DefaultPCEPSessionNegotiator neg;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -131,8 +133,7 @@ public abstract class AbstractPCEPSessionTest<T extends TopologySessionListenerF
         this.listenerFactory = (T) ((Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
         this.manager = new ServerSessionManager(getDataBroker(), TOPO_IID, this.listenerFactory);
 
-        final DefaultPCEPSessionNegotiator neg = new DefaultPCEPSessionNegotiator(mock(Promise.class), this.clientListener, this.manager.getSessionListener(), (short) 1, 5, this.localPrefs);
-        this.session = neg.createSession(this.clientListener, getLocalPref(), getLocalPref());
+        this.neg = new DefaultPCEPSessionNegotiator(mock(Promise.class), this.clientListener, this.manager.getSessionListener(), (short) 1, 5, this.localPrefs);
         this.topologyRpcs = new TopologyRPCs(this.manager);
     }
 
@@ -166,7 +167,15 @@ public abstract class AbstractPCEPSessionTest<T extends TopologySessionListenerF
         return this.localPrefs;
     }
 
+    protected Open getRemotePref() {
+        return this.remotePrefs;
+    }
+
     protected PCEPSessionListener getSessionListener() {
         return this.manager.getSessionListener();
     }
+
+    protected final PCEPSession getPCEPSession(final Open localOpen, final Open remoteOpen) {
+        return neg.createSession(this.clientListener, localOpen, remoteOpen);
+    }
 }
diff --git a/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposalTest.java b/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/PCEPStatefulPeerProposalTest.java
new file mode 100644 (file)
index 0000000..c14569a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.StatefulBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class PCEPStatefulPeerProposalTest {
+
+    private static final InstanceIdentifier<Topology> TOPOLOGY_IID = InstanceIdentifier.create(NetworkTopology.class)
+            .child(Topology.class, new TopologyKey(new TopologyId("topology")));
+    private static final NodeId NODE_ID = new NodeId("node");
+    private static final LspDbVersion LSP_DB_VERSION = new LspDbVersionBuilder().setLspDbVersionValue(
+            BigInteger.valueOf(1l)).build();
+
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private CheckedFuture<Optional<LspDbVersion>, ReadFailedException> listenableFutureMock;
+
+    private TlvsBuilder tlvsBuilder;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setUp() throws InterruptedException, ExecutionException {
+        MockitoAnnotations.initMocks(this);
+        this.tlvsBuilder = new TlvsBuilder().addAugmentation(
+                Tlvs1.class,
+                new Tlvs1Builder().setStateful(
+                        new StatefulBuilder().addAugmentation(Stateful1.class, new Stateful1Builder().build()).build())
+                        .build());
+        final ReadOnlyTransaction rTxMock = Mockito.mock(ReadOnlyTransaction.class);
+        Mockito.doReturn(rTxMock).when(dataBroker).newReadOnlyTransaction();
+        Mockito.doReturn(listenableFutureMock).when(rTxMock)
+                .read(Mockito.any(LogicalDatastoreType.class), Mockito.any(InstanceIdentifier.class));
+
+        Mockito.doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(final InvocationOnMock invocation) throws Throwable {
+                final Runnable runnable = (Runnable) invocation.getArguments()[0];
+                runnable.run();
+                return null;
+            }
+        }).when(listenableFutureMock).addListener(Mockito.any(Runnable.class), Mockito.any(Executor.class));
+    }
+
+    @Test
+    public void testSetPeerProposalSuccess() throws InterruptedException, ExecutionException {
+        Mockito.doReturn(Optional.of(LSP_DB_VERSION)).when(listenableFutureMock).get();
+        final PCEPStatefulPeerProposal peerProposal = PCEPStatefulPeerProposal.createStatefulPeerProposal(dataBroker,
+                TOPOLOGY_IID);
+        peerProposal.setPeerProposal(NODE_ID, tlvsBuilder);
+        assertEquals(LSP_DB_VERSION, tlvsBuilder.getAugmentation(Tlvs3.class).getLspDbVersion());
+    }
+
+    @Test
+    public void testSetPeerProposalAbsent() throws InterruptedException, ExecutionException {
+        Mockito.doReturn(Optional.absent()).when(listenableFutureMock).get();
+        final PCEPStatefulPeerProposal peerProposal = PCEPStatefulPeerProposal.createStatefulPeerProposal(dataBroker,
+                TOPOLOGY_IID);
+        peerProposal.setPeerProposal(NODE_ID, tlvsBuilder);
+        assertNull(tlvsBuilder.getAugmentation(Tlvs3.class));
+    }
+
+    @Test
+    public void testSetPeerProposalFailure() throws InterruptedException, ExecutionException {
+        Mockito.doThrow(new RuntimeException()).when(listenableFutureMock).get();
+        final PCEPStatefulPeerProposal peerProposal = PCEPStatefulPeerProposal.createStatefulPeerProposal(dataBroker,
+                TOPOLOGY_IID);
+        peerProposal.setPeerProposal(NODE_ID, tlvsBuilder);
+        assertNull(tlvsBuilder.getAugmentation(Tlvs3.class));
+    }
+
+}
diff --git a/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/StateSynchronizationAvoidanceProcedureTest.java b/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/StateSynchronizationAvoidanceProcedureTest.java
new file mode 100644 (file)
index 0000000..23b6e8e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import static org.opendaylight.protocol.pcep.pcc.mock.MsgBuilderUtil.createLsp;
+import static org.opendaylight.protocol.pcep.pcc.mock.MsgBuilderUtil.createPath;
+
+import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.protocol.pcep.PCEPSession;
+import org.opendaylight.protocol.pcep.pcc.mock.MsgBuilderUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.PathComputationClient1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Stateful1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Stateful1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.OperationalStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Pcrpt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PlspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.SymbolicPathName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.identifiers.tlv.LspIdentifiersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.srp.object.Srp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.StatefulBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.symbolic.path.name.tlv.SymbolicPathNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.ero.Subobject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.LspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.PccSyncState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+
+public class StateSynchronizationAvoidanceProcedureTest extends AbstractPCEPSessionTest<Stateful07TopologySessionListenerFactory> {
+
+    private Stateful07TopologySessionListener listener;
+
+    private PCEPSession session;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        this.listener = (Stateful07TopologySessionListener) getSessionListener();
+    }
+
+    @Test
+    public void testNodePersisted() throws InterruptedException, ExecutionException {
+        this.session = getPCEPSession(getOpen(null), getOpen(null));
+        this.listener.onSessionUp(session);
+        //report LSP + LSP-DB version number
+        final Pcrpt pcRpt = MsgBuilderUtil.createPcRtpMessage(new LspBuilder().setTlvs(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder()
+                    .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1.class,
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1Builder().setLspDbVersion(new LspDbVersionBuilder().setLspDbVersionValue(BigInteger.valueOf(1l)).build()).build()).build()).setPlspId(new PlspId(1L)).setSync(false).setRemove(false).setOperational(OperationalStatus.Active).build(), Optional.of(MsgBuilderUtil.createSrp(1l)), null);
+        this.listener.onMessage(session, pcRpt);
+        //check topology
+        final Topology topo1 = getTopology().get();
+        final LspDbVersion lspDb1 = topo1.getNode().get(0).getAugmentation(Node1.class).getPathComputationClient().getAugmentation(PathComputationClient1.class).getLspDbVersion();
+        Assert.assertEquals(1l, lspDb1.getLspDbVersionValue().longValue());
+        //drop session
+        this.listener.onSessionDown(session, new IllegalStateException());
+        //check topology - node is persisted
+        final Topology topo2 = getTopology().get();
+        Assert.assertFalse(topo2.getNode().isEmpty());
+    }
+
+    @Test
+    public void testStateSynchronizationSkipped() throws InterruptedException, ExecutionException {
+        //session up - sync skipped (LSP-DBs match)
+        final LspDbVersion lspDbVersion = new LspDbVersionBuilder().setLspDbVersionValue(BigInteger.valueOf(1l)).build();
+        this.session = getPCEPSession(getOpen(lspDbVersion), getOpen(lspDbVersion));
+        this.listener.onSessionUp(session);
+        //check node - synchronized
+        final Topology topo = getTopology().get();
+        Assert.assertEquals(PccSyncState.Synchronized, topo.getNode().get(0).getAugmentation(Node1.class).getPathComputationClient().getStateSync());
+    }
+
+    @Test
+    public void testStateSynchronizationPerformed() throws InterruptedException, ExecutionException {
+        this.session = getPCEPSession(getOpen(null), getOpen(null));
+        this.listener.onSessionUp(session);
+        //report LSP + LSP-DB version number
+        final Pcrpt pcRpt = MsgBuilderUtil.createPcRtpMessage(new LspBuilder().setPlspId(new PlspId(1l)).setTlvs(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder().setLspIdentifiers(new LspIdentifiersBuilder().setLspId(new LspId(1l)).build()).setSymbolicPathName(new SymbolicPathNameBuilder().setPathName(new SymbolicPathName("test".getBytes())).build())
+                    .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1.class,
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1Builder().setLspDbVersion(new LspDbVersionBuilder().setLspDbVersionValue(BigInteger.valueOf(1l)).build()).build()).build()).setPlspId(new PlspId(1L)).setSync(true).setRemove(false).setOperational(OperationalStatus.Active).build(), Optional.<Srp>absent(), createPath(Collections.<Subobject> emptyList()));
+        this.listener.onMessage(session, pcRpt);
+        final Topology topo = getTopology().get();
+        final PathComputationClient pcc = topo.getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+        Assert.assertFalse(pcc.getReportedLsp().isEmpty());
+        this.listener.onSessionDown(session, new IllegalArgumentException());
+        this.listener = (Stateful07TopologySessionListener) getSessionListener();
+
+        //session up - expect sync (LSP-DBs do not match)
+        final LspDbVersion localDbVersion = new LspDbVersionBuilder().setLspDbVersionValue(BigInteger.valueOf(2l)).build();
+        this.session = getPCEPSession(getOpen(localDbVersion), getOpen(null));
+        this.listener.onSessionUp(session);
+
+        final Topology topo2 = getTopology().get();
+        final PathComputationClient pcc2 = topo2.getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+        //check node - not synchronized
+        Assert.assertEquals(PccSyncState.InitialResync, pcc2.getStateSync());
+        //check reported LSP - persisted from previous session
+        Assert.assertFalse(pcc2.getReportedLsp().isEmpty());
+        //sync rpt + LSP-DB
+        final Pcrpt syncMsg = MsgBuilderUtil.createPcRtpMessage(createLsp(0, false, Optional.of(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder().addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs1Builder().setLspDbVersion(new LspDbVersionBuilder().setLspDbVersionValue(BigInteger.valueOf(2l)).build()).build()).build()), true, false), Optional.<Srp>absent(),
+                createPath(Collections.<Subobject> emptyList()));
+        this.listener.onMessage(session, syncMsg);
+        final Topology topo3 = getTopology().get();
+        final PathComputationClient pcc3 = topo3.getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+        //check node - synchronized
+        Assert.assertEquals(PccSyncState.Synchronized, pcc3.getStateSync());
+        //check reported LSP is empty, LSP state from previous session was purged
+        Assert.assertTrue(pcc3.getReportedLsp().isEmpty());
+    }
+
+    protected Open getOpen(final LspDbVersion dbVersion) {
+        return new OpenBuilder(super.getLocalPref()).setTlvs(new TlvsBuilder().addAugmentation(Tlvs1.class, new Tlvs1Builder().setStateful(new StatefulBuilder()
+            .addAugmentation(Stateful1.class, new Stateful1Builder().setInitiation(Boolean.TRUE).build())
+            .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1Builder().setIncludeDbVersion(Boolean.TRUE).build())
+            .build()).build()).addAugmentation(Tlvs3.class, new Tlvs3Builder().setLspDbVersion(dbVersion).build()).build()).build();
+    }
+
+}
index 1668b535216deb3d57e0b55d7ae274d4ef4aceda..8ed7acd35144d6ab863200ec9b5add0ca387ef3d 100644 (file)
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.opendaylight.protocol.pcep.pcc.mock.MsgBuilderUtil.createLspTlvs;
+
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import java.net.UnknownHostException;
@@ -25,6 +26,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.yang.pcep.topology.provider.SessionState;
 import org.opendaylight.protocol.pcep.PCEPCloseTermination;
+import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.protocol.pcep.TerminationReason;
 import org.opendaylight.protocol.pcep.pcc.mock.MsgBuilderUtil;
 import org.opendaylight.protocol.pcep.spi.AbstractMessageParser;
@@ -97,11 +99,14 @@ public class Stateful07TopologySessionListenerTest extends AbstractPCEPSessionTe
 
     private Stateful07TopologySessionListener listener;
 
+    private PCEPSession session;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
         this.listener = (Stateful07TopologySessionListener) getSessionListener();
+        this.session = getPCEPSession(getLocalPref(), getRemotePref());
     }
 
     @Test
@@ -302,8 +307,8 @@ public class Stateful07TopologySessionListenerTest extends AbstractPCEPSessionTe
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder().setLspIdentifiers(new LspIdentifiersBuilder().setLspId(new LspId(1L)).build()).setSymbolicPathName(
                                 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(new byte[] { 22, 34 })).build()).build()).build()).build());
         final Pcrpt rptmsg = new PcrptBuilder().setPcrptMessage(new PcrptMessageBuilder().setReports(reports).build()).build();
-        this.session.sessionUp();
-        this.session.handleMessage(rptmsg);
+        this.listener.onSessionUp(this.session);
+        this.listener.onMessage(this.session, rptmsg);
         final Topology topology = getTopology().get();
         assertFalse(topology.getNode().isEmpty());
     }
@@ -366,6 +371,11 @@ public class Stateful07TopologySessionListenerTest extends AbstractPCEPSessionTe
             .build()).build()).build()).build();
     }
 
+    @Override
+    protected Open getRemotePref() {
+        return getLocalPref();
+    }
+
     private AddLspInput createAddLspInput() {
         final ArgumentsBuilder argsBuilder = new ArgumentsBuilder();
         final Ipv4CaseBuilder ipv4Builder = new Ipv4CaseBuilder();
diff --git a/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimizationTest.java b/pcep/topology-provider/src/test/java/org/opendaylight/bgpcep/pcep/topology/provider/SyncOptimizationTest.java
new file mode 100644 (file)
index 0000000..7f7020e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.protocol.pcep.PCEPSession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Stateful1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.Tlvs3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev150714.lsp.db.version.tlv.LspDbVersionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.StatefulBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.Tlvs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
+
+public class SyncOptimizationTest {
+
+    @Mock
+    private PCEPSession pcepSession;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testDoesLspDbMatchPositive() {
+        final Tlvs tlvs = createTlvs(1l, false);
+        Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertTrue(syncOpt.doesLspDbMatch());
+    }
+
+    @Test
+    public void testDoesLspDbMatchNegative() {
+        final Tlvs localTlvs = createTlvs(1l, false);
+        final Tlvs remoteTlvs = createTlvs(2l, false);
+        Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertFalse(syncOpt.doesLspDbMatch());
+    }
+
+    @Test
+    public void testIsSyncAvoidanceEnabledPositive() {
+        final Tlvs tlvs = createTlvs(1l, true);
+        Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertTrue(syncOpt.isSyncAvoidanceEnabled());
+    }
+
+    @Test
+    public void testIsSyncAvoidanceEnabledNegative() {
+        final Tlvs localTlvs = createTlvs(1l, true);
+        final Tlvs remoteTlvs = createTlvs(2l, false);
+        Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertFalse(syncOpt.isSyncAvoidanceEnabled());
+    }
+
+    @Test
+    public void testIsDbVersionPresentPositive() {
+        final Tlvs localTlvs = createTlvs(null, false);
+        final Tlvs remoteTlvs = createTlvs(2l, false);
+        Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertTrue(syncOpt.isDbVersionPresent());
+    }
+
+    @Test
+    public void testIsDbVersionPresentNegative() {
+        final Tlvs tlvs = createTlvs(null, true);
+        Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
+        Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
+        final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+        assertFalse(syncOpt.isDbVersionPresent());
+    }
+
+    private static Tlvs createTlvs(final Long lspDbVersion, final boolean includeDbVresion) {
+        return new TlvsBuilder()
+            .addAugmentation(Tlvs1.class, new Tlvs1Builder().setStateful(
+                new StatefulBuilder().addAugmentation(Stateful1.class,
+                        new Stateful1Builder()
+                            .setIncludeDbVersion(includeDbVresion).build()).build()).build())
+            .addAugmentation(Tlvs3.class, new Tlvs3Builder().setLspDbVersion(
+                    new LspDbVersionBuilder().setLspDbVersionValue(lspDbVersion != null ? BigInteger.valueOf(lspDbVersion) : null).build()).build()).build();
+    }
+
+}
index efca708b4e6574492f2a0db769ddc179852ca58c..94b1e9cfdf3a3c82f88c93d84180dd1ad4605deb 100644 (file)
@@ -16,12 +16,12 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.opendaylight.bgpcep.pcep.topology.provider.TopologyProgrammingTest.MockedTopologySessionListenerFactory;
 import org.opendaylight.bgpcep.programming.spi.Instruction;
 import org.opendaylight.bgpcep.programming.spi.InstructionScheduler;
+import org.opendaylight.protocol.pcep.PCEPSession;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.StatefulBuilder;
@@ -76,11 +76,12 @@ public class TopologyProgrammingTest extends AbstractPCEPSessionTest<MockedTopol
 
     private TopologyProgramming topologyProgramming;
 
+    private PCEPSession session;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        MockitoAnnotations.initMocks(this);
         Mockito.doReturn(true).when(this.instruction).checkedExecutionStart();
         Mockito.doNothing().when(this.instruction).executionCompleted(InstructionStatus.Failed, null);
         Mockito.doAnswer(new Answer<Void>() {
@@ -156,6 +157,7 @@ public class TopologyProgrammingTest extends AbstractPCEPSessionTest<MockedTopol
         Mockito.doNothing().when(this.instruction).executionCompleted(Mockito.any(InstructionStatus.class), Mockito.any(Details.class));
         Mockito.doReturn(this.instructionFuture).when(this.scheduler).scheduleInstruction(Mockito.any(SubmitInstructionInput.class));
         this.topologyProgramming = new TopologyProgramming(this.scheduler, this.manager);
+        this.session = getPCEPSession(getLocalPref(), getRemotePref());
         listener.onSessionUp(this.session);
     }