From 4f8dbff5c3a94f5ea8db32a3601fc704b95250f7 Mon Sep 17 00:00:00 2001 From: Jan Srnicek Date: Thu, 12 Jan 2017 09:59:30 +0100 Subject: HONEYCOMB-296 - Reference checking in Locator set Reference must be checked while removing to prevent dead references Change-Id: I37cb426f73a3fa64d4e6795062d8d7affc0cbb2b Signed-off-by: Jan Srnicek --- .../lisp/translate/write/LocatorSetCustomizer.java | 55 ++++++++++++- .../translate/write/LocatorSetCustomizerTest.java | 89 +++++++++++++++++++++- .../common/translate/util/ReferenceCheck.java | 40 ++++++++++ 3 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizer.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizer.java index b125d4038..8c41372e1 100755 --- a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizer.java +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizer.java @@ -20,17 +20,29 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static java.nio.charset.StandardCharsets.UTF_8; -import io.fd.hc2vpp.lisp.translate.read.trait.LocatorSetReader; -import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import com.google.common.base.Optional; import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.common.translate.util.ReferenceCheck; +import io.fd.hc2vpp.lisp.translate.read.trait.LocatorSetReader; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet; import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.DpSubtableGrouping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.Lisp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.LocalMappings; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.local.mappings.LocalMapping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.VniTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.lisp.feature.data.grouping.LispFeatureData; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSet; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSetKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.locator.set.Interface; @@ -44,7 +56,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; */ public class LocatorSetCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer, ByteDataTranslator, - LocatorSetReader { + LocatorSetReader, ReferenceCheck { private final NamingContext locatorSetContext; @@ -85,11 +97,48 @@ public class LocatorSetCustomizer extends FutureJVppCustomizer @Nonnull LocatorSet dataBefore, @Nonnull WriteContext writeContext) throws WriteFailedException { final String locatorSetName = dataBefore.getName(); + + final Optional eidTableData = writeContext.readAfter(InstanceIdentifier.create(Lisp.class) + .child(LispFeatureData.class) + .child(EidTable.class)); + + if (eidTableData.isPresent()) { + // due to non-functional LeafRefValidation, it must be checked like this + final List vniTables = + Optional.fromNullable(eidTableData.get().getVniTable()).or(Collections.emptyList()); + checkReferenceExist(id, vrfReferences(vniTables, locatorSetName)); + checkReferenceExist(id, bdReferences(vniTables, locatorSetName)); + } + addDelLocatorSetAndReply(false, dataBefore.getName(), id); //removes mapping after successful delete locatorSetContext.removeName(locatorSetName, writeContext.getMappingContext()); } + private Collection bdReferences(final List vniTables, + final String locatorSetName) { + return vniTables.stream() + .map(vniTable -> java.util.Optional.ofNullable(vniTable.getBridgeDomainSubtable()) + .map(DpSubtableGrouping::getLocalMappings) + .map(LocalMappings::getLocalMapping) + .orElse(Collections.emptyList())) + .flatMap(Collection::stream) + .filter(localMapping -> locatorSetName.equals(localMapping.getLocatorSet())) + .collect(Collectors.toSet()); + } + + private static Collection vrfReferences(final List vniTables, + final String locatorSetName) { + return vniTables.stream() + .map(vniTable -> java.util.Optional.ofNullable(vniTable.getVrfSubtable()) + .map(DpSubtableGrouping::getLocalMappings) + .map(LocalMappings::getLocalMapping) + .orElse(Collections.emptyList())) + .flatMap(Collection::stream) + .filter(localMapping -> locatorSetName.equals(localMapping.getLocatorSet())) + .collect(Collectors.toSet()); + } + private int addDelLocatorSetAndReply(final boolean add, final String name, final InstanceIdentifier id) throws WriteFailedException { diff --git a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizerTest.java b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizerTest.java index b29e1a018..734dddd6c 100755 --- a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizerTest.java +++ b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizerTest.java @@ -40,6 +40,14 @@ import java.util.Arrays; import java.util.concurrent.ExecutionException; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.Lisp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.LocalMappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.local.mappings.LocalMappingBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.VniTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.vni.table.VrfSubtableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.lisp.feature.data.grouping.LispFeatureData; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.LocatorSets; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSet; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSetBuilder; @@ -49,6 +57,15 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public class LocatorSetCustomizerTest extends WriterCustomizerTest { + private static final InstanceIdentifier + EID_TABLE_ID = InstanceIdentifier.create(Lisp.class) + .child(LispFeatureData.class) + .child(EidTable.class); + + private static final LocatorSet LOCATOR_SET_TO_DELETE = new LocatorSetBuilder() + .setName("Locator") + .build(); + private LocatorSetCustomizer customizer; @Override @@ -126,10 +143,25 @@ public class LocatorSetCustomizerTest extends WriterCustomizerTest { @Test public void testDeleteCurrentAttributes() throws InterruptedException, ExecutionException, WriteFailedException { - LocatorSet locatorSet = new LocatorSetBuilder() - .setName("Locator") - .build(); + when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(Optional.absent()); + verifySuccessfullDelete(LOCATOR_SET_TO_DELETE); + } + + @Test + public void testDeleteCurrentAttributesWithoutLocalMappingContainer() + throws InterruptedException, ExecutionException, WriteFailedException { + when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(eidTableDataWithoutLocalMappingContainer()); + verifySuccessfullDelete(LOCATOR_SET_TO_DELETE); + } + + @Test + public void testDeleteCurrentAttributesWithoutLocalMappingValues() + throws InterruptedException, ExecutionException, WriteFailedException { + when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(eidTableDataWithoutLocalMappingValues()); + verifySuccessfullDelete(LOCATOR_SET_TO_DELETE); + } + private void verifySuccessfullDelete(final LocatorSet locatorSet) throws WriteFailedException { ArgumentCaptor locatorSetCaptor = ArgumentCaptor.forClass(LispAddDelLocatorSet.class); when(api.lispAddDelLocatorSet(any(LispAddDelLocatorSet.class))) @@ -145,4 +177,55 @@ public class LocatorSetCustomizerTest extends WriterCustomizerTest { assertEquals("Locator", new String(request.locatorSetName)); assertEquals(0, request.isAdd); } + + @Test + public void testDeleteReferenced() throws InterruptedException, ExecutionException, WriteFailedException { + when(writeContext.readAfter(EID_TABLE_ID)) + .thenReturn(eidTableData()); + + ArgumentCaptor locatorSetCaptor = ArgumentCaptor.forClass(LispAddDelLocatorSet.class); + + when(api.lispAddDelLocatorSet(any(LispAddDelLocatorSet.class))) + .thenReturn(future(new LispAddDelLocatorSetReply())); + + try { + customizer.deleteCurrentAttributes(null, LOCATOR_SET_TO_DELETE, writeContext); + } catch (IllegalStateException e) { + verify(api, times(0)).lispAddDelLocatorSet(locatorSetCaptor.capture()); + return; + } + fail("testDeleteReferenced should have failed"); + } + + private static Optional eidTableData() { + return Optional.of(new EidTableBuilder() + .setVniTable( + Arrays.asList(new VniTableBuilder() + .setVrfSubtable(new VrfSubtableBuilder() + .setLocalMappings(new LocalMappingsBuilder() + .setLocalMapping(Arrays.asList( + new LocalMappingBuilder().setLocatorSet("Locator") + .build(), + new LocalMappingBuilder() + .setLocatorSet("OtherLocatorSet").build() + )).build()).build()).build())).build()); + } + + private static Optional eidTableDataWithoutLocalMappingValues() { + return Optional.of(new EidTableBuilder() + .setVniTable( + Arrays.asList(new VniTableBuilder() + .setVrfSubtable(new VrfSubtableBuilder() + .setLocalMappings(new LocalMappingsBuilder().build()).build()).build())) + .build()); + } + + private static Optional eidTableDataWithoutLocalMappingContainer() { + return Optional.of(new EidTableBuilder() + .setVniTable( + Arrays.asList(new VniTableBuilder().setVrfSubtable(new VrfSubtableBuilder().build()).build())) + .build()); + } + + } diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java new file mode 100644 index 000000000..847f28aed --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.common.translate.util; + +import static com.google.common.base.Preconditions.checkState; + +import java.util.Collection; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Checks references exist, and throws if present + */ +public interface ReferenceCheck { + + /** + * Checks if references are present, and throw if so + * + * @throws IllegalStateException if any references present + */ + default void checkReferenceExist(@Nonnull final InstanceIdentifier locSetId, + final Collection references) { + checkState(references == null || references.isEmpty(), "%s is referenced in %s", locSetId, references); + } +} -- cgit 1.2.3-korg