From 1fb7cb0596bde05c0931c43e53fba98e74005f9d Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 22 Mar 2016 15:10:06 +0100 Subject: Migrate Vpp/BridgeDomains config management under new writers Change-Id: I0e5734bd54548ff78a2ec4420e4a8294401f4d46 Signed-off-by: Maros Marsalek --- .../v3po/impl/vpp/BridgeDomainCustomizer.java | 123 ++++++++++++++++ .../io/fd/honeycomb/v3po/impl/vpp/VppTest.java | 163 +++++++++++++++++++++ .../io/fd/honeycomb/v3po/impl/vpp/VppUtils.java | 62 ++++++++ 3 files changed, 348 insertions(+) create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java create mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java create mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java (limited to 'v3po') diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java new file mode 100644 index 000000000..f707164eb --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java @@ -0,0 +1,123 @@ +/* + * 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.honeycomb.v3po.impl.vpp; + +import static com.google.common.base.Preconditions.checkState; + +import io.fd.honeycomb.v3po.impl.trans.util.Context; +import io.fd.honeycomb.v3po.impl.trans.util.VppApiCustomizer; +import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.ListVppWriterCustomizer; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BridgeDomainCustomizer + extends VppApiCustomizer + implements ListVppWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + + static final byte ADD_BD = (byte) 1; + static final int NO_RET_VAL = -77; + static final int RELEASE = 1; + + public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi api) { + super(api); + } + + @Nonnull + @Override + public List extract(@Nonnull final InstanceIdentifier currentId, + @Nonnull final DataObject parentData) { + return ((BridgeDomains) parentData).getBridgeDomain(); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain current, + @Nonnull final Context ctx) { + final String bdName = current.getName(); + int bdId = getVppApi().findOrAddBridgeDomainId(bdName); + checkState(bdId > 0, "Unable to find or create bridge domain. Return code: %s", bdId); + + byte flood = booleanToByte(current.isFlood()); + byte forward = booleanToByte(current.isForward()); + byte learn = booleanToByte(current.isLearn()); + byte uuf = booleanToByte(current.isUnknownUnicastFlood()); + byte arpTerm = booleanToByte(current.isArpTermination()); + + int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_BD); + + int rv = NO_RET_VAL; + while (rv == -77) { + rv = getVppApi().getRetval(ctxId, RELEASE /* release */); + // TODO limit attempts + } + checkState(rv > 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv); + + bdId = getVppApi().bridgeDomainIdFromName(bdName); + LOG.debug("Bridge domain {} written as {} successfully", bdName, bdId); + } + + private byte booleanToByte(@Nullable final Boolean aBoolean) { + return aBoolean != null && aBoolean ? (byte) 1 : (byte) 0; + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, + @Nonnull final Context ctx) { + String bdName = id.firstKeyOf(BridgeDomain.class).getName(); + + int bdId = getVppApi().findOrAddBridgeDomainId(bdName); + checkState(bdId > 0, "Unable to delete bridge domain. Does not exist. Return code: %s", bdId); + + int ctxId = getVppApi().bridgeDomainAddDel(bdId, + (byte) 0 /* flood */, + (byte) 0 /* forward */, + (byte) 0 /* learn */, + (byte) 0 /* uuf */, + (byte) 0 /* arpTerm */, + (byte) 0 /* isAdd */); + + int rv = NO_RET_VAL; + while (rv == NO_RET_VAL) { + rv = getVppApi().getRetval(ctxId, RELEASE /* release */); + // TODO limit attempts + } + + checkState(rv > 0, "Bridge domain delete failed. Return code: %s", rv); + LOG.debug("Bridge domain {} deleted as {} successfully", bdName, bdId); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, + @Nonnull final Context ctx) { + // Most basic update implementation: Delete + Write + deleteCurrentAttributes(id, dataBefore, ctx); + writeCurrentAttributes(id, dataAfter, ctx); + } + +} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java new file mode 100644 index 000000000..beec76ab1 --- /dev/null +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java @@ -0,0 +1,163 @@ +/* + * 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.honeycomb.v3po.impl.vpp; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.util.DelegatingWriterRegistry; +import java.util.Collections; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") +@PrepareForTest(vppApi.class) +public class VppTest { + + private vppApi api; + private DelegatingWriterRegistry rootRegistry; + private CompositeRootVppWriter vppWriter; + private WriteContext ctx; + + final byte zero = (byte) 0; + final byte flood = (byte) 1; + final byte forward = (byte) 0; + final byte learn = (byte) 1; + final byte uuf = (byte) 0; + final byte arpTerm = (byte) 0; + final byte add = (byte) 1; + + @Before + public void setUp() throws Exception { + api = PowerMockito.mock(vppApi.class); + ctx = mock(WriteContext.class); + PowerMockito.doAnswer(new Answer() { + @Override + public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable { + final String bName = (String) invocationOnMock.getArguments()[0]; + return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString()); + } + }).when(api).findOrAddBridgeDomainId(anyString()); + PowerMockito.doReturn(1).when(api).bridgeDomainIdFromName(anyString()); + PowerMockito.doReturn(1).when(api).getRetval(anyInt(), anyInt()); + vppWriter = VppUtils.getVppWriter(api); + rootRegistry = new DelegatingWriterRegistry( + Collections.>singletonList(vppWriter)); + } + + @Test + public void writeVpp() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + Collections.emptyList(), + Lists.newArrayList(new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build()), + ctx); + + verify(api).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); + + vppWriter.update(InstanceIdentifier.create(Vpp.class), + Collections.emptyList(), + Lists.newArrayList(new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build()), + ctx); + + verify(api, times(2)).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); + } + + private BridgeDomains getBridgeDomains(String... name) { + final List bdmns = Lists.newArrayList(); + for (String s : name) { + bdmns.add(new BridgeDomainBuilder() + .setName(s) + .setArpTermination(false) + .setFlood(true) + .setForward(false) + .setLearn(true) + .build()); + } + return new BridgeDomainsBuilder() + .setBridgeDomain(bdmns) + .build(); + } + + @Test + public void deleteVpp() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + Collections.singletonList(new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build()), + Collections.emptyList(), + ctx); + + final byte zero = (byte) 0; + + verify(api).bridgeDomainAddDel(1, zero, zero, zero, zero, zero, zero); + } + + @Test + public void updateVppNoActualChange() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + Collections.singletonList(new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build()), + Collections.singletonList(new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build()), + ctx); + + verifyZeroInteractions(api); + } + + @Test + public void writeBridgeDomain() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class), + getBridgeDomains("bdn1", "bdn2").getBridgeDomain(), + getBridgeDomains("bdn1", "bdn3").getBridgeDomain(), + ctx); + + // bdn1 is untouched + // bdn3 is added + verify(api).bridgeDomainAddDel(3, flood, forward, learn, uuf, arpTerm, add); + // bdn2 is deleted + verify(api).bridgeDomainAddDel(2, zero, zero, zero, zero, zero, zero); + } + + // TODO test unkeyed list + // TODO test update of a child without dedicated writer +} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java new file mode 100644 index 000000000..d73a8732c --- /dev/null +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java @@ -0,0 +1,62 @@ +/* + * 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.honeycomb.v3po.impl.vpp; + +import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; +import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.impl.trans.w.util.NoopWriterCustomizer; +import io.fd.honeycomb.v3po.impl.trans.w.util.ReflexiveChildWriterCustomizer; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.openvpp.vppjapi.vppApi; + +final class VppUtils { + + public VppUtils() {} + + /** + * Create root Vpp writer with all its children wired + */ + static CompositeRootVppWriter getVppWriter(@Nonnull final vppApi vppApi) { + + final CompositeListVppWriter bridgeDomainWriter = new CompositeListVppWriter<>( + BridgeDomain.class, + new io.fd.honeycomb.v3po.impl.vpp.BridgeDomainCustomizer(vppApi)); + + final ChildVppWriter bridgeDomainsReader = new CompositeChildVppWriter<>( + BridgeDomains.class, + VppRWUtils.singletonChildWriterList(bridgeDomainWriter), + new ReflexiveChildWriterCustomizer()); + + final List>> childWriters = new ArrayList<>(); + childWriters.add(bridgeDomainsReader); + + return new CompositeRootVppWriter<>( + Vpp.class, + childWriters, + new NoopWriterCustomizer()); + } +} -- cgit 1.2.3-korg