summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2016-07-13 08:48:14 +0200
committerMarek Gradzki <mgradzki@cisco.com>2016-07-14 10:53:40 +0200
commite5ddeadb5b19272c11b08bc8378e08551393c0d8 (patch)
tree3d4c758e091fcf9212eb0f1238eff3bee3dae51b /v3po/v3po2vpp
parent9e6835b79cda20c3614c6e76c64099ab64be2831 (diff)
HONEYCOMB-49: VPP classifier model. Translation layer implementation
Change-Id: I7d91f29f621fbb7ede9b3dd5d49a9b5c3ba58565 Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp')
-rw-r--r--v3po/v3po2vpp/src/main/config/default-config.xml51
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java21
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java202
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java157
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java147
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java158
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java41
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModule.java59
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModuleFactory.java13
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java77
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModuleFactory.java13
-rw-r--r--v3po/v3po2vpp/src/main/yang/v3po2vpp.yang58
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java136
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java218
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java153
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java231
16 files changed, 1729 insertions, 6 deletions
diff --git a/v3po/v3po2vpp/src/main/config/default-config.xml b/v3po/v3po2vpp/src/main/config/default-config.xml
index 6b487a13f..09c6c54df 100644
--- a/v3po/v3po2vpp/src/main/config/default-config.xml
+++ b/v3po/v3po2vpp/src/main/config/default-config.xml
@@ -42,6 +42,11 @@
<name>bridge-domain-context</name>
<artificial-name-prefix>bridge-domain-</artificial-name-prefix>
</module>
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:util">prefix:naming-context-impl</type>
+ <name>classify-table-context</name>
+ <artificial-name-prefix>classify-table-</artificial-name-prefix>
+ </module>
<module>
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:v3po2vpp">prefix:vpp-state-honeycomb-reader</type>
@@ -111,6 +116,18 @@
<name>bridge-domain-context</name>
</bridge-domain-context-ifc-state>
</module>
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:v3po2vpp">prefix:vpp-classifier-honeycomb-reader</type>
+ <name>vpp-classifier-honeycomb-reader</name>
+ <vpp-jvpp>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg">prefix:vpp-jvpp</type>
+ <name>vpp-jvpp</name>
+ </vpp-jvpp>
+ <classify-table-context>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:util">prefix:naming-context</type>
+ <name>classify-table-context</name>
+ </classify-table-context>
+ </module>
<module>
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:v3po2vpp">prefix:vpp-honeycomb-writer</type>
@@ -147,6 +164,19 @@
</module>
<module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:v3po2vpp">prefix:vpp-classifier-honeycomb-writer</type>
+ <name>vpp-classifier-honeycomb-writer</name>
+ <vpp-jvpp>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg">prefix:vpp-jvpp</type>
+ <name>vpp-jvpp</name>
+ </vpp-jvpp>
+ <classify-table-context>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:util">prefix:naming-context</type>
+ <name>classify-table-context</name>
+ </classify-table-context>
+ </module>
+
+ <module>
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:delegating-reader-registry</type>
<name>read-registry</name>
<root-readers>
@@ -157,6 +187,10 @@
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader</type>
<name>interfaces-state-honeycomb-reader</name>
</root-readers>
+ <root-readers>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader</type>
+ <name>vpp-classifier-honeycomb-reader</name>
+ </root-readers>
</module>
<module>
@@ -170,6 +204,10 @@
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-factory</type>
<name>interfaces-honeycomb-writer</name>
</writer-factory>
+ <writer-factory>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-factory</type>
+ <name>vpp-classifier-honeycomb-writer</name>
+ </writer-factory>
</module>
</modules>
@@ -185,6 +223,10 @@
<name>interfaces-state-honeycomb-reader</name>
<provider>/modules/module[type='interfaces-state-honeycomb-reader'][name='interfaces-state-honeycomb-reader']</provider>
</instance>
+ <instance>
+ <name>vpp-classifier-honeycomb-reader</name>
+ <provider>/modules/module[type='vpp-classifier-honeycomb-reader'][name='vpp-classifier-honeycomb-reader']</provider>
+ </instance>
</service>
<service>
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:honeycomb-notification-producer</type>
@@ -203,6 +245,10 @@
<name>bridge-domain-context</name>
<provider>/modules/module[type='naming-context-impl'][name='bridge-domain-context']</provider>
</instance>
+ <instance>
+ <name>classify-table-context</name>
+ <provider>/modules/module[type='naming-context-impl'][name='classify-table-context']</provider>
+ </instance>
</service>
<service>
<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-factory</type>
@@ -216,6 +262,11 @@
<provider>/modules/module[type='interfaces-honeycomb-writer'][name='interfaces-honeycomb-writer']
</provider>
</instance>
+ <instance>
+ <name>vpp-classifier-honeycomb-writer</name>
+ <provider>/modules/module[type='vpp-classifier-honeycomb-writer'][name='vpp-classifier-honeycomb-writer']
+ </provider>
+ </instance>
</service>
</services>
</data>
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
index 7b4b2d01e..f902f8985 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
@@ -117,21 +117,30 @@ public final class InterfaceUtils {
return vppPhysAddrToYang(vppPhysAddress, 0);
}
- public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, int startIndex) {
+ public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) {
Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes");
final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH;
checkArgument(endIndex <= vppPhysAddress.length,
"Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length,
startIndex, endIndex);
- StringBuilder physAddr = new StringBuilder();
+ return printHexBinary(vppPhysAddress, startIndex, endIndex);
+ }
+
+ public static String printHexBinary(@Nonnull final byte[] bytes) {
+ Objects.requireNonNull(bytes, "bytes array should not be null");
+ return printHexBinary(bytes, 0, bytes.length);
+ }
+
+ private static String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
+ StringBuilder str = new StringBuilder();
- appendHexByte(physAddr, vppPhysAddress[startIndex]);
+ appendHexByte(str, bytes[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
- physAddr.append(":");
- appendHexByte(physAddr, vppPhysAddress[i]);
+ str.append(":");
+ appendHexByte(str, bytes[i]);
}
- return physAddr.toString();
+ return str.toString();
}
/**
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java
new file mode 100644
index 000000000..002fc62fd
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java
@@ -0,0 +1,202 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
+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.util.TranslateUtils;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifySessionDetails;
+import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump;
+import org.openvpp.jvpp.dto.ClassifySessionDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify session read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table verbose} command.
+ */
+public class ClassifySessionReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifySession, ClassifySessionKey, ClassifySessionBuilder>, VppNodeReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
+ static final String CACHE_KEY = ClassifySessionReader.class.getName();
+
+ private final NamingContext classifyTableContext;
+
+ public ClassifySessionReader(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifySession> readData) {
+ ((ClassifyTableBuilder) builder).setClassifySession(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifySession> id) {
+ return new ClassifySessionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify session: {}", id);
+
+ final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class);
+ checkArgument(key != null, "could not find ClassifySession key in {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", ""));
+ final Optional<ClassifySessionDetails> classifySession =
+ findClassifySessionDetailsByMatch(classifySessionDump, match);
+
+ if (classifySession.isPresent()) {
+ final ClassifySessionDetails detail = classifySession.get();
+ builder.setHitNextIndex(readVppNode(detail.hitNextIndex, LOG));
+ if (detail.opaqueIndex != ~0) {
+ // value is specified:
+ builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex));
+ }
+ builder.setAdvance(detail.advance);
+ builder.setMatch(key.getMatch());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build());
+ }
+ }
+ }
+
+ private OpaqueIndex readOpaqueIndex(final int opaqueIndex) {
+ // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
+ // FIXME: the approach might fail if the opaqueIndex contains small value that collides
+ // with some of the adjacent nodes
+ final VppNode node = readVppNode(opaqueIndex, LOG);
+ if (node != null) {
+ return new OpaqueIndex(node);
+ } else {
+ return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
+ }
+ }
+
+ @Nullable
+ private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id);
+
+ final String cacheKey = CACHE_KEY + tableKey;
+
+ ClassifySessionDetailsReplyDump classifySessionDump =
+ (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey);
+ if (classifySessionDump != null) {
+ LOG.debug("Classify sessions is present in cache: {}", cacheKey);
+ return classifySessionDump;
+ }
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsIndex(tableName, ctx.getMappingContext()),
+ "Reading classify sessions for table {}, but table index could not be found in the classify table context",
+ tableName);
+ final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+ LOG.debug("Dumping classify sessions for classify table id={}", tableId);
+
+ try {
+ final ClassifySessionDump dumpRequest = new ClassifySessionDump();
+ dumpRequest.tableId = tableId;
+ classifySessionDump = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id);
+
+ // update the cache:
+ ctx.getModificationCache().put(cacheKey, classifySessionDump);
+ return classifySessionDump;
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ private static Optional<ClassifySessionDetails> findClassifySessionDetailsByMatch(
+ @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) {
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ final List<ClassifySessionDetails> details = classifySessionDump.classifySessionDetails;
+ final List<ClassifySessionDetails> filteredSessions = details.stream()
+ .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList());
+ if (filteredSessions.isEmpty()) {
+ return Optional.absent();
+ } else if (filteredSessions.size() == 1) {
+ return Optional.of(filteredSessions.get(0));
+ } else {
+ throw new IllegalStateException(String.format(
+ "Found %d classify sessions witch given match. Single session expected.",
+ filteredSessions.size()));
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifySessionKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify sessions: {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ return classifySessionDump.classifySessionDetails.stream()
+ .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match))))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java
new file mode 100644
index 000000000..08989ce7d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java
@@ -0,0 +1,157 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+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.util.TranslateUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelSession;
+import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify session create/delete.<br> Sends {@code classify_add_del_session} message
+ * to VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifySessionWriter extends FutureJVppCustomizer
+ implements ListWriterCustomizer<ClassifySession, ClassifySessionKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifySessionWriter(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Nonnull
+ @Override
+ public Optional<List<ClassifySession>> extract(@Nonnull final InstanceIdentifier<ClassifySession> currentId,
+ @Nonnull final DataObject parentData) {
+ return Optional.fromNullable(((ClassifyTable) parentData).getClassifySession());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter);
+ try {
+ classifyAddDelSession(true, id, dataAfter, writeContext);
+ LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify session update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore);
+ try {
+ classifyAddDelSession(false, id, dataBefore, writeContext);
+ LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession classifySession,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find classify table key in {}", id);
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+ "Could not find classify table index for {} in the classify table context", tableName);
+ final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+
+ final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
+ .classifyAddDelSession(
+ getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession));
+
+ TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifySession classifySession) {
+ ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory:
+ // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ request.hitNextIndex = classifySession.getHitNextIndex().getPacketHandlingAction().getIntValue();
+
+ if (classifySession.getOpaqueIndex() != null) {
+ request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex());
+ } else {
+ request.opaqueIndex = ~0; // value not specified
+ }
+
+ // default 0:
+ request.advance = classifySession.getAdvance();
+
+ request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", ""));
+ return request;
+ }
+
+ private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) {
+ if (opaqueIndex.getUint32() != null) {
+ return opaqueIndex.getUint32().intValue();
+ } else {
+ // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue();
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java
new file mode 100644
index 000000000..7f877ca49
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java
@@ -0,0 +1,147 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
+
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
+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.util.TranslateUtils;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyTableIds;
+import org.openvpp.jvpp.dto.ClassifyTableIdsReply;
+import org.openvpp.jvpp.dto.ClassifyTableInfo;
+import org.openvpp.jvpp.dto.ClassifyTableInfoReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify table read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table} command.
+ */
+public class ClassifyTableReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifyTableReader(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifyTable> readData) {
+ ((VppClassifierBuilder) builder).setClassifyTable(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifyTable> id) {
+ return new ClassifyTableBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify table: {}", id);
+
+ final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(key != null, "could not find ClassifyTable key in {}", id);
+ final ClassifyTableInfo request = new ClassifyTableInfo();
+
+ final String tableName = key.getName();
+ if (!classifyTableContext.containsIndex(tableName, ctx.getMappingContext())) {
+ LOG.debug("Could not find classify table {} in the naming context", tableName);
+ return;
+ }
+ request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+
+ try {
+ final ClassifyTableInfoReply reply =
+ TranslateUtils.getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id);
+
+ // mandatory values:
+ builder.setName(tableName);
+ builder.setKey(key);
+ builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets));
+ builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors));
+
+
+ builder.setMissNextIndex(readVppNode(reply.missNextIndex, LOG));
+ builder.setMask(new HexString(printHexBinary(reply.mask)));
+ builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions));
+
+ if (reply.nextTableIndex != ~0) {
+ // next table index is present:
+ builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext()));
+ }
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build());
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifyTableKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify tables: {}", id);
+ try {
+ final ClassifyTableIdsReply classifyTableIdsReply = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id);
+ if (classifyTableIdsReply.ids != null) {
+ return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> {
+ final String tableName = classifyTableContext.getName(i, context.getMappingContext());
+ LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i);
+ return new ClassifyTableKey(tableName);
+ }).collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java
new file mode 100644
index 000000000..4f59ffe8e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java
@@ -0,0 +1,158 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+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.util.TranslateUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelTable;
+import org.openvpp.jvpp.dto.ClassifyAddDelTableReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
+ * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifyTableWriter extends FutureJVppCustomizer
+ implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Nonnull
+ @Override
+ public Optional<List<ClassifyTable>> extract(@Nonnull final InstanceIdentifier<ClassifyTable> currentId,
+ @Nonnull final DataObject parentData) {
+ return Optional.fromNullable(((VppClassifier) parentData).getClassifyTable());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter);
+ try {
+ final int newTableIndex =
+ classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext());
+
+ // Add classify table name <-> vpp index mapping to the naming context:
+ classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.warn("ClassifyTable update is not supported, ignoring configuration {}", dataAfter);
+ // TODO if only leaves were updated (but not child/aug nodes), we should throw exception to deny config change
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
+ final String tableName = dataBefore.getName();
+ checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+ "Removing classify table {}, but index could not be found in the classify table context", tableName);
+
+ final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+ try {
+ classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
+
+ // Remove deleted interface from interface context:
+ classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
+ throws VppBaseCallException, WriteTimeoutException {
+ final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
+ getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx));
+
+ final ClassifyAddDelTableReply reply =
+ TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ return reply.newTableIndex;
+
+ }
+
+ private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifyTable table,
+ @Nonnull final MappingContext ctx) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory, all u32 values are permitted:
+ request.nbuckets = table.getNbuckets().intValue();
+ request.memorySize = table.getMemorySize().intValue();
+ request.skipNVectors = table.getSkipNVectors().intValue();
+
+ // mandatory
+ // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ request.missNextIndex = table.getMissNextIndex().getPacketHandlingAction().getIntValue();
+
+ final String nextTable = table.getNextTable();
+ if (nextTable != null) {
+ request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx);
+ } else {
+ request.nextTableIndex = ~0; // value not specified
+ }
+ request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", ""));
+ checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16.");
+ request.matchNVectors = request.mask.length / 16;
+
+ return request;
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java
new file mode 100644
index 000000000..aa8b4f9f3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java
@@ -0,0 +1,41 @@
+/*
+ * 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.vppclassifier;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.slf4j.Logger;
+
+interface VppNodeReader {
+
+ /**
+ * Converts vpp node index to YANG representation of vpp node.
+ *
+ * @param nodeIndex index of vpp node treated as signed integer.
+ * @return vpp node representation
+ */
+ default VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) {
+ final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex);
+ if (action == null) {
+ // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex);
+ return null;
+ }
+ return new VppNode(action);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModule.java
new file mode 100644
index 000000000..55e86f8bb
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModule.java
@@ -0,0 +1,59 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+
+import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader;
+import io.fd.honeycomb.v3po.translate.impl.read.CompositeRootReader;
+import io.fd.honeycomb.v3po.translate.read.ChildReader;
+import io.fd.honeycomb.v3po.translate.util.read.CloseableReader;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveRootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifySessionReader;
+import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifyTableReader;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+
+public class VppClassifierHoneycombReaderModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppClassifierHoneycombReaderModule {
+
+ public VppClassifierHoneycombReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public VppClassifierHoneycombReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.VppClassifierHoneycombReaderModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ final CompositeListReader<ClassifySession, ClassifySessionKey, ClassifySessionBuilder> classifySessionReader =
+ new CompositeListReader<>(ClassifySession.class,
+ new ClassifySessionReader(getVppJvppDependency(), getClassifyTableContextDependency()));
+
+ final List<ChildReader<? extends ChildOf<ClassifyTable>>> classifyTableChildReaders = new ArrayList<>();
+ classifyTableChildReaders.add((ChildReader)classifySessionReader);
+ final CompositeListReader<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder> classifyTableReader =
+ new CompositeListReader<>(
+ ClassifyTable.class,
+ classifyTableChildReaders,
+ new ClassifyTableReader(getVppJvppDependency(), getClassifyTableContextDependency()));
+
+ final List<ChildReader<? extends ChildOf<VppClassifier>>> vppClassifierChildReaders = new ArrayList<>();
+ vppClassifierChildReaders.add(classifyTableReader);
+ return new CloseableReader<>(new CompositeRootReader<>(
+ VppClassifier.class,
+ vppClassifierChildReaders,
+ new ReflexiveRootReaderCustomizer<>(VppClassifierBuilder.class)));
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModuleFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModuleFactory.java
new file mode 100644
index 000000000..34212f5e8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombReaderModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po2vpp yang module local name: vpp-classifier-honeycomb-reader
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Jun 03 14:05:48 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+public class VppClassifierHoneycombReaderModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppClassifierHoneycombReaderModuleFactory {
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java
new file mode 100644
index 000000000..52e99b295
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java
@@ -0,0 +1,77 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+
+import io.fd.honeycomb.v3po.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifySessionWriter;
+import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifyTableWriter;
+import io.fd.honeycomb.v3po.translate.write.ModifiableWriterRegistry;
+import io.fd.honeycomb.v3po.translate.write.WriterFactory;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public class VppClassifierHoneycombWriterModule extends
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppClassifierHoneycombWriterModule {
+
+
+ public static final InstanceIdentifier<ClassifyTable> CLASSIFY_TABLE_ID =
+ InstanceIdentifier.create(VppClassifier.class).child(ClassifyTable.class);
+
+ public static final InstanceIdentifier<ClassifySession> CLASSIFY_SESSION_ID =
+ CLASSIFY_TABLE_ID.child(ClassifySession.class);
+
+
+ public VppClassifierHoneycombWriterModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public VppClassifierHoneycombWriterModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.VppClassifierHoneycombWriterModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new VppClassifierHoneycombWriterFactory(
+ getVppJvppDependency(),
+ getClassifyTableContextDependency());
+ }
+
+ private static final class VppClassifierHoneycombWriterFactory implements WriterFactory, AutoCloseable {
+ private final FutureJVpp jvpp;
+ private final NamingContext classifyTableContext;
+
+ public VppClassifierHoneycombWriterFactory(@Nonnull final FutureJVpp jvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ this.jvpp = jvpp;
+ this.classifyTableContext = classifyTableContext;
+ }
+
+ @Override
+ public void close() throws Exception {
+ // unregister is not supported in ModifiableWriterRegistry (not really needed though)
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistry registry) {
+
+ registry.addWriter(
+ new GenericListWriter<>(CLASSIFY_TABLE_ID, new ClassifyTableWriter(jvpp, classifyTableContext)));
+
+ registry.addWriterAfter(
+ new GenericListWriter<>(CLASSIFY_SESSION_ID, new ClassifySessionWriter(jvpp, classifyTableContext)),
+ CLASSIFY_TABLE_ID);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModuleFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModuleFactory.java
new file mode 100644
index 000000000..c4ff69061
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po2vpp yang module local name: vpp-classifier-honeycomb-writer
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Jun 03 14:05:48 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+public class VppClassifierHoneycombWriterModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppClassifierHoneycombWriterModuleFactory {
+
+}
diff --git a/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang b/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang
index 8a5527248..0c215707d 100644
--- a/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang
+++ b/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang
@@ -146,6 +146,35 @@ module v3po2vpp {
}
}
+ identity vpp-classifier-honeycomb-reader {
+ base config:module-type;
+ config:provided-service tapi:honeycomb-reader;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case vpp-classifier-honeycomb-reader {
+ when "/config:modules/config:module/config:type = 'vpp-classifier-honeycomb-reader'";
+
+ container vpp-jvpp {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity vjvppc:vpp-jvpp;
+ }
+ }
+ }
+
+ container classify-table-context {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity vpp-u:naming-context;
+ }
+ }
+ }
+ }
+ }
+
identity vpp-honeycomb-writer {
base config:module-type;
@@ -224,6 +253,35 @@ module v3po2vpp {
}
}
+ identity vpp-classifier-honeycomb-writer {
+ base config:module-type;
+ config:provided-service tapi:honeycomb-writer-factory;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case vpp-classifier-honeycomb-writer {
+ when "/config:modules/config:module/config:type = 'vpp-classifier-honeycomb-writer'";
+
+ container vpp-jvpp {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity vjvppc:vpp-jvpp;
+ }
+ }
+ }
+
+ container classify-table-context {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity vpp-u:naming-context;
+ }
+ }
+ }
+ }
+ }
+
identity vpp-cfg-initializer {
base config:module-type;
config:provided-service init:cfg-initializer;
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java
new file mode 100644
index 000000000..ce0d3f62e
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.vppclassifier;
+
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.ClassifySessionDetails;
+import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump;
+import org.openvpp.jvpp.dto.ClassifySessionDump;
+
+public class ClassifySessionReaderTest extends
+ ListReaderCustomizerTest<ClassifySession, ClassifySessionKey, ClassifySessionBuilder> {
+
+ private static final String MATCH_1 = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00";
+ private static final String MATCH_2 = "00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00";
+
+ private static final int TABLE_INDEX = 1;
+ private static final String TABLE_NAME = "table1";
+
+ private NamingContext classifyTableContext;
+
+ public ClassifySessionReaderTest() {
+ super(ClassifySession.class);
+ }
+
+ @Override
+ public void setUpBefore() {
+ classifyTableContext = new NamingContext("classifyTableContext", "test-instance");
+
+ final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
+ doReturn(ifcMapping).when(mappingContext).read(any());
+ }
+
+ @Override
+ protected RootReaderCustomizer<ClassifySession, ClassifySessionBuilder> initCustomizer() {
+ return new ClassifySessionReader(api, classifyTableContext);
+ }
+
+ private static InstanceIdentifier<ClassifySession> getClassifySessionId(final String tableName,
+ final String match) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(ClassifyTable.class, new ClassifyTableKey(tableName))
+ .child(ClassifySession.class, new ClassifySessionKey(new HexString(match)));
+ }
+
+ @Test
+ public void testMerge() {
+ final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class);
+ final List<ClassifySession> value = mock(List.class);
+ getCustomizer().merge(builder, value);
+ verify(builder).setClassifySession(value);
+ }
+
+ @Test
+ public void testReadWithCache() throws ReadFailedException {
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, MATCH_1);
+ final ClassifySessionBuilder builder = mock(ClassifySessionBuilder.class);
+ final ModificationCache cache = new ModificationCache();
+ final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump();
+ final ClassifySessionDetails details = new ClassifySessionDetails();
+ details.match =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00};
+ dump.classifySessionDetails = Collections.singletonList(details);
+ cache.put(ClassifySessionReader.CACHE_KEY + id.firstKeyOf(ClassifyTable.class), dump);
+ when(ctx.getModificationCache()).thenReturn(cache);
+
+ getCustomizer().readCurrentAttributes(id, builder, ctx);
+ }
+
+ @Test
+ public void testGetAllIds() throws ReadFailedException {
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, MATCH_1);
+ final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump();
+ final ClassifySessionDetails details1 = new ClassifySessionDetails();
+ details1.match =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00};
+ final ClassifySessionDetails details2 = new ClassifySessionDetails();
+ details2.match =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x07, 0x00, 0x00, 0x00, 0x00};
+ dump.classifySessionDetails = Arrays.asList(details1, details2);
+
+ final CompletableFuture<ClassifySessionDetailsReplyDump> replyFuture = new CompletableFuture<>();
+ replyFuture.complete(dump);
+ doReturn(replyFuture).when(api).classifySessionDump(any(ClassifySessionDump.class));
+
+ final List<ClassifySessionKey> allIds = getCustomizer().getAllIds(id, ctx);
+ assertEquals(2, allIds.size());
+ assertEquals(MATCH_1, allIds.get(0).getMatch().getValue());
+ assertEquals(MATCH_2, allIds.get(1).getMatch().getValue());
+ }
+
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java
new file mode 100644
index 000000000..04a766fa3
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.vppclassifier;
+
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelSession;
+import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply;
+import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public class ClassifySessionWriterTest {
+
+ private static final int TABLE_INDEX = 123;
+ private static final String TABLE_NAME = "table123";
+
+ @Mock
+ private FutureJVpp api;
+ @Mock
+ private WriteContext writeContext;
+ @Mock
+ private MappingContext mappingContext;
+
+ private NamingContext classifyTableContext;
+ private ClassifySessionWriter customizer;
+ private static final int SESSION_INDEX = 456;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance");
+ doReturn(mappingContext).when(writeContext).getMappingContext();
+ customizer = new ClassifySessionWriter(api, classifyTableContext);
+
+ final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
+ doReturn(ifcMapping).when(mappingContext).read(any());
+ }
+
+ private static ClassifySession generateClassifySession(final long opaqueIndex, final String match) {
+ final ClassifySessionBuilder builder = new ClassifySessionBuilder();
+ builder.setOpaqueIndex(new OpaqueIndex(opaqueIndex));
+ builder.setHitNextIndex(new VppNode(PacketHandlingAction.Deny));
+ builder.setAdvance(123);
+ builder.setMatch(new HexString(match));
+ return builder.build();
+ }
+
+ private static InstanceIdentifier<ClassifySession> getClassifySessionId(final String tableName,
+ final String match) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(ClassifyTable.class, new ClassifyTableKey(tableName))
+ .child(ClassifySession.class, new ClassifySessionKey(new HexString(match)));
+ }
+
+ private void whenClassifyAddDelSessionThenSuccess() throws ExecutionException, InterruptedException {
+ final CompletableFuture<ClassifyAddDelSessionReply> replyFuture = new CompletableFuture<>();
+ replyFuture.complete(new ClassifyAddDelSessionReply());
+ doReturn(replyFuture).when(api).classifyAddDelSession(any(ClassifyAddDelSession.class));
+ }
+
+ private void whenClassifyAddDelSessionThenFailure() throws ExecutionException, InterruptedException {
+ doReturn(TestHelperUtils.<L2InterfaceVlanTagRewriteReply>createFutureException()).when(api)
+ .classifyAddDelSession(any(ClassifyAddDelSession.class));
+ }
+
+ private void verifyClassifyAddDelSessionWasInvoked(final ClassifyAddDelSession expected) {
+ ArgumentCaptor<ClassifyAddDelSession> argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class);
+ verify(api).classifyAddDelSession(argumentCaptor.capture());
+ final ClassifyAddDelSession actual = argumentCaptor.getValue();
+ assertEquals(expected.opaqueIndex, actual.opaqueIndex);
+ assertEquals(expected.isAdd, actual.isAdd);
+ assertEquals(expected.tableIndex, actual.tableIndex);
+ assertEquals(expected.hitNextIndex, actual.hitNextIndex);
+ assertArrayEquals(expected.match, actual.match);
+ assertEquals(expected.advance, actual.advance);
+ }
+
+ private void verifyClassifyAddDelSessionDeleteWasInvoked(final ClassifyAddDelSession expected) {
+ ArgumentCaptor<ClassifyAddDelSession> argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class);
+ verify(api).classifyAddDelSession(argumentCaptor.capture());
+ final ClassifyAddDelSession actual = argumentCaptor.getValue();
+ assertEquals(expected.opaqueIndex, actual.opaqueIndex);
+ assertEquals(expected.isAdd, actual.isAdd);
+ assertEquals(expected.tableIndex, actual.tableIndex);
+ }
+
+ private static ClassifyAddDelSession generateClassifyAddDelSession(final byte isAdd, final int tableIndex,
+ final int sessionIndex) {
+ final ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = isAdd;
+ request.tableIndex = tableIndex;
+ request.opaqueIndex = sessionIndex;
+ request.hitNextIndex = 0;
+ request.advance = 123;
+ request.match =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00};
+ return request;
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00";
+ final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match);
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, match);
+
+ whenClassifyAddDelSessionThenSuccess();
+
+ customizer.writeCurrentAttributes(id, classifySession, writeContext);
+
+ verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX));
+ }
+
+ @Test
+ public void testCreateFailed() throws Exception {
+ final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00";
+ final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match);
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, match);
+
+ whenClassifyAddDelSessionThenFailure();
+
+ try {
+ customizer.writeCurrentAttributes(id, classifySession, writeContext);
+ } catch (WriteFailedException.CreateFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX));
+ return;
+ }
+ fail("WriteFailedException.CreateFailedException was expected");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testUpdate() throws Exception {
+ customizer.updateCurrentAttributes(null, null, null, writeContext);
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00";
+ final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match);
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, match);
+
+ whenClassifyAddDelSessionThenSuccess();
+
+ customizer.deleteCurrentAttributes(id, classifySession, writeContext);
+
+ verifyClassifyAddDelSessionDeleteWasInvoked(
+ generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX));
+ }
+
+ @Test
+ public void testDeleteFailed() throws Exception {
+ final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00";
+ final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match);
+ final InstanceIdentifier<ClassifySession> id = getClassifySessionId(TABLE_NAME, match);
+
+ whenClassifyAddDelSessionThenFailure();
+
+ try {
+ customizer.deleteCurrentAttributes(id, classifySession, writeContext);
+ } catch (WriteFailedException.DeleteFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyClassifyAddDelSessionDeleteWasInvoked(
+ generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX));
+ return;
+ }
+ fail("WriteFailedException.DeleteFailedException was expected");
+
+ customizer.deleteCurrentAttributes(id, classifySession, writeContext);
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java
new file mode 100644
index 000000000..14d6c5544
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.vppclassifier;
+
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.openvpp.jvpp.dto.ClassifyTableIds;
+import org.openvpp.jvpp.dto.ClassifyTableIdsReply;
+import org.openvpp.jvpp.dto.ClassifyTableInfo;
+import org.openvpp.jvpp.dto.ClassifyTableInfoReply;
+
+public class ClassifyTableReaderTest extends
+ ListReaderCustomizerTest<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder> {
+
+ private static final int TABLE_INDEX_1 = 1;
+ private static final String TABLE_NAME_1 = "table1";
+ private static final int TABLE_INDEX_2 = 2;
+ private static final String TABLE_NAME_2 = "table2";
+
+ private NamingContext classifyTableContext;
+
+ public ClassifyTableReaderTest() {
+ super(ClassifyTable.class);
+ }
+
+ @Override
+ public void setUpBefore() {
+ classifyTableContext = new NamingContext("classifyTableContext", "test-instance");
+
+ final KeyedInstanceIdentifier<Mapping, MappingKey> t0Id = getMappingIid(TABLE_NAME_1, "test-instance");
+ final KeyedInstanceIdentifier<Mapping, MappingKey> t1Id = getMappingIid(TABLE_NAME_2, "test-instance");
+ final Optional<Mapping> t0 = getMapping(TABLE_NAME_1, TABLE_INDEX_1);
+ final Optional<Mapping> t1 = getMapping(TABLE_NAME_2, TABLE_INDEX_2);
+ final List<Mapping> allMappings = Lists.newArrayList(t0.get(), t1.get());
+ final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+ doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(t0Id.firstIdentifierOf(Mappings.class));
+ doReturn(t0).when(mappingContext).read(t0Id);
+ doReturn(t1).when(mappingContext).read(t1Id);
+ }
+
+ @Override
+ protected RootReaderCustomizer<ClassifyTable, ClassifyTableBuilder> initCustomizer() {
+ return new ClassifyTableReader(api, classifyTableContext);
+ }
+
+ private static InstanceIdentifier<ClassifyTable> getClassifyTableId(final String name) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(ClassifyTable.class, new ClassifyTableKey(name));
+ }
+
+ private static ClassifyTableInfoReply generateClassifyTableInfoReply() {
+ final ClassifyTableInfoReply reply = new ClassifyTableInfoReply();
+ reply.tableId = TABLE_INDEX_1;
+ reply.nbuckets = 2;
+ reply.skipNVectors = 0;
+ reply.matchNVectors = 1;
+ reply.nextTableIndex = ~0;
+ reply.missNextIndex = ~0;
+ reply.mask =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00};
+ return reply;
+ }
+
+ private void verifyClasifyTableRead(final ClassifyTableBuilder builder) {
+ verify(builder).setName(TABLE_NAME_1);
+ verify(builder).setNbuckets(2L);
+ verify(builder, times(0)).setNextTable(anyString());
+ verify(builder).setMissNextIndex(new VppNode(PacketHandlingAction.Permit));
+ verify(builder).setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"));
+ verify(builder).setActiveSessions(0L);
+ }
+
+ @Test
+ public void testMerge() {
+ final VppClassifierBuilder builder = mock(VppClassifierBuilder.class);
+ final List<ClassifyTable> value = mock(List.class);
+ getCustomizer().merge(builder, value);
+ verify(builder).setClassifyTable(value);
+ }
+
+ @Test
+ public void testRead() throws ReadFailedException {
+ final CompletableFuture<ClassifyTableInfoReply> replyFuture = new CompletableFuture<>();
+ replyFuture.complete(generateClassifyTableInfoReply());
+ doReturn(replyFuture).when(api).classifyTableInfo(any(ClassifyTableInfo.class));
+
+ final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class);
+ getCustomizer().readCurrentAttributes(getClassifyTableId(TABLE_NAME_1), builder, ctx);
+
+ verifyClasifyTableRead(builder);
+ }
+
+ @Test
+ public void testGetAllIds() throws ReadFailedException {
+ final CompletableFuture<ClassifyTableIdsReply> replyFuture = new CompletableFuture<>();
+ final ClassifyTableIdsReply reply = new ClassifyTableIdsReply();
+ reply.ids = new int[] {1, 2};
+ replyFuture.complete(reply);
+ doReturn(replyFuture).when(api).classifyTableIds(any(ClassifyTableIds.class));
+
+ final List<ClassifyTableKey> allIds = getCustomizer().getAllIds(getClassifyTableId(TABLE_NAME_1), ctx);
+
+ assertEquals(reply.ids.length, allIds.size());
+ assertEquals(TABLE_NAME_1, allIds.get(0).getName());
+ assertEquals(TABLE_NAME_2, allIds.get(1).getName());
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java
new file mode 100644
index 000000000..683bd69c3
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.vppclassifier;
+
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelTable;
+import org.openvpp.jvpp.dto.ClassifyAddDelTableReply;
+import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public class ClassifyTableWriterTest {
+
+ private static final int TABLE_INDEX = 123;
+ private static final String TABLE_NAME = "table123";
+
+ @Mock
+ private FutureJVpp api;
+ @Mock
+ private WriteContext writeContext;
+ @Mock
+ private MappingContext mappingContext;
+
+ private NamingContext classifyTableContext;
+ private ClassifyTableWriter customizer;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance");
+ doReturn(mappingContext).when(writeContext).getMappingContext();
+ customizer = new ClassifyTableWriter(api, classifyTableContext);
+ }
+
+ private static ClassifyTable generateClassifyTable(final String name) {
+ final ClassifyTableBuilder builder = new ClassifyTableBuilder();
+ builder.setName(name);
+ builder.setKey(new ClassifyTableKey(name));
+ builder.setSkipNVectors(0L);
+ builder.setNbuckets(2L);
+ builder.setMemorySize(2L << 20);
+ builder.setMissNextIndex(new VppNode(PacketHandlingAction.Permit));
+ builder.setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"));
+ return builder.build();
+ }
+
+ private static InstanceIdentifier<ClassifyTable> getClassifyTableId(final String name) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(ClassifyTable.class, new ClassifyTableKey(name));
+ }
+
+ private void whenClassifyAddDelTableThenSuccess() throws ExecutionException, InterruptedException {
+ final CompletableFuture<ClassifyAddDelTableReply> replyFuture = new CompletableFuture<>();
+ final ClassifyAddDelTableReply reply = new ClassifyAddDelTableReply();
+ reply.newTableIndex = TABLE_INDEX;
+ replyFuture.complete(reply);
+ doReturn(replyFuture).when(api).classifyAddDelTable(any(ClassifyAddDelTable.class));
+ }
+
+ private void whenClassifyAddDelTableThenFailure() throws ExecutionException, InterruptedException {
+ doReturn(TestHelperUtils.<L2InterfaceVlanTagRewriteReply>createFutureException()).when(api)
+ .classifyAddDelTable(any(ClassifyAddDelTable.class));
+ }
+
+ private void verifyClassifyAddDelTableAddWasInvoked(final ClassifyAddDelTable expected) {
+ ArgumentCaptor<ClassifyAddDelTable> argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class);
+ verify(api).classifyAddDelTable(argumentCaptor.capture());
+ final ClassifyAddDelTable actual = argumentCaptor.getValue();
+ assertEquals(expected.isAdd, actual.isAdd);
+ assertEquals(~0, actual.tableIndex);
+ assertEquals(expected.nbuckets, actual.nbuckets);
+ assertEquals(expected.memorySize, actual.memorySize);
+ assertEquals(expected.skipNVectors, actual.skipNVectors);
+ assertEquals(expected.matchNVectors, actual.matchNVectors);
+ assertEquals(expected.nextTableIndex, actual.nextTableIndex);
+ assertEquals(expected.missNextIndex, actual.missNextIndex);
+ assertArrayEquals(expected.mask, actual.mask);
+ }
+
+ private void verifyClassifyAddDelTableDeleteWasInvoked(final ClassifyAddDelTable expected) {
+ ArgumentCaptor<ClassifyAddDelTable> argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class);
+ verify(api).classifyAddDelTable(argumentCaptor.capture());
+ final ClassifyAddDelTable actual = argumentCaptor.getValue();
+ assertEquals(expected.isAdd, actual.isAdd);
+ assertEquals(expected.tableIndex, actual.tableIndex);
+ }
+
+ private static ClassifyAddDelTable generateClassifyAddDelTable(final byte isAdd, final int tableIndex) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = isAdd;
+ request.tableIndex = tableIndex;
+ request.nbuckets = 2;
+ request.memorySize = 2 << 20;
+ request.skipNVectors = 0;
+ request.matchNVectors = 1;
+ request.nextTableIndex = ~0;
+ request.missNextIndex = ~0;
+ request.mask =
+ new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00};
+ return request;
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
+ final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
+
+ whenClassifyAddDelTableThenSuccess();
+
+ customizer.writeCurrentAttributes(id, classifyTable, writeContext);
+
+ verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX));
+ verify(mappingContext)
+ .put(eq(getMappingIid(TABLE_NAME, "test-instance")), eq(getMapping(TABLE_NAME, TABLE_INDEX).get()));
+ }
+
+ @Test
+ public void testCreateFailed() throws Exception {
+ final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
+ final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
+
+ whenClassifyAddDelTableThenFailure();
+
+ try {
+ customizer.writeCurrentAttributes(id, classifyTable, writeContext);
+ } catch (WriteFailedException.CreateFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX));
+ verify(mappingContext, times(0)).put(
+ eq(getMappingIid(TABLE_NAME, "test-instance")),
+ eq(getMapping(TABLE_NAME, TABLE_INDEX).get()));
+ return;
+ }
+ fail("WriteFailedException.CreateFailedException was expected");
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
+ final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
+
+ final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
+ doReturn(ifcMapping).when(mappingContext).read(any());
+
+ whenClassifyAddDelTableThenSuccess();
+
+ customizer.deleteCurrentAttributes(id, classifyTable, writeContext);
+
+ verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX));
+ }
+
+ @Test
+ public void testDeleteFailed() throws Exception {
+ final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
+ final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
+
+ final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
+ doReturn(ifcMapping).when(mappingContext).read(any());
+
+ whenClassifyAddDelTableThenFailure();
+
+ try {
+ customizer.deleteCurrentAttributes(id, classifyTable, writeContext);
+ } catch (WriteFailedException.DeleteFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX));
+ return;
+ }
+ fail("WriteFailedException.DeleteFailedException was expected");
+
+ customizer.deleteCurrentAttributes(id, classifyTable, writeContext);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ final ClassifyTable classifyTableBefore = generateClassifyTable(TABLE_NAME);
+ final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
+ customizer.updateCurrentAttributes(id, classifyTableBefore, new ClassifyTableBuilder().build(), writeContext);
+
+ verifyZeroInteractions(api);
+ }
+} \ No newline at end of file