From 0c5820220a4e7ebc3245259085d00551d2687e32 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Wed, 5 Oct 2016 15:03:33 +0200 Subject: HONEYCOMB-229 Introduce NAT to HC Reflects SNAT from VPP: - 1:1 Static IPv4 mapping - interface in/out NAT feature management Bonus: - Support presence containers in infra Change-Id: Ieb38526f83edbae5e605d5c7e39bb22bbafc50e5 Signed-off-by: Maros Marsalek --- .../data/impl/ModifiableDataTreeDelegator.java | 2 +- .../fd/honeycomb/data/impl/ModificationDiff.java | 34 ++++++++++++++++++++-- .../honeycomb/data/impl/ModificationDiffTest.java | 32 ++++++++++++++++++-- infra/data-impl/src/test/resources/test-diff.yang | 4 +++ 4 files changed, 66 insertions(+), 6 deletions(-) (limited to 'infra') diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java index 7af9847d7..7f8b53919 100644 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java @@ -115,7 +115,7 @@ public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter()); final ModificationDiff modificationDiff = - ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode); + ModificationDiff.recursivelyFromCandidateRoot(rootNode); LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff); // Distinguish between updates (create + update) and deletes diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java index 1c87bc03a..e78bb876b 100644 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java @@ -41,7 +41,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; final class ModificationDiff { private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap()); - private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE); + private static final EnumSet VALID_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE); + private static final EnumSet IGNORED_MODIFICATIONS = EnumSet.of(ModificationType.APPEARED, ModificationType.DISAPPEARED); private final Map updates; @@ -97,13 +98,26 @@ final class ModificationDiff { : EMPTY_DIFF); } + /** + * Same as {@link #recursivelyFromCandidate(YangInstanceIdentifier, DataTreeCandidateNode)} but does not process + * the root node for modifications, since it's the artificial data root, that has no child leaves but always is + * marked as SUBTREE_MODIFIED. + */ + @Nonnull + static ModificationDiff recursivelyFromCandidateRoot(@Nonnull final DataTreeCandidateNode currentCandidate) { + return recursivelyChildrenFromCandidate(YangInstanceIdentifier.EMPTY, currentCandidate); + } + /** * Check whether current node was modified. {@link MixinNode}s are ignored * and only nodes which direct leaves(or choices) are modified are considered a modification. */ private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) { + // Disappear is not a modification + if (IGNORED_MODIFICATIONS.contains(currentCandidate.getModificationType())) { + return false; // Mixin nodes are not considered modifications - if (isMixin(currentCandidate) && !isAugment(currentCandidate)) { + } else if (isMixin(currentCandidate) && !isAugment(currentCandidate)) { return false; } else { return isCurrentModified(currentCandidate); @@ -111,13 +125,18 @@ final class ModificationDiff { } private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) { + // First check if it's an empty presence node + if (isEmptyPresenceNode(currentCandidate)) { + return true; + } + // Check if there are any modified leaves and if so, consider current node as modified final Boolean directLeavesModified = currentCandidate.getChildNodes().stream() .filter(ModificationDiff::isLeaf) // For some reason, we get modifications on unmodified list keys // and that messes up our modifications collection here, so we need to skip .filter(ModificationDiff::isBeforeAndAfterDifferent) - .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType())) + .filter(child -> VALID_MODIFICATIONS.contains(child.getModificationType())) .findFirst() .isPresent(); @@ -132,6 +151,15 @@ final class ModificationDiff { .isPresent(); } + /** + * Check if new data are empty but still to be considered as a modification, meaning it's presence has a meaning + * e.g. containers with presence statement. + */ + private static boolean isEmptyPresenceNode(final @Nonnull DataTreeCandidateNode currentCandidate) { + return currentCandidate.getChildNodes().isEmpty() + && VALID_MODIFICATIONS.contains(currentCandidate.getModificationType()); + } + /** * Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}. */ diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java index 2fa82043b..cc00f2dc6 100644 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java @@ -1,9 +1,12 @@ package io.fd.honeycomb.data.impl; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import com.google.common.base.Optional; import java.util.Map; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; @@ -45,10 +48,11 @@ public class ModificationDiffTest { static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1"); static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2"); + static final QName PRESENCE_CONTAINER_QNAME = QName.create(TOP_CONTAINER_QNAME, "presence"); + static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME); static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - @Test public void testInitialWrite() throws Exception { final TipProducingDataTree dataTree = getDataTree(); @@ -65,6 +69,30 @@ public class ModificationDiffTest { assertUpdate(modificationDiff.getUpdates().values().iterator().next(), TOP_CONTAINER_ID, null, topContainer); } + @Test + public void testWritePresenceEmptyContainer() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final DataTreeModification dataTreeModification = getModification(dataTree); + final NormalizedNode presenceContainer = Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(PRESENCE_CONTAINER_QNAME)) + .build(); + final YangInstanceIdentifier PRESENCE_CONTAINER_ID = YangInstanceIdentifier.of(PRESENCE_CONTAINER_QNAME); + dataTreeModification.write(PRESENCE_CONTAINER_ID, presenceContainer); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final ModificationDiff modificationDiff = getModificationDiff(prepare); + + dataTree.commit(prepare); + + final Optional> presenceAfter = getModification(dataTree).readNode(PRESENCE_CONTAINER_ID); + assertTrue(presenceAfter.isPresent()); + assertThat(presenceAfter.get(), equalTo(presenceContainer)); + + assertThat(modificationDiff.getUpdates().size(), is(1)); + assertThat(modificationDiff.getUpdates().values().size(), is(1)); + assertUpdate(modificationDiff.getUpdates().values().iterator().next(), PRESENCE_CONTAINER_ID, null, presenceContainer); + } + @Test public void testInitialWriteForContainerWithChoice() throws Exception { final TipProducingDataTree dataTree = getDataTree(); @@ -132,7 +160,7 @@ public class ModificationDiffTest { } private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) { - return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode()); + return ModificationDiff.recursivelyFromCandidateRoot(prepare.getRootNode()); } @Test diff --git a/infra/data-impl/src/test/resources/test-diff.yang b/infra/data-impl/src/test/resources/test-diff.yang index 5cccc8718..6c27ddc17 100644 --- a/infra/data-impl/src/test/resources/test-diff.yang +++ b/infra/data-impl/src/test/resources/test-diff.yang @@ -7,6 +7,10 @@ module test-diff { description "Initial revision"; } + container presence { + presence "testing presence"; + } + container top-container { leaf string { type string; -- cgit 1.2.3-korg