Bridge domain interconnection read customizer
authorMarek Gradzki <[email protected]>
Mon, 16 May 2016 12:57:04 +0000 (14:57 +0200)
committerMarek Gradzki <[email protected]>
Thu, 19 May 2016 11:24:18 +0000 (11:24 +0000)
Change-Id: If74cf4ad2a05b3311478afc64cb54748f0d813dc
Signed-off-by: Marek Gradzki <[email protected]>
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java [new file with mode: 0644]

diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java
new file mode 100644 (file)
index 0000000..099d4c1
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
+import org.openvpp.jvpp.dto.BridgeDomainDump;
+import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2
+ */
+public class L2Customizer extends FutureJVppCustomizer
+        implements ChildReaderCustomizer<L2, L2Builder> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
+    private final NamingContext interfaceContext;
+    private final NamingContext bridgeDomainContext;
+
+    public L2Customizer(@Nonnull final FutureJVpp futureJvpp,
+                        @Nonnull final NamingContext interfaceContext,
+                        @Nonnull final NamingContext bridgeDomainContext) {
+        super(futureJvpp);
+        this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+        this.bridgeDomainContext = Preconditions.checkNotNull(bridgeDomainContext, "bridgeDomainContext should not be null");
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
+        ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue);
+    }
+
+    @Nonnull
+    @Override
+    public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
+        return new L2Builder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
+                                      @Nonnull final Context ctx) throws ReadFailedException {
+        LOG.debug("Reading attributes for L2: {}", id);
+        final InterfaceKey key = id.firstKeyOf(Interface.class);
+        final int ifaceId = interfaceContext.getIndex(key.getName());
+
+        final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
+                ifaceId, ctx);
+        LOG.debug("Interface details for interface: {}, details: {}", key.getName(), iface);
+
+        final Optional<BridgeDomainSwIfDetails> bdForInterface = getBridgeDomainForInterface(ifaceId);
+        if (bdForInterface.isPresent()) {
+            final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get();
+            final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
+            bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId));
+            // bbBuilder.setBridgedVirtualInterface // TODO where to find that value?
+            if (bdSwIfDetails.shg != 0) {
+                bbBuilder.setSplitHorizonGroup((short)bdSwIfDetails.shg);
+            }
+            builder.setInterconnection(bbBuilder.build());
+        }
+
+        // TODO is there a way to check if interconnection is XconnectBased?
+    }
+
+    private Optional<BridgeDomainSwIfDetails> getBridgeDomainForInterface(final int ifaceId) {
+        // We need to perform full bd dump, because there is no way
+        // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?)
+        // TODO cache dump result
+        final BridgeDomainDump request = new BridgeDomainDump();
+        request.bdId = -1;
+
+        final CompletableFuture<BridgeDomainDetailsReplyDump> bdCompletableFuture =
+                getFutureJVpp().bridgeDomainSwIfDump(request).toCompletableFuture();
+        final BridgeDomainDetailsReplyDump reply = V3poUtils.getReply(bdCompletableFuture);
+
+        if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) {
+            return Optional.empty();
+        }
+
+        // interface can be added to only one BD only
+        return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst();
+    }
+}
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java
new file mode 100644 (file)
index 0000000..b454446
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.test.ChildReaderCustomizerTest;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
+import org.openvpp.jvpp.dto.BridgeDomainDump;
+import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+
+public class L2CustomizerTest extends ChildReaderCustomizerTest<L2, L2Builder> {
+
+    private NamingContext interfaceContext;
+    private NamingContext bridgeDomainContext;
+
+    public L2CustomizerTest() {
+        super(L2.class);
+    }
+
+    @Override
+    public void setUpBefore() {
+        interfaceContext = new NamingContext("generatedIfaceName");
+        bridgeDomainContext = new NamingContext("generatedBDName");
+    }
+
+    @Override
+    protected RootReaderCustomizer<L2, L2Builder> initCustomizer() {
+        return new L2Customizer(api, interfaceContext, bridgeDomainContext);
+    }
+
+    @Test
+    public void testMerge() {
+        final VppInterfaceStateAugmentationBuilder builder = mock(VppInterfaceStateAugmentationBuilder.class);
+        final L2 value = mock(L2.class);
+        getCustomizer().merge(builder, value);
+        verify(builder).setL2(value);
+    }
+
+    private InstanceIdentifier<L2> getL2Id(final String name) {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name))
+                .augmentation(
+                        VppInterfaceStateAugmentation.class).child(L2.class);
+    }
+
+    private void whenBridgeDomainSwIfDumpThenReturn(final List<BridgeDomainSwIfDetails> bdSwIfList)
+            throws ExecutionException, InterruptedException {
+        final CompletionStage<BridgeDomainDetailsReplyDump> replyCS = mock(CompletionStage.class);
+        final CompletableFuture<BridgeDomainDetailsReplyDump> replyFuture = mock(CompletableFuture.class);
+        when(replyCS.toCompletableFuture()).thenReturn(replyFuture);
+        final BridgeDomainDetailsReplyDump reply = new BridgeDomainDetailsReplyDump();
+        reply.bridgeDomainSwIfDetails = bdSwIfList;
+        when(replyFuture.get()).thenReturn(reply);
+        when(api.bridgeDomainSwIfDump(any(BridgeDomainDump.class))).thenReturn(replyCS);
+    }
+
+
+    private BridgeDomainSwIfDetails generateBdSwIfDetails(final int ifId, final int bdId) {
+        final BridgeDomainSwIfDetails bdSwIfDetails = new BridgeDomainSwIfDetails();
+        bdSwIfDetails.swIfIndex = ifId;
+        bdSwIfDetails.shg = 1;
+        bdSwIfDetails.bdId = bdId;
+        return bdSwIfDetails;
+    }
+
+    private Interconnection generateInterconnection(final int ifId, final String bdName) {
+        final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
+        bbBuilder.setBridgeDomain(bdName);
+        bbBuilder.setSplitHorizonGroup((short) 1);
+        return bbBuilder.build();
+    }
+
+    @Test
+    public void testRead() throws Exception {
+        final Context ctx = new Context();
+        final Map<Integer, SwInterfaceDetails> cachedInterfaceDump = new HashMap<>();
+        final int ifId = 1;
+        final int bdId = 1;
+        final String bdName = "bd001";
+        final String ifName = "eth0.sub0";
+        interfaceContext.addName(ifId, ifName);
+        bridgeDomainContext.addName(bdId, bdName);
+
+        final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails();
+        ifaceDetails.subId = ifId;
+        cachedInterfaceDump.put(ifId, ifaceDetails);
+        ctx.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
+
+        whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)));
+
+        final L2Builder builder = mock(L2Builder.class);
+        getCustomizer().readCurrentAttributes(getL2Id(ifName), builder, ctx);
+
+        verify(builder).setInterconnection(generateInterconnection(ifId, bdName));
+    }
+}
\ No newline at end of file