description
"Initial state resynchronization is being performed.";
}
+ enum incremental-sync {
+ description
+ "Incremental state resynchronization is being performed.";
+ }
enum synchronized {
description
"State synchronization has been achieved.";
final Node initialNodeState = state.getInitialNodeState();
final boolean isNodePresent = isLspDbRetreived() && initialNodeState != null;
if (isNodePresent) {
- loadLspData(initialNodeState, lspData, lsps);
+ loadLspData(initialNodeState, lspData, lsps, isIncrementalSynchro());
pccBuilder.setReportedLsp(initialNodeState.getAugmentation(Node1.class).getPathComputationClient().getReportedLsp());
}
writeNode(pccBuilder, state, topologyAugment);
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 abstract void loadLspData(final Node node, final Map<String, ReportedLsp> lspData, final Map<L, String> lsps, final boolean incrementalSynchro);
protected final boolean isLspDbPersisted() {
if (syncOptimization != null) {
return false;
}
+ /**
+ * Is Incremental synchronization if LSP-DB-VERSION are included,
+ * LSP-DB-VERSION TLV values doesnt match, and LSP-SYNC-CAPABILITY is enabled
+ * @return
+ */
+ protected final boolean isIncrementalSynchro() {
+ if (syncOptimization != null) {
+ return syncOptimization.isSyncAvoidanceEnabled() && syncOptimization.isDeltaSyncEnabled();
+ }
+ return false;
+ }
+
protected final boolean isSynchronized() {
if (syncOptimization != null) {
return syncOptimization.doesLspDbMatch();
pccBuilder.setReportedLsp(Collections.<ReportedLsp> emptyList());
if (isSynchronized()) {
pccBuilder.setStateSync(PccSyncState.Synchronized);
+ } else if (isIncrementalSynchro()) {
+ pccBuilder.setStateSync(PccSyncState.IncrementalSync);
} else {
pccBuilder.setStateSync(PccSyncState.InitialResync);
}
private boolean manageNextReport(final Reports report, final MessageContext ctx) {
final Lsp lsp = report.getLsp();
final PlspId plspid = lsp.getPlspId();
- if (!lsp.isSync() && (lsp.getPlspId() == null || plspid.getValue() == 0)) {
+ if (!lsp.isSync() && (plspid == null || plspid.getValue() == 0)) {
purgeStaleLsps(ctx);
stateSynchronizationAchieved(ctx);
return true;
return capa;
}
+ /**
+ * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale
+ * @param lspData
+ * @param lsps
+ * @param incrementalSynchro
+ */
@Override
- protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData, final Map<PlspId, String> lsps) {
+ protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData, final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
//load node's lsps from DS
final PathComputationClient pcc = node.getAugmentation(Node1.class).getPathComputationClient();
final List<ReportedLsp> reportedLsps = pcc.getReportedLsp();
final Path1 path1 = reportedLsp.getPath().get(0).getAugmentation(Path1.class);
if (path1 != null) {
final PlspId plspId = path1.getLsp().getPlspId();
- staleLsps.add(plspId);
+ if (!incrementalSynchro) {
+ staleLsps.add(plspId);
+ }
lsps.put(plspId, lspName);
}
}
}
}
+ /**
+ * When the PCC reports an LSP during state synchronization, if the LSP already
+ * exists in the LSP database, the PCE MUST update the LSP database and
+ * clear the stale marker from the LSP
+ * @param plspId
+ * @param sync
+ */
private synchronized void unmarkStaleLsp(final PlspId plspId, final boolean sync) {
if (!sync) {
staleLsps.remove(plspId);
}
}
+ /**
+ * Purge any LSPs from the LSP database that are still marked as stale
+ * @param ctx
+ */
private synchronized void purgeStaleLsps(final MessageContext ctx) {
for (final PlspId plspId : staleLsps) {
removeLsp(ctx, plspId);
private final boolean dbVersionMatch;
private final boolean isSyncAvoidanceEnabled;
+ private final boolean isDeltaSyncEnabled;
private final boolean isDbVersionPresent;
public SyncOptimization(final PCEPSession session) {
final LspDbVersion remoteLspDbVersion = getLspDbVersion(remote);
this.dbVersionMatch = compareLspDbVersion(localLspDbVersion, remoteLspDbVersion);
this.isSyncAvoidanceEnabled = isSyncAvoidance(local) && isSyncAvoidance(remote);
+ this.isDeltaSyncEnabled = isDeltaSync(local) && isDeltaSync(remote);
this.isDbVersionPresent = localLspDbVersion != null || remoteLspDbVersion != null;
}
return isSyncAvoidanceEnabled;
}
+ public boolean isDeltaSyncEnabled() {
+ return isDeltaSyncEnabled;
+ }
+
public boolean isDbVersionPresent() {
return isDbVersionPresent;
}
return false;
}
- private static boolean isSyncAvoidance(final Tlvs openTlvs) {
+ private static Stateful1 getStateful1(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 tlvs1.getStateful().getAugmentation(Stateful1.class);
}
}
+ return null;
+ }
+
+ private static boolean isSyncAvoidance(final Tlvs openTlvs) {
+ final Stateful1 stateful1 = getStateful1(openTlvs);
+ if (stateful1 != null && stateful1.isIncludeDbVersion() != null) {
+ return stateful1.isIncludeDbVersion();
+ }
+ return false;
+ }
+
+ private static boolean isDeltaSync(final Tlvs openTlvs) {
+ final Stateful1 stateful1 = getStateful1(openTlvs);
+ if (stateful1 != null && stateful1.isDeltaLspSyncCapability() != null) {
+ return stateful1.isDeltaLspSyncCapability();
+ }
return false;
}
--- /dev/null
+/*
+ * 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.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;
+
+public class IncrementalSynchronizationProcedureTest 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 testStateSynchronizationPerformed() throws InterruptedException, ExecutionException {
+ this.session = getPCEPSession(getOpen(null), getOpen(null));
+ this.listener.onSessionUp(session);
+ //report LSP + LSP-DB version number
+ final Pcrpt pcRpt = getPcrpt(1L, "test");
+ this.listener.onMessage(session, pcRpt);
+
+ final PathComputationClient pcc = getTopology().get().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 PathComputationClient pcc2 = getTopology().get().getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+ //check node - IncrementalSync state
+ Assert.assertEquals(PccSyncState.IncrementalSync, pcc2.getStateSync());
+ //check reported LSP - persisted from previous session
+ Assert.assertFalse(pcc2.getReportedLsp().isEmpty());
+
+ //report LSP2 + LSP-DB version number 2
+ final Pcrpt pcRpt2 = getPcrpt(2L,"testsecond");
+ this.listener.onMessage(session, pcRpt2);
+
+ final PathComputationClient pcc3 = getTopology().get().getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+
+ //check node - synchronized
+ Assert.assertEquals(PccSyncState.IncrementalSync, pcc3.getStateSync());
+ //check reported LSP is not empty
+ Assert.assertEquals(2, pcc3.getReportedLsp().size());
+
+ //sync rpt + LSP-DB
+ final Pcrpt syncMsg = getSyncPcrt();
+ this.listener.onMessage(session, syncMsg);
+ final PathComputationClient pcc4 = getTopology().get().getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+ //check node - synchronized
+ Assert.assertEquals(PccSyncState.Synchronized, pcc4.getStateSync());
+ //check reported LSP is empty, LSP state from previous session was purged
+ Assert.assertEquals(2, pcc4.getReportedLsp().size());
+
+
+ //report LSP3 + LSP-DB version number 4
+ final Pcrpt pcRpt3 = getPcrpt(3L,"testthird");
+ this.listener.onMessage(session, pcRpt3);
+
+ final PathComputationClient pcc5 = getTopology().get().getNode().get(0).getAugmentation(Node1.class).getPathComputationClient();
+
+ //check node - synchronized
+ Assert.assertEquals(PccSyncState.Synchronized, pcc5.getStateSync());
+ Assert.assertEquals(3,pcc5.getReportedLsp().size());
+ }
+
+ private 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).setDeltaLspSyncCapability(Boolean.TRUE).build())
+ .build()).build()).addAugmentation(Tlvs3.class, new Tlvs3Builder().setLspDbVersion(dbVersion).build()).build()).build();
+ }
+
+ private Pcrpt getPcrpt(Long val, String pathname) {
+ return MsgBuilderUtil.createPcRtpMessage(new LspBuilder().setPlspId(new PlspId(val)).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(val)).build())
+ .setSymbolicPathName(new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(pathname.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(val)).build()).build()).build()).setPlspId(new PlspId(val)
+ ).setSync(true).setRemove(false).setOperational(OperationalStatus.Active).build(), Optional.<Srp>absent(), createPath(Collections.<Subobject>emptyList()));
+ }
+
+ private Pcrpt getSyncPcrt() {
+ return 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(3l)).build()).build()).build()), true, false), Optional.<Srp>absent(),
+ createPath(Collections.<Subobject>emptyList()));
+ }
+}
@Test
public void testDoesLspDbMatchPositive() {
- final Tlvs tlvs = createTlvs(1l, false);
+ final Tlvs tlvs = createTlvs(1l, false, false);
Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
@Test
public void testDoesLspDbMatchNegative() {
- final Tlvs localTlvs = createTlvs(1l, false);
- final Tlvs remoteTlvs = createTlvs(2l, false);
+ final Tlvs localTlvs = createTlvs(1l, false, false);
+ final Tlvs remoteTlvs = createTlvs(2l, false, false);
Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
@Test
public void testIsSyncAvoidanceEnabledPositive() {
- final Tlvs tlvs = createTlvs(1l, true);
+ final Tlvs tlvs = createTlvs(1l, true, false);
Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
@Test
public void testIsSyncAvoidanceEnabledNegative() {
- final Tlvs localTlvs = createTlvs(1l, true);
- final Tlvs remoteTlvs = createTlvs(2l, false);
+ final Tlvs localTlvs = createTlvs(1l, true, false);
+ final Tlvs remoteTlvs = createTlvs(2l, false, 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 testIsDeltaSyncEnabledPositive() {
+ final Tlvs tlvs = createTlvs(1l, true, true);
+ Mockito.doReturn(tlvs).when(pcepSession).localSessionCharacteristics();
+ Mockito.doReturn(tlvs).when(pcepSession).getRemoteTlvs();
+ final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+ assertTrue(syncOpt.isDeltaSyncEnabled());
+ }
+
+ @Test
+ public void testIsDeltaSyncEnabledNegative() {
+ final Tlvs localTlvs = createTlvs(1l, true, true);
+ final Tlvs remoteTlvs = createTlvs(2l, false, false);
+ Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
+ Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
+ final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
+ assertFalse(syncOpt.isDeltaSyncEnabled());
+ }
+
@Test
public void testIsDbVersionPresentPositive() {
- final Tlvs localTlvs = createTlvs(null, false);
- final Tlvs remoteTlvs = createTlvs(2l, false);
+ final Tlvs localTlvs = createTlvs(null, false, false);
+ final Tlvs remoteTlvs = createTlvs(2l, false, false);
Mockito.doReturn(localTlvs).when(pcepSession).localSessionCharacteristics();
Mockito.doReturn(remoteTlvs).when(pcepSession).getRemoteTlvs();
final SyncOptimization syncOpt = new SyncOptimization(pcepSession);
@Test
public void testIsDbVersionPresentNegative() {
- final Tlvs tlvs = createTlvs(null, true);
+ final Tlvs tlvs = createTlvs(null, true, false);
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) {
+ private static Tlvs createTlvs(final Long lspDbVersion, final boolean includeDbVresion, final boolean includeDeltaSync) {
return new TlvsBuilder()
.addAugmentation(Tlvs1.class, new Tlvs1Builder().setStateful(
new StatefulBuilder().addAugmentation(Stateful1.class,
new Stateful1Builder()
- .setIncludeDbVersion(includeDbVresion).build()).build()).build())
+ .setIncludeDbVersion(includeDbVresion).setDeltaLspSyncCapability(includeDeltaSync).build()).build()).build())
.addAugmentation(Tlvs3.class, new Tlvs3Builder().setLspDbVersion(
- new LspDbVersionBuilder().setLspDbVersionValue(lspDbVersion != null ? BigInteger.valueOf(lspDbVersion) : null).build()).build()).build();
+ new LspDbVersionBuilder().setLspDbVersionValue(lspDbVersion != null ? BigInteger.valueOf(lspDbVersion) : null).build()).build()).build();
}
}