HONEYCOMB-310: translation layer for acl plugin 52/4252/6
authorJan Srnicek <[email protected]>
Fri, 16 Dec 2016 12:07:56 +0000 (13:07 +0100)
committerMarek Gradzki <[email protected]>
Tue, 20 Dec 2016 12:59:56 +0000 (13:59 +0100)
Not covered by this patch (moved to subsequent commits):
- postman collection
- distinguish ingress/egress ACLs while reading assigned acls
- proper support for acl tag
- unit tests improvements
- read for acls (not necessarily assigned)
- initializers

Change-Id: I5a198ce1a6e20d0b1d95b4d2d83d0464fb86580c
Signed-off-by: Jan Srnicek <[email protected]>
Signed-off-by: Marek Gradzki <[email protected]>
44 files changed:
acl/acl-impl/asciidoc/Readme.adoc [new file with mode: 0644]
acl/acl-impl/pom.xml [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java [new file with mode: 0644]
acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclModuleTest.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclTestSchemaContext.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequestTest.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequestTest.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducerTest.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizerTest.java [new file with mode: 0644]
acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java [new file with mode: 0644]
acl/acl-impl/src/test/resources/acl/macip/macip-acl.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp-v6.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/acl/standard/standard-acl-tcp.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/acl/standard/standard-acl-udp.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/rules/icmp-rule.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/rules/icmp-v6-rule.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/rules/other-rule.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/rules/tcp-rule.json [new file with mode: 0644]
acl/acl-impl/src/test/resources/rules/udp-rule.json [new file with mode: 0644]
acl/pom.xml
v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceDataTranslator.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java
vpp-integration/minimal-distribution/pom.xml

diff --git a/acl/acl-impl/asciidoc/Readme.adoc b/acl/acl-impl/asciidoc/Readme.adoc
new file mode 100644 (file)
index 0000000..e990bc2
--- /dev/null
@@ -0,0 +1,3 @@
+= acl-impl
+
+Overview of acl-impl
\ No newline at end of file
diff --git a/acl/acl-impl/pom.xml b/acl/acl-impl/pom.xml
new file mode 100644 (file)
index 0000000..7f08ca7
--- /dev/null
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright (c) 2015 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>io.fd.honeycomb.common</groupId>
+        <artifactId>impl-parent</artifactId>
+        <version>1.17.01-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>io.fd.hc2vpp.acl</groupId>
+    <artifactId>acl-impl</artifactId>
+    <version>1.17.01-SNAPSHOT</version>
+
+    <properties>
+        <jvpp.acl.version>1.0-SNAPSHOT</jvpp.acl.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.fd.hc2vpp.acl</groupId>
+            <artifactId>acl-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.vpp</groupId>
+            <artifactId>jvpp-acl</artifactId>
+            <version>${jvpp.acl.version}</version>
+        </dependency>
+
+        <!-- DI -->
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.jmob</groupId>
+            <artifactId>guice.conf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-multibindings</artifactId>
+        </dependency>
+
+        <!-- Infra dependencies -->
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>translate-spi</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>minimal-distribution</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- HC2VPP Dependencies -->
+        <dependency>
+            <groupId>io.fd.hc2vpp.common</groupId>
+            <artifactId>vpp-translate-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Test -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-testlib</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.hc2vpp.common</groupId>
+            <artifactId>vpp-translate-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb.infra</groupId>
+            <artifactId>test-tools</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java
new file mode 100644 (file)
index 0000000..f15119b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.hc2vpp.acl.read.factory.InterfaceAclReaderFactory;
+import io.fd.hc2vpp.acl.write.factory.InterfaceAclWriterFactory;
+import io.fd.hc2vpp.acl.write.factory.VppAclWriterFactory;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import net.jmob.guice.conf.core.ConfigurationModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AclModule extends AbstractModule {
+
+    public static final String STANDARD_ACL_CONTEXT_NAME = "standard-acl-context";
+    public static final String STANDARD_LEARNED_ACL_NAME_PREFIX = "standard-learned-acl-";
+    public static final String MAC_IP_ACL_CONTEXT_NAME = "mac-ip-acl-context";
+    public static final String MAC_IP_LEARNED_ACL_NAME_PREFIX = "mac-ip-acl-context";
+
+    private static final Logger LOG = LoggerFactory.getLogger(AclModule.class);
+
+    private final Class<? extends Provider<FutureJVppAclFacade>> jvppAclProviderClass;
+
+    public AclModule() {
+        this(JVppAclProvider.class);
+    }
+
+    @VisibleForTesting
+    AclModule(@Nonnull final Class<? extends Provider<FutureJVppAclFacade>> jvppAclProviderClass) {
+        this.jvppAclProviderClass = jvppAclProviderClass;
+    }
+
+    @Override
+    protected void configure() {
+        LOG.info("Configuring module Acl");
+        install(ConfigurationModule.create());
+
+        // binds JVpp Acl future facade
+        bind(FutureJVppAclFacade.class).toProvider(jvppAclProviderClass).in(Singleton.class);
+
+        bind(NamingContext.class).annotatedWith(Names.named(STANDARD_ACL_CONTEXT_NAME))
+                .toInstance(new NamingContext(STANDARD_LEARNED_ACL_NAME_PREFIX, STANDARD_ACL_CONTEXT_NAME));
+
+        bind(NamingContext.class).annotatedWith(Names.named(MAC_IP_ACL_CONTEXT_NAME))
+                .toInstance(new NamingContext(MAC_IP_LEARNED_ACL_NAME_PREFIX, MAC_IP_ACL_CONTEXT_NAME));
+
+        final Multibinder<WriterFactory> writerFactoryMultibinder =
+                Multibinder.newSetBinder(binder(), WriterFactory.class);
+        writerFactoryMultibinder.addBinding().to(VppAclWriterFactory.class);
+        writerFactoryMultibinder.addBinding().to(InterfaceAclWriterFactory.class);
+
+        final Multibinder<ReaderFactory> readerFactoryMultibinder =
+                Multibinder.newSetBinder(binder(), ReaderFactory.class);
+        readerFactoryMultibinder.addBinding().to(InterfaceAclReaderFactory.class);
+
+        LOG.info("Module Acl successfully configured");
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java
new file mode 100644 (file)
index 0000000..b3caa0e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl;
+
+import com.google.inject.Inject;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.acl.JVppAclImpl;
+import io.fd.vpp.jvpp.acl.dto.AclPluginGetVersion;
+import io.fd.vpp.jvpp.acl.dto.AclPluginGetVersionReply;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class JVppAclProvider extends ProviderTrait<FutureJVppAclFacade> implements JvppReplyConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JVppAclProvider.class);
+
+    @Inject
+    private JVppRegistry registry;
+
+    private static JVppAclImpl initAclApi() {
+        final JVppAclImpl jvppAcl = new JVppAclImpl();
+        // Free jvpp-acl plugin's resources on shutdown
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                LOG.info("Unloading jvpp-acl plugin");
+                jvppAcl.close();
+                LOG.info("Successfully unloaded jvpp-acl plugin");
+            }
+        });
+        return jvppAcl;
+    }
+
+    @Override
+    protected FutureJVppAclFacade create() {
+        try {
+            return reportVersionAndGet(initAclApi());
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to open VPP management connection", e);
+        } catch (TimeoutException | VppBaseCallException e) {
+            throw new IllegalStateException("Unable to load ACL plugin version", e);
+        }
+    }
+
+    private FutureJVppAclFacade reportVersionAndGet(final JVppAclImpl jvppAcl)
+            throws IOException, TimeoutException, VppBaseCallException {
+        final FutureJVppAclFacade futureFacade = new FutureJVppAclFacade(registry, jvppAcl);
+        final AclPluginGetVersionReply pluginVersion =
+                getReply(futureFacade.aclPluginGetVersion(new AclPluginGetVersion()).toCompletableFuture());
+        LOG.info("Acl plugin successfully loaded[version {}.{}]", pluginVersion.major, pluginVersion.minor);
+        return futureFacade;
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java
new file mode 100644 (file)
index 0000000..90f2b2f
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.read;
+
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager.DumpCacheManagerBuilder;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpPostProcessingFunction;
+import io.fd.vpp.jvpp.acl.dto.AclDetailsReplyDump;
+import io.fd.vpp.jvpp.acl.dto.AclDump;
+import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetailsReplyDump;
+import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDump;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+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.interfaces.rev140508.interfaces.state.Interface;
+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._interface.acl.rev161214._interface.acl.attributes.acl.EgressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAclsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAclsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppAcl;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppAclCustomizer extends FutureJVppAclCustomizer
+        implements ListReaderCustomizer<VppAcls, VppAclsKey, VppAclsBuilder>, JvppReplyConsumer, ByteDataTranslator {
+
+    private final NamingContext interfaceContext;
+    private final NamingContext standardAclContext;
+    /**
+     * true == ingress
+     * false == egress
+     */
+    private final boolean input;
+    private final DumpCacheManager<AclInterfaceListDetailsReplyDump, Integer> aclReferenceDumpManager;
+    private final DumpCacheManager<AclDetailsReplyDump, Integer> aclDumpManager;
+
+    public VppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade,
+                            @Nonnull final NamingContext interfaceContext,
+                            @Nonnull final NamingContext standardAclContext,
+                            final boolean input) {
+        super(jVppAclFacade);
+        this.interfaceContext = interfaceContext;
+        this.standardAclContext = standardAclContext;
+        this.input = input;
+
+        aclReferenceDumpManager =
+                new DumpCacheManagerBuilder<AclInterfaceListDetailsReplyDump, Integer>()
+                        .withExecutor(createAclReferenceDumpExecutor())
+                        .withPostProcessingFunction(input
+                                ? createInputAclFilter()
+                                : createOutputAclFilter())
+                        .acceptOnly(AclInterfaceListDetailsReplyDump.class)
+                        .build();
+
+        aclDumpManager = new DumpCacheManagerBuilder<AclDetailsReplyDump, Integer>()
+                .withExecutor(createAclExecutor())
+                .acceptOnly(AclDetailsReplyDump.class)
+                .build();
+    }
+
+    private EntityDumpExecutor<AclDetailsReplyDump, Integer> createAclExecutor() {
+        return (identifier, params) -> {
+            AclDump request = new AclDump();
+            request.aclIndex = params;
+            return getReplyForRead(getjVppAclFacade().aclDump(request).toCompletableFuture(), identifier);
+        };
+    }
+
+    private EntityDumpPostProcessingFunction<AclInterfaceListDetailsReplyDump> createInputAclFilter() {
+        return dump -> {
+            // filters acl's to first N(those are input ones)
+            dump.aclInterfaceListDetails = dump.aclInterfaceListDetails
+                    .stream()
+                    .map(iface -> {
+                        iface.acls = Arrays.copyOfRange(iface.acls, 0, iface.nInput - 1);
+                        return iface;
+                    })
+                    .collect(Collectors.toList());
+            return dump;
+        };
+    }
+
+    private EntityDumpPostProcessingFunction<AclInterfaceListDetailsReplyDump> createOutputAclFilter() {
+        return dump -> {
+            // filters acl's to last N(those are output ones)
+            dump.aclInterfaceListDetails = dump.aclInterfaceListDetails
+                    .stream()
+                    .map(iface -> {
+                        iface.acls = Arrays.copyOfRange(iface.acls, iface.nInput, iface.acls.length);
+                        return iface;
+                    })
+                    .collect(Collectors.toList());
+            return dump;
+        };
+    }
+
+    private EntityDumpExecutor<AclInterfaceListDetailsReplyDump, Integer> createAclReferenceDumpExecutor() {
+        return (identifier, params) -> {
+            AclInterfaceListDump dumpRequest = new AclInterfaceListDump();
+            dumpRequest.swIfIndex = params;
+            return getReplyForRead(getjVppAclFacade().aclInterfaceListDump(dumpRequest).toCompletableFuture(),
+                    identifier);
+        };
+    }
+
+    @Nonnull
+    @Override
+    public List<VppAclsKey> getAllIds(@Nonnull final InstanceIdentifier<VppAcls> id, @Nonnull final ReadContext context)
+            throws ReadFailedException {
+
+        final String parentInterfaceName = id.firstKeyOf(Interface.class).getName();
+        final int parentInterfaceIndex = interfaceContext.getIndex(parentInterfaceName, context.getMappingContext());
+
+        final Optional<AclInterfaceListDetailsReplyDump> dumpReply =
+                aclReferenceDumpManager.getDump(id, context.getModificationCache(), parentInterfaceIndex);
+
+        if (dumpReply.isPresent() && !dumpReply.get().aclInterfaceListDetails.isEmpty()) {
+            return Arrays.stream(dumpReply.get().aclInterfaceListDetails.get(0).acls)
+                    .mapToObj(aclIndex -> standardAclContext.getName(aclIndex, context.getMappingContext()))
+                    .map(aclName -> new VppAclsKey(aclName, VppAcl.class))
+                    .collect(Collectors.toList());
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<VppAcls> readData) {
+        if (input) {
+            IngressBuilder.class.cast(builder).setVppAcls(readData);
+        } else {
+            EgressBuilder.class.cast(builder).setVppAcls(readData);
+        }
+    }
+
+    @Nonnull
+    @Override
+    public VppAclsBuilder getBuilder(@Nonnull final InstanceIdentifier<VppAcls> id) {
+        return new VppAclsBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VppAcls> id,
+                                      @Nonnull final VppAclsBuilder builder,
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
+        final VppAclsKey vppAclsKey = id.firstKeyOf(VppAcls.class);
+        final String aclName = vppAclsKey.getName();
+        final int aclIndex = standardAclContext.getIndex(aclName, ctx.getMappingContext());
+
+        final Optional<AclDetailsReplyDump> dumpReply =
+                aclDumpManager.getDump(id, ctx.getModificationCache(), aclIndex);
+
+        if (dumpReply.isPresent() && !dumpReply.get().aclDetails.isEmpty()) {
+            // FIXME (model expects hex string, but tag is written and read as ascii string)
+            // decide how tag should be handled (model change might be needed).
+            builder.setName(aclName);
+            builder.setType(vppAclsKey.getType());
+            builder.setTag(new HexString(printHexBinary(dumpReply.get().aclDetails.get(0).tag)));
+        } else {
+            throw new ReadFailedException(id,
+                    new IllegalArgumentException(String.format("Acl with name %s not found", aclName)));
+        }
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java
new file mode 100644 (file)
index 0000000..982d89b
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.read;
+
+import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.acl.dto.MacipAclDetails;
+import io.fd.vpp.jvpp.acl.dto.MacipAclDetailsReplyDump;
+import io.fd.vpp.jvpp.acl.dto.MacipAclDump;
+import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceGet;
+import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceGetReply;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAclBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppMacIpAclCustomizer extends FutureJVppAclCustomizer
+        implements ReaderCustomizer<VppMacipAcl, VppMacipAclBuilder>, JvppReplyConsumer, ByteDataTranslator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VppMacIpAclCustomizer.class);
+
+    private final DumpCacheManager<MacipAclDetailsReplyDump, Integer> macIpAclDumpManager;
+    private final DumpCacheManager<MacipAclInterfaceGetReply, Void> interfaceMacIpAclDumpManager;
+    private final NamingContext interfaceContext;
+    private final NamingContext macIpAclContext;
+
+    public VppMacIpAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade,
+                                 @Nonnull final NamingContext interfaceContext,
+                                 @Nonnull final NamingContext macIpAclContext) {
+        super(jVppAclFacade);
+
+        // for dumping of Mac-ip details
+        macIpAclDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<MacipAclDetailsReplyDump, Integer>()
+                .withExecutor(createMacIpDumpExecutor())
+                .acceptOnly(MacipAclDetailsReplyDump.class)
+                .build();
+
+        // for dumping of reference on interface
+        interfaceMacIpAclDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<MacipAclInterfaceGetReply, Void>()
+                .withExecutor(createInterfaceMacIpDumpExecutor())
+                .acceptOnly(MacipAclInterfaceGetReply.class)
+                .build();
+        this.interfaceContext = interfaceContext;
+        this.macIpAclContext = macIpAclContext;
+    }
+
+    private EntityDumpExecutor<MacipAclDetailsReplyDump, Integer> createMacIpDumpExecutor() {
+        return (identifier, params) -> {
+            MacipAclDump request = new MacipAclDump();
+            request.aclIndex = params;
+
+            return getReplyForRead(getjVppAclFacade().macipAclDump(request).toCompletableFuture(), identifier);
+        };
+    }
+
+    private EntityDumpExecutor<MacipAclInterfaceGetReply, Void> createInterfaceMacIpDumpExecutor() {
+        return (identifier, params) -> getReplyForRead(
+                getjVppAclFacade().macipAclInterfaceGet(new MacipAclInterfaceGet()).toCompletableFuture(),
+                identifier);
+    }
+
+    @Nonnull
+    @Override
+    public VppMacipAclBuilder getBuilder(@Nonnull final InstanceIdentifier<VppMacipAcl> id) {
+        return new VppMacipAclBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id,
+                                      @Nonnull final VppMacipAclBuilder builder,
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
+        final String interfaceName = id.firstKeyOf(Interface.class).getName();
+        final MappingContext mappingContext = ctx.getMappingContext();
+        final int interfaceIndex = interfaceContext.getIndex(interfaceName, mappingContext);
+        final ModificationCache modificationCache = ctx.getModificationCache();
+        final Optional<MacipAclInterfaceGetReply> interfacesMacIpDumpReply =
+                interfaceMacIpAclDumpManager.getDump(id, modificationCache, NO_PARAMS);
+
+        if (interfacesMacIpDumpReply.isPresent() && interfaceIndex < interfacesMacIpDumpReply.get().count) {
+            final int aclIndex = interfacesMacIpDumpReply.get().acls[interfaceIndex];
+
+            final Optional<MacipAclDetailsReplyDump> macIpDumpReply =
+                    macIpAclDumpManager.getDump(id, modificationCache, aclIndex);
+
+            if (macIpDumpReply.isPresent() && !macIpDumpReply.get().macipAclDetails.isEmpty()) {
+                final MacipAclDetails details = macIpDumpReply.get().macipAclDetails.get(0);
+
+                builder.setName(macIpAclContext.getName(aclIndex, mappingContext))
+                        .setType(
+                                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAcl.class)
+                        .setTag(new HexString(printHexBinary(details.tag)));
+            } else {
+                // this is invalid state(Interface in VPP will act as "deny-all" for security reasons), but generally
+                // it should not happen
+                throw new ReadFailedException(id,
+                        new IllegalStateException(String.format("ACC with index %s not found in VPP", aclIndex)));
+            }
+        } else {
+            // this is valid state, so just logging
+            LOG.info("No Mac-ip ACL specified for Interface name={},index={}", interfaceName, interfaceIndex);
+        }
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+                      @Nonnull final VppMacipAcl readValue) {
+        IngressBuilder.class.cast(parentBuilder).setVppMacipAcl(readValue);
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java
new file mode 100644 (file)
index 0000000..8952062
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.read.factory;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.acl.AclModule;
+import io.fd.hc2vpp.acl.read.VppAclCustomizer;
+import io.fd.hc2vpp.acl.read.VppMacIpAclCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.EgressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceAclReaderFactory implements ReaderFactory {
+
+    @Inject
+    private FutureJVppAclFacade futureAclFacade;
+
+    @Inject
+    @Named(AclModule.STANDARD_ACL_CONTEXT_NAME)
+    private NamingContext standardAclContext;
+
+    @Inject
+    @Named(AclModule.MAC_IP_ACL_CONTEXT_NAME)
+    private NamingContext macIpAClContext;
+
+    @Inject
+    @Named("interface-context")
+    private NamingContext interfaceContext;
+
+    private static final InstanceIdentifier<Interface>
+        IFC_ID = InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    private static final InstanceIdentifier<VppAclInterfaceStateAugmentation> VPP_ACL_AUG_IID =
+        IFC_ID.augmentation(VppAclInterfaceStateAugmentation.class);
+    private static final InstanceIdentifier<Acl> ACL_IID = VPP_ACL_AUG_IID.child(Acl.class);
+
+    @Override
+    public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+        registry.addStructuralReader(VPP_ACL_AUG_IID, VppAclInterfaceStateAugmentationBuilder.class);
+        registry.addStructuralReader(ACL_IID, AclBuilder.class);
+
+        final InstanceIdentifier<Ingress> ingressInstanceIdentifier = ACL_IID.child(Ingress.class);
+        registry.addStructuralReader(ingressInstanceIdentifier, IngressBuilder.class);
+        registry.addAfter(new GenericListReader<>(ingressInstanceIdentifier.child(VppAcls.class),
+            new VppAclCustomizer(futureAclFacade, interfaceContext, standardAclContext, true)), IFC_ID);
+        registry.addAfter(new GenericReader<>(ingressInstanceIdentifier.child(VppMacipAcl.class),
+            new VppMacIpAclCustomizer(futureAclFacade, interfaceContext, macIpAClContext)), IFC_ID);
+
+        final InstanceIdentifier<Egress> egressInstanceIdentifier = ACL_IID.child(Egress.class);
+        registry.addStructuralReader(egressInstanceIdentifier, EgressBuilder.class);
+        registry.addAfter(new GenericListReader<>(egressInstanceIdentifier.child(VppAcls.class),
+            new VppAclCustomizer(futureAclFacade, interfaceContext, standardAclContext, false)), IFC_ID);
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java
new file mode 100644 (file)
index 0000000..e2d6bee
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+
+/**
+ * Holds reference to jvpp acl implementation
+ */
+public abstract class FutureJVppAclCustomizer {
+
+    private final FutureJVppAclFacade jVppAclFacade;
+
+    public FutureJVppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade) {
+        this.jVppAclFacade = checkNotNull(jVppAclFacade, "JVpp Acl Future api is null");
+    }
+
+    public FutureJVppAclFacade getjVppAclFacade() {
+        return jVppAclFacade;
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java
new file mode 100644 (file)
index 0000000..3257878
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.ace;
+
+import io.fd.hc2vpp.acl.util.ace.extractor.MacIpAceDataExtractor;
+import io.fd.hc2vpp.acl.util.ace.extractor.StandardAceDataExtractor;
+import io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer;
+import io.fd.vpp.jvpp.acl.types.AclRule;
+import io.fd.vpp.jvpp.acl.types.MacipAclRule;
+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.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
+
+/**
+ * Convert Ace's to vpp rules
+ */
+public interface AceConverter extends MacIpAceDataExtractor, StandardAceDataExtractor, ProtoPreBindRuleProducer {
+
+
+    default MacipAclRule[] convertToMacIpAclRules(@Nonnull final List<Ace> aces) {
+        return aces.stream()
+                .map(ace -> {
+                    final VppMacipAce macIpAce = fromMacIpAce(ace);
+
+                    MacipAclRule rule = new MacipAclRule();
+
+                    rule.srcMac = sourceMacAsBytes(macIpAce);
+                    rule.srcMacMask = sourceMacMaskAsBytes(macIpAce);
+                    rule.isPermit = macIpAction(ace);
+
+                    if (macIpIsIpv6(macIpAce)) {
+                        rule.isIpv6 = 1;
+                        rule.srcIpAddr = ipv6Address(macIpAce);
+                        rule.srcIpPrefixLen = ipv6AddressPrefix(macIpAce);
+                    } else {
+                        rule.isIpv6 = 0;
+                        rule.srcIpAddr = ipv4Address(macIpAce);
+                        rule.srcIpPrefixLen = ipv4AddressPrefix(macIpAce);
+                    }
+
+                    return rule;
+                })
+                .collect(Collectors.toList())
+                .toArray(new MacipAclRule[aces.size()]);
+    }
+
+    default AclRule[] convertToStandardAclRules(@Nonnull final List<Ace> aces) {
+        return aces.stream()
+                .map(ace -> {
+                    final VppAce standardAce = fromStandardAce(ace);
+
+                    // pre-bind rule with protocol based attributes
+                    AclRule rule = createPreBindRule(standardAce);
+
+                    rule.isPermit = standardAction(ace);
+
+                    if (standardIsIpv6(ace)) {
+                        rule.isIpv6 = 1;
+                        rule.srcIpAddr = ipv6SourceAddress(standardAce);
+                        rule.srcIpPrefixLen = ipv6SourceAddressPrefix(standardAce);
+                        rule.dstIpAddr = ipv6DestinationAddress(standardAce);
+                        rule.dstIpPrefixLen = ipv6DestinationAddressPrefix(standardAce);
+                    } else {
+                        rule.isIpv6 = 0;
+                        rule.srcIpAddr = ipv4SourceAddress(standardAce);
+                        rule.srcIpPrefixLen = ipv4SourceAddressPrefix(standardAce);
+                        rule.dstIpAddr = ipv4DestinationAddress(standardAce);
+                        rule.dstIpPrefixLen = ipv4DestinationAddressPrefix(standardAce);
+                    }
+
+
+                    return rule;
+                })
+                .collect(Collectors.toList())
+                .toArray(new AclRule[aces.size()]);
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java
new file mode 100644 (file)
index 0000000..a0d1990
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.ace.extractor;
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Deny;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAceIpv4HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAceIpv6HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv6;
+
+public interface MacIpAceDataExtractor extends AddressTranslator {
+
+    default VppMacipAce fromMacIpAce(@Nonnull final Ace ace) {
+        return VppMacipAce.class.cast(ace.getMatches().getAceType());
+    }
+
+    default boolean macIpIsIpv6(@Nonnull final VppMacipAce ace) {
+        return ace.getVppMacipAceNodes().getAceIpVersion() instanceof AceIpv6;
+    }
+
+    default byte[] sourceMacAsBytes(@Nonnull final VppMacipAce ace) {
+        return macToByteArray(ace.getVppMacipAceNodes().getSourceMacAddress().getValue());
+    }
+
+    default byte[] sourceMacMaskAsBytes(@Nonnull final VppMacipAce ace) {
+        return macToByteArray(ace.getVppMacipAceNodes().getSourceMacAddressMask().getValue());
+    }
+
+    default byte[] ipv4Address(@Nonnull final VppMacipAce ace) {
+        return ipv4AddressPrefixToArray(
+            VppMacipAceIpv4HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv4Network());
+    }
+
+    default byte ipv4AddressPrefix(@Nonnull final VppMacipAce ace) {
+        return extractPrefix(
+            VppMacipAceIpv4HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv4Network());
+    }
+
+    default byte[] ipv6Address(@Nonnull final VppMacipAce ace) {
+        return ipv6AddressPrefixToArray(
+            VppMacipAceIpv6HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv6Network());
+    }
+
+    default byte ipv6AddressPrefix(@Nonnull final VppMacipAce ace) {
+        return extractPrefix(
+            VppMacipAceIpv6HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv6Network());
+    }
+
+    /**
+     * Only 0 and 1 are allowed for mac-ip
+     */
+    default byte macIpAction(@Nonnull final Ace ace) {
+        final PacketHandling action = ace.getActions().getPacketHandling();
+        if (action instanceof Permit) {
+            return 1;
+        } else if (action instanceof Deny) {
+            return 0;
+        } else {
+            throw new IllegalArgumentException(
+                String.format("Unsupported packet-handling action %s for ACE %s", action, ace));
+        }
+    }
+
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java
new file mode 100644 (file)
index 0000000..2e7ccbd
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.ace.extractor;
+
+
+import com.google.common.collect.ImmutableMap;
+import io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Deny;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv6HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.actions.packet.handling.Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv6;
+
+
+public interface StandardAceDataExtractor extends AddressTranslator, ProtoPreBindRuleProducer {
+
+    /**
+     * Allowed packet-processing actions for Acl's
+     */
+    Map<Class<? extends PacketHandling>, Integer> ACTION_VALUE_PAIRS = ImmutableMap.of(Deny.class, 0, Permit.class, 1,
+            Stateful.class, 2);
+
+    default VppAce fromStandardAce(@Nonnull final Ace ace) {
+        return VppAce.class.cast(ace.getMatches().getAceType());
+    }
+
+    default boolean standardIsIpv6(@Nonnull final Ace ace) {
+        return VppAce.class.cast(ace.getMatches().getAceType()).getVppAceNodes().getAceIpVersion() instanceof AceIpv6;
+    }
+
+    default byte[] ipv4SourceAddress(@Nonnull final VppAce ace) {
+        return ipv4AddressPrefixToArray(
+            AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv4Network());
+    }
+
+    default byte ipv4SourceAddressPrefix(@Nonnull final VppAce ace) {
+        return extractPrefix(AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv4Network());
+    }
+
+    default byte[] ipv4DestinationAddress(@Nonnull final VppAce ace) {
+        return ipv4AddressPrefixToArray(
+            AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv4Network());
+    }
+
+    default byte ipv4DestinationAddressPrefix(@Nonnull final VppAce ace) {
+        return extractPrefix(AceIpv4.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv4Network());
+    }
+
+    default byte[] ipv6SourceAddress(@Nonnull final VppAce ace) {
+        return ipv6AddressPrefixToArray(
+            AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv6Network());
+    }
+
+    default byte ipv6SourceAddressPrefix(@Nonnull final VppAce ace) {
+        return extractPrefix(AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv6Network());
+    }
+
+    default byte[] ipv6DestinationAddress(@Nonnull final VppAce ace) {
+        return ipv6AddressPrefixToArray(
+            AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv6Network());
+    }
+
+    default byte ipv6DestinationAddressPrefix(@Nonnull final VppAce ace) {
+        return extractPrefix(AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv6Network());
+    }
+
+    default byte standardAction(@Nonnull final Ace ace) {
+        final PacketHandling action = ace.getActions().getPacketHandling();
+        return ACTION_VALUE_PAIRS.get(ACTION_VALUE_PAIRS.keySet().stream()
+                .filter(aClass -> aClass.isInstance(action))
+                .findAny()
+                .orElseThrow(() -> new IllegalArgumentException(
+                        String.format("Unsupported packet-handling action %s for ACE %s", action,
+                                ace.getRuleName())))).byteValue();
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java
new file mode 100644 (file)
index 0000000..77e58fe
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.acl;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
+
+/**
+ * Extracts data from Acls.
+ * Expects data validated by {@link AclValidator}
+ */
+public interface AclDataExtractor {
+
+    /**
+     * Checks if provided {@link Acl} has aces of type {@link VppAce}
+     */
+    default boolean isStandardAcl(@Nonnull final Acl acl) {
+        return acl.getAccessListEntries().getAce().stream()
+                .map(Ace::getMatches)
+                .map(Matches::getAceType)
+                .filter(aceType -> aceType instanceof VppAce)
+                .findAny()
+                .isPresent();
+    }
+
+    /**
+     * Checks if provided {@link Acl} has aces of type {@link VppMacipAce}
+     */
+    default boolean isMacIpAcl(@Nonnull final Acl acl) {
+        return acl.getAccessListEntries().getAce().stream()
+                .map(Ace::getMatches)
+                .map(Matches::getAceType)
+                .filter(aceType -> aceType instanceof VppMacipAce)
+                .findAny()
+                .isPresent();
+    }
+
+    default List<Ace> getAces(@Nonnull final Acl acl) {
+        return acl.getAccessListEntries().getAce();
+    }
+
+    /**
+     * Convert {@link Acl} name to byte array as UTF_8
+     */
+    default byte[] getAclNameAsBytes(@Nonnull final Acl acl) {
+        return acl.getAclName().getBytes(StandardCharsets.UTF_8);
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java
new file mode 100644 (file)
index 0000000..3779b82
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.acl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
+
+/**
+ * Validate Acl data if processable by vpp
+ */
+public interface AclValidator {
+
+    Set<Class<? extends AclBase>> SUPPORTED_ACL_TYPES = ImmutableSet.of(VppAcl.class, VppMacipAcl.class);
+
+    Map<Class<? extends AclBase>, Class<? extends AceType>> ACL_ACE_PAIRS = ImmutableMap.of(
+            VppAcl.class, VppAce.class,
+            VppMacipAcl.class, VppMacipAce.class);
+
+    static void isSupportedAclType(final Acl acl) {
+        checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getAclType()),
+                "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getAclType(),
+                acl.getAclName(), SUPPORTED_ACL_TYPES);
+    }
+
+    static void hasConsistentAceTypeForAclType(final Acl acl) {
+        checkTypesSame(acl.getAccessListEntries().getAce(), acl.getAclName(),
+                checkNotNull(ACL_ACE_PAIRS.get(acl.getAclType()), "Unsupported ACL type %s for ACL %s",
+                        acl.getAclType(), acl.getAclName()));
+    }
+
+    static void checkTypesSame(final List<Ace> aces, final String aclName, final Class<? extends AceType> aceType) {
+        final Set<AceType> unsupportedAceTypes = aces.stream()
+                .map(Ace::getMatches)
+                .map(Matches::getAceType)
+                .filter(aceType::equals)
+                .collect(Collectors.toSet());
+        checkArgument(unsupportedAceTypes.isEmpty(), "Detected unsupported ace types [%s] for ACL %s, expected %s",
+                unsupportedAceTypes, aclName, aceType);
+    }
+
+    static void hasAceList(final Acl acl) {
+        //checks if aces are defined
+        checkArgument(!checkNotNull(checkNotNull(acl.getAccessListEntries(), "No access list entries defined")
+                .getAce(), "No aces defined")
+                .isEmpty(), "Empty ace list defined");
+    }
+
+    default void validateAcl(@Nonnull final Acl acl) {
+        hasAceList(acl);
+        isSupportedAclType(acl);
+        hasConsistentAceTypeForAclType(acl);
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java
new file mode 100644 (file)
index 0000000..1fecc6c
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.acl;
+
+import io.fd.hc2vpp.acl.util.ace.AceConverter;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.AclAddReplace;
+import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply;
+import io.fd.vpp.jvpp.acl.dto.AclDel;
+import io.fd.vpp.jvpp.acl.dto.MacipAclAdd;
+import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply;
+import io.fd.vpp.jvpp.acl.dto.MacipAclDel;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Write standard and mac-ip acls
+ */
+public interface AclWriter extends AclDataExtractor, AceConverter, JvppReplyConsumer {
+
+    int ACL_INDEX_CREATE_NEW = -1;
+
+    default void addStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade,
+                                @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+                                @Nonnull final NamingContext standardAclContext,
+                                @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+
+        final AclAddReplace request = new AclAddReplace();
+
+        request.tag = getAclNameAsBytes(acl);
+        request.aclIndex = ACL_INDEX_CREATE_NEW;
+        request.r = convertToStandardAclRules(getAces(acl));
+        request.count = request.r.length;
+
+        final AclAddReplaceReply reply =
+                getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id);
+
+        // maps new acl to returned index
+        standardAclContext.addName(reply.aclIndex, acl.getAclName(), mappingContext);
+    }
+
+    // according to vpp team, this was tested extensively, and should work
+    default void updateStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade,
+                                   @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+                                   @Nonnull final NamingContext standardAclContext,
+                                   @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+
+        final AclAddReplace request = new AclAddReplace();
+
+        request.tag = getAclNameAsBytes(acl);
+        // by setting existing index, request is resolved as update
+        request.aclIndex = standardAclContext.getIndex(acl.getAclName(), mappingContext);
+        request.r = convertToStandardAclRules(getAces(acl));
+        request.count = request.r.length;
+
+        getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id);
+
+    }
+
+
+    default void deleteStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade,
+                                   @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+                                   @Nonnull final NamingContext standardAclContext,
+                                   @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+
+        final AclDel request = new AclDel();
+        final String aclName = acl.getAclName();
+        request.aclIndex = standardAclContext.getIndex(aclName, mappingContext);
+
+        getReplyForDelete(futureFacade.aclDel(request).toCompletableFuture(), id);
+
+        // removes mapping after successful delete
+        standardAclContext.removeName(aclName, mappingContext);
+    }
+
+    default void addMacIpAcl(@Nonnull final FutureJVppAclFacade futureFacade,
+                             @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+                             @Nonnull final NamingContext macIpAclContext,
+                             @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+        final MacipAclAdd request = new MacipAclAdd();
+
+        request.tag = getAclNameAsBytes(acl);
+        request.r = convertToMacIpAclRules(getAces(acl));
+        request.count = request.r.length;
+
+        final MacipAclAddReply reply = getReplyForWrite(futureFacade.macipAclAdd(request).toCompletableFuture(), id);
+
+        // map mac-ip acl to returned index
+        macIpAclContext.addName(reply.aclIndex, acl.getAclName(), mappingContext);
+    }
+
+    default void deleteMacIpAcl(@Nonnull final FutureJVppAclFacade futureFacade,
+                                @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+                                @Nonnull final NamingContext macIpAclContext,
+                                @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+        final MacipAclDel request = new MacipAclDel();
+        final String aclName = acl.getAclName();
+        request.aclIndex = macIpAclContext.getIndex(aclName, mappingContext);
+
+        getReplyForDelete(futureFacade.macipAclDel(request).toCompletableFuture(), id);
+
+        macIpAclContext.removeName(aclName, mappingContext);
+    }
+
+
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java
new file mode 100644 (file)
index 0000000..e3c5b72
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package io.fd.hc2vpp.acl.util.iface.acl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.util.List;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Multi-assignment single-request taking advantage from acl_interface_set_acl_list api
+ */
+public class AclInterfaceAssignmentRequest implements JvppReplyConsumer, ByteDataTranslator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AclInterfaceAssignmentRequest.class);
+
+    private final MappingContext mappingContext;
+    private InstanceIdentifier<Acl> identifier;
+    private List<String> inputAclNames;
+    private List<String> outputAclNames;
+    private NamingContext standardAclContext;
+    private NamingContext interfaceContext;
+
+
+    private AclInterfaceAssignmentRequest(final MappingContext mappingContext) {
+        this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null");
+    }
+
+    public static AclInterfaceAssignmentRequest create(@Nonnull final MappingContext mappingContext) {
+        return new AclInterfaceAssignmentRequest(mappingContext);
+    }
+
+    public AclInterfaceAssignmentRequest identifier(
+            @Nonnull final InstanceIdentifier<Acl> identifier) {
+        this.identifier = identifier;
+        return this;
+    }
+
+    public AclInterfaceAssignmentRequest inputAclNames(@Nonnull final List<String> inputAclNames) {
+        this.inputAclNames = inputAclNames;
+        return this;
+    }
+
+    public AclInterfaceAssignmentRequest outputAclNames(@Nonnull final List<String> outputAclNames) {
+        this.outputAclNames = outputAclNames;
+        return this;
+    }
+
+    public AclInterfaceAssignmentRequest standardAclContext(@Nonnull final NamingContext standardAclContext) {
+        this.standardAclContext = standardAclContext;
+        return this;
+    }
+
+    public AclInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) {
+        this.interfaceContext = interfaceContext;
+        return this;
+    }
+
+    private void checkValidRequest() {
+        checkNotNull(identifier, "Identifier cannot be null");
+        checkNotNull(inputAclNames, "Input ACL names cannot be null");
+        checkNotNull(outputAclNames, "Output ACL names cannot be null");
+        checkNotNull(standardAclContext, "ACL context cannot be null");
+        checkNotNull(interfaceContext, "Interface context cannot be null");
+    }
+
+    public void executeAsCreate(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException {
+        checkValidRequest();
+        final String interfaceName = identifier.firstKeyOf(Interface.class).getName();
+
+        // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request
+        synchronized (mappingContext) {
+            LOG.debug(
+                    "Executing acl interface assignment write request for interface={}, input ACL's={},output ACL's={}",
+                    interfaceName, inputAclNames, outputAclNames);
+
+            getReplyForWrite(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(),
+                    identifier);
+            LOG.debug(
+                    "Acl interface assignment write request for interface={}, input ACL's={},output ACL's={} successfully passed",
+                    interfaceName, inputAclNames, outputAclNames);
+        }
+    }
+
+    public void executeAsUpdate(@Nonnull final FutureJVppAclFacade api, final Acl before, final Acl after)
+            throws WriteFailedException {
+        checkValidRequest();
+        final String interfaceName = identifier.firstKeyOf(Interface.class).getName();
+
+        // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request
+        synchronized (mappingContext) {
+            LOG.debug(
+                    "Executing acl interface assignment update request for interface={}, input ACL's={},output ACL's={}",
+                    interfaceName, inputAclNames, outputAclNames);
+
+            getReplyForUpdate(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(),
+                    identifier, before, after);
+            LOG.debug(
+                    "Acl interface assignment update request for interface={}, input ACL's={},output ACL's={} successfully passed",
+                    interfaceName, inputAclNames, outputAclNames);
+        }
+    }
+
+    public void executeAsDelete(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException {
+        checkValidRequest();
+        final String interfaceName = identifier.firstKeyOf(Interface.class).getName();
+
+        // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request
+        synchronized (mappingContext) {
+            LOG.debug(
+                    "Executing acl interface assignment delete request for interface={}, input ACL's={},output ACL's={}",
+                    interfaceName, inputAclNames, outputAclNames);
+
+            getReplyForDelete(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(),
+                    identifier);
+            LOG.debug(
+                    "Acl interface assignment delete request for interface={}, input ACL's={},output ACL's={} successfully passed",
+                    interfaceName, inputAclNames, outputAclNames);
+        }
+    }
+
+    // synchronized on higher layer
+    private AclInterfaceSetAclList createRequest(final String interfaceName) {
+
+        AclInterfaceSetAclList request = new AclInterfaceSetAclList();
+        request.swIfIndex = interfaceContext.getIndex(interfaceName, mappingContext);
+        request.nInput = (byte) inputAclNames.size();
+        request.count = (byte) (inputAclNames.size() + outputAclNames.size());
+        request.acls = Stream.concat(inputAclNames.stream(), outputAclNames.stream())
+                .mapToInt(aclName -> standardAclContext.getIndex(aclName, mappingContext))
+                .toArray();
+        return request;
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java
new file mode 100644 (file)
index 0000000..f8d7263
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package io.fd.hc2vpp.acl.util.iface.macip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceAddDel;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MacIpInterfaceAssignmentRequest implements ByteDataTranslator, JvppReplyConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MacIpInterfaceAssignmentRequest.class);
+
+    private final boolean isNew;
+    private final MappingContext mappingContext;
+    private InstanceIdentifier<VppMacipAcl> identifier;
+    private String aclName;
+    private NamingContext macIpAclContext;
+    private NamingContext interfaceContext;
+
+
+    private MacIpInterfaceAssignmentRequest(final boolean isNew, final MappingContext mappingContext) {
+        this.isNew = isNew;
+        this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null");
+    }
+
+    public static MacIpInterfaceAssignmentRequest addNew(@Nonnull final MappingContext mappingContext) {
+        return new MacIpInterfaceAssignmentRequest(true, mappingContext);
+    }
+
+    public static MacIpInterfaceAssignmentRequest deleteExisting(@Nonnull final MappingContext mappingContext) {
+        return new MacIpInterfaceAssignmentRequest(false, mappingContext);
+    }
+
+    public MacIpInterfaceAssignmentRequest identifier(@Nonnull final InstanceIdentifier<VppMacipAcl> identifier) {
+        this.identifier = identifier;
+        return this;
+    }
+
+    public MacIpInterfaceAssignmentRequest aclName(@Nonnull final String aclName) {
+        this.aclName = aclName;
+        return this;
+    }
+
+    public MacIpInterfaceAssignmentRequest macIpAclContext(@Nonnull final NamingContext macIpAclContext) {
+        this.macIpAclContext = macIpAclContext;
+        return this;
+    }
+
+    public MacIpInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) {
+        this.interfaceContext = interfaceContext;
+        return this;
+    }
+
+    private void checkValidRequest() {
+        checkNotNull(identifier, "Identifier cannot be null");
+        checkNotNull(aclName, "ACL name cannot be null");
+        checkNotNull(macIpAclContext, "ACL context cannot be null");
+        checkNotNull(interfaceContext, "Interface context cannot be null");
+    }
+
+    public void execute(@Nonnull final FutureJVppAclFacade api)
+            throws WriteFailedException {
+
+        // locking on mapping context, to prevent modifying of mappings (for both contexts) during execution of request
+        synchronized (mappingContext) {
+            checkValidRequest();
+
+            final String interfaceName = identifier.firstKeyOf(Interface.class).getName();
+
+            MacipAclInterfaceAddDel request = new MacipAclInterfaceAddDel();
+            request.isAdd = booleanToByte(isNew);
+            request.aclIndex = macIpAclContext.getIndex(aclName, mappingContext);
+            request.swIfIndex =
+                    interfaceContext.getIndex(interfaceName, mappingContext);
+
+            LOG.debug("Executing mac-ip interface assignment request for isNew={},aclName={},interfaceName={}", isNew,
+                    aclName, interfaceName);
+            getReplyForWrite(api.macipAclInterfaceAddDel(request).toCompletableFuture(), identifier);
+            LOG.debug(
+                    "Mac-ip interface assignment request for isNew={},aclName={},interfaceName={} successfully passed",
+                    isNew, aclName, interfaceName);
+        }
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java
new file mode 100644 (file)
index 0000000..c1f9a40
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.protocol;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer.ProtocolPair.pair;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.vpp.jvpp.acl.types.AclRule;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ValueRange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.VppAceNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.IpProtocol;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Icmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.IcmpV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Other;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Tcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Udp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.IcmpNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.v6.IcmpV6Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.tcp.TcpNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodes;
+
+/**
+ * Creates ACL rules pre-bind with protocol-related fields.<br>
+ * Support TCP, UDP, ICMP and ICMPv6 protocol numbers according to
+ * <a href="http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml"> this document </a>
+ */
+public interface ProtoPreBindRuleProducer {
+
+    int ICMP_INDEX = 1;
+    int TCP_INDEX = 6;
+    int UDP_INDEX = 17;
+    int ICMPV6_INDEX = 58;
+
+    Set<ProtocolPair> PROTOCOL_PAIRS = ImmutableSet.of(pair(Icmp.class, ICMP_INDEX), pair(Tcp.class, TCP_INDEX),
+            pair(Udp.class, UDP_INDEX), pair(IcmpV6.class, ICMPV6_INDEX));
+
+    class ProtocolPair {
+        private final Class<? extends IpProtocol> protocolClass;
+        private final int index;
+
+        private ProtocolPair(final Class<? extends IpProtocol> protocolClass, final int index) {
+            this.protocolClass = protocolClass;
+            this.index = index;
+        }
+
+        static ProtocolPair pair(@Nonnull final Class<? extends IpProtocol> protocolClass, @Nonnull final int index) {
+            return new ProtocolPair(protocolClass, index);
+        }
+
+        boolean match(@Nonnull final Class<? extends IpProtocol> protocolClass) {
+            return this.protocolClass.isAssignableFrom(protocolClass);
+        }
+
+        int getIndex() {
+            return this.index;
+        }
+    }
+
+    static byte protocol(final IpProtocol ipProtocol) {
+        final Optional<ProtocolPair> optPair = PROTOCOL_PAIRS.stream()
+                .filter(protocolPair -> protocolPair.match(ipProtocol.getClass()))
+                .findAny();
+
+        if (!optPair.isPresent()) {
+            if (Other.class.isAssignableFrom(ipProtocol.getClass())) {
+                return Other.class.cast(ipProtocol).getOtherNodes().getProtocol().byteValue();
+            }
+
+            throw new IllegalArgumentException(String.format("Unsupported Protocol Type %s", ipProtocol.getClass()));
+        }
+        return (byte) optPair.get().getIndex();
+    }
+
+    static AclRule bindIcmpNodes(AclRule rule, VppAce ace) {
+        final VppAceNodes vppAceNodes = ace.getVppAceNodes();
+        checkArgument(vppAceNodes.getIpProtocol() instanceof Icmp);
+        final IcmpNodes icmp = Icmp.class.cast(vppAceNodes.getIpProtocol()).getIcmpNodes();
+        final ValueRange typesRange = icmp.getIcmpTypeRange();
+        final ValueRange codesRange = icmp.getIcmpCodeRange();
+
+        rule.srcportOrIcmptypeFirst = typesRange.getFirst();
+        rule.srcportOrIcmptypeLast = typesRange.getLast();
+        rule.dstportOrIcmpcodeFirst = codesRange.getFirst();
+        rule.dstportOrIcmpcodeLast = codesRange.getLast();
+
+        return rule;
+    }
+
+    static AclRule bindIcmpv6Nodes(AclRule rule, VppAce ace) {
+        final VppAceNodes vppAceNodes = ace.getVppAceNodes();
+        checkArgument(vppAceNodes.getIpProtocol() instanceof IcmpV6);
+        final IcmpV6Nodes icmpV6 = IcmpV6.class.cast(vppAceNodes.getIpProtocol()).getIcmpV6Nodes();
+        final ValueRange typesRange = icmpV6.getIcmpTypeRange();
+        final ValueRange codesRange = icmpV6.getIcmpCodeRange();
+
+        rule.srcportOrIcmptypeFirst = typesRange.getFirst();
+        rule.srcportOrIcmptypeLast = typesRange.getLast();
+        rule.dstportOrIcmpcodeFirst = codesRange.getFirst();
+        rule.dstportOrIcmpcodeLast = codesRange.getLast();
+
+        return rule;
+    }
+
+
+    static AclRule bindTcpNodes(AclRule rule, VppAce ace) {
+        final VppAceNodes vppAceNodes = ace.getVppAceNodes();
+        checkArgument(vppAceNodes.getIpProtocol() instanceof Tcp);
+
+        final TcpNodes tcp = Tcp.class.cast(vppAceNodes.getIpProtocol()).getTcpNodes();
+        final SourcePortRange sourcePortRange = tcp.getSourcePortRange();
+        final DestinationPortRange destinationPortRange = tcp.getDestinationPortRange();
+
+        rule.srcportOrIcmptypeFirst = portNumber(sourcePortRange.getLowerPort());
+        rule.srcportOrIcmptypeLast = portNumber(sourcePortRange.getUpperPort());
+        rule.dstportOrIcmpcodeFirst = portNumber(destinationPortRange.getLowerPort());
+        rule.dstportOrIcmpcodeLast = portNumber(destinationPortRange.getUpperPort());
+        rule.tcpFlagsMask = tcp.getTcpFlagsMask().byteValue();
+        rule.tcpFlagsValue = tcp.getTcpFlagsValue().byteValue();
+
+        return rule;
+    }
+
+    static AclRule bindUdpNodes(AclRule rule, VppAce ace) {
+        final VppAceNodes vppAceNodes = ace.getVppAceNodes();
+        checkArgument(vppAceNodes.getIpProtocol() instanceof Udp);
+
+        final UdpNodes udp = Udp.class.cast(vppAceNodes.getIpProtocol()).getUdpNodes();
+        final SourcePortRange sourcePortRange = udp.getSourcePortRange();
+        final DestinationPortRange destinationPortRange = udp.getDestinationPortRange();
+
+        rule.srcportOrIcmptypeFirst = portNumber(sourcePortRange.getLowerPort());
+        rule.srcportOrIcmptypeLast = portNumber(sourcePortRange.getUpperPort());
+        rule.dstportOrIcmpcodeFirst = portNumber(destinationPortRange.getLowerPort());
+        rule.dstportOrIcmpcodeLast = portNumber(destinationPortRange.getUpperPort());
+
+        return rule;
+    }
+
+    static AclRule bindDefaultNodes(AclRule rule) {
+        rule.srcportOrIcmptypeFirst = 0;
+        rule.srcportOrIcmptypeLast = (short) 65535;
+        rule.dstportOrIcmpcodeFirst = 0;
+        rule.dstportOrIcmpcodeLast = (short) 65535;
+        rule.tcpFlagsValue = 0;
+        rule.tcpFlagsMask = 0;
+        return rule;
+    }
+
+    static short portNumber(final PortNumber portNumber) {
+        return portNumber.getValue().shortValue();
+    }
+
+    default AclRule createPreBindRule(@Nonnull final VppAce vppAce) {
+        AclRule rule = new AclRule();
+
+        rule.proto = protocol(vppAce.getVppAceNodes().getIpProtocol());
+
+        switch (rule.proto) {
+            case ICMP_INDEX: {
+                return bindIcmpNodes(rule, vppAce);
+            }
+
+            case TCP_INDEX: {
+                return bindTcpNodes(rule, vppAce);
+            }
+
+            case UDP_INDEX: {
+                return bindUdpNodes(rule, vppAce);
+            }
+
+            case ICMPV6_INDEX: {
+                return bindIcmpv6Nodes(rule, vppAce);
+            }
+            default: {
+                return bindDefaultNodes(rule);
+            }
+        }
+
+    }
+
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java
new file mode 100644 (file)
index 0000000..3a4fb0c
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write;
+
+import static java.util.stream.Collectors.toList;
+
+import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
+import io.fd.hc2vpp.acl.util.iface.acl.AclInterfaceAssignmentRequest;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Handles acl assignments(only standard ones, mac-ip have dedicated customizer)
+ */
+public class InterfaceAclCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer<Acl> {
+
+    private final NamingContext interfaceContext;
+    private final NamingContext standardAclContext;
+
+    public InterfaceAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade,
+                                  @Nonnull final NamingContext interfaceContext,
+                                  @Nonnull final NamingContext standardAclContext) {
+        super(jVppAclFacade);
+        this.interfaceContext = interfaceContext;
+        this.standardAclContext = standardAclContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        AclInterfaceAssignmentRequest.create(writeContext.getMappingContext())
+                .standardAclContext(standardAclContext)
+                .interfaceContext(interfaceContext)
+                .identifier(id)
+                .inputAclNames(getAclNames(dataAfter.getIngress()))
+                .outputAclNames(getAclNames(dataAfter.getEgress()))
+                .executeAsCreate(getjVppAclFacade());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+                                        @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        AclInterfaceAssignmentRequest.create(writeContext.getMappingContext())
+                .standardAclContext(standardAclContext)
+                .interfaceContext(interfaceContext)
+                .identifier(id)
+                .inputAclNames(getAclNames(dataAfter.getIngress()))
+                .outputAclNames(getAclNames(dataAfter.getEgress()))
+                .executeAsUpdate(getjVppAclFacade(), dataBefore, dataAfter);
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        AclInterfaceAssignmentRequest.create(writeContext.getMappingContext())
+                .standardAclContext(standardAclContext)
+                .interfaceContext(interfaceContext)
+                .identifier(id)
+                .inputAclNames(getAclNames(dataBefore.getIngress()))
+                .outputAclNames(getAclNames(dataBefore.getEgress()))
+                .executeAsDelete(getjVppAclFacade());
+    }
+
+    private static List<String> getAclNames(@Nonnull final VppAclsBaseAttributes acls) {
+        if (acls == null || acls.getVppAcls() == null) {
+            return Collections.emptyList();
+        } else {
+            return acls.getVppAcls().stream().map(VppAcls::getName).collect(toList());
+        }
+    }
+
+
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java
new file mode 100644 (file)
index 0000000..4b59c83
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write;
+
+import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.addNew;
+import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.deleteExisting;
+
+import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+
+public class InterfaceAclMacIpCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer<VppMacipAcl> {
+
+    private final NamingContext macIpAclContext;
+    private final NamingContext interfaceContext;
+
+    public InterfaceAclMacIpCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade,
+                                       @Nonnull final NamingContext macIpAclContext,
+                                       @Nonnull final NamingContext interfaceContext) {
+        super(jVppAclFacade);
+        this.macIpAclContext = macIpAclContext;
+        this.interfaceContext = interfaceContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id,
+                                       @Nonnull final VppMacipAcl dataAfter,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        addNew(writeContext.getMappingContext())
+                .identifier(id)
+                .aclName(dataAfter.getName())
+                .macIpAclContext(macIpAclContext)
+                .interfaceContext(interfaceContext)
+                .execute(getjVppAclFacade());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id,
+                                        @Nonnull final VppMacipAcl dataBefore,
+                                        @Nonnull final VppMacipAcl dataAfter, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+                new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id,
+                                        @Nonnull final VppMacipAcl dataBefore,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        deleteExisting(writeContext.getMappingContext())
+                .identifier(id)
+                .aclName(dataBefore.getName())
+                .macIpAclContext(macIpAclContext)
+                .interfaceContext(interfaceContext)
+                .execute(getjVppAclFacade());
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java
new file mode 100644 (file)
index 0000000..a295678
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write;
+
+import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
+import io.fd.hc2vpp.acl.util.acl.AclDataExtractor;
+import io.fd.hc2vpp.acl.util.acl.AclValidator;
+import io.fd.hc2vpp.acl.util.acl.AclWriter;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppAclCustomizer extends FutureJVppAclCustomizer
+        implements ListWriterCustomizer<Acl, AclKey>, AclValidator, AclDataExtractor, AclWriter {
+
+    private final NamingContext standardAclContext;
+    private final NamingContext macIpAclContext;
+
+    public VppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade,
+                            @Nonnull final NamingContext standardAclContext,
+                            @Nonnull final NamingContext macIpAclContext) {
+        super(jVppAclFacade);
+        this.standardAclContext = standardAclContext;
+        this.macIpAclContext = macIpAclContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        validateAcl(dataAfter);
+
+        final MappingContext mappingContext = writeContext.getMappingContext();
+
+        if (isStandardAcl(dataAfter)) {
+            addStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext);
+        } else if (isMacIpAcl(dataAfter)) {
+            addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext);
+        } else {
+            // double check, first one done by validation
+            throw new WriteFailedException.CreateFailedException(id, dataAfter,
+                    new IllegalArgumentException("Unsupported acl option"));
+        }
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+                                        @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        validateAcl(dataAfter);
+
+        final MappingContext mappingContext = writeContext.getMappingContext();
+
+        if (isStandardAcl(dataAfter)) {
+            updateStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext);
+        } else if (isMacIpAcl(dataAfter)) {
+            synchronized (macIpAclContext) {
+                // there is no direct support for update of mac-ip acl, but only one is allowed per interface
+                // so it is atomic from vpp standpoint. Enclosed in synchronized block to prevent issues with
+                // multiple threads managing naming context
+                deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext);
+                addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext);
+            }
+        } else {
+            // double check, first one done by validation
+            throw new WriteFailedException.CreateFailedException(id, dataAfter,
+                    new IllegalArgumentException("Unsupported acl option"));
+        }
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        // According to VPP team, acl references should be removed before trying to remove ACL
+        // For mac-ip, reference should be removed during removal of mac-ip, so no need to check in hc
+        validateAcl(dataBefore);
+
+        final MappingContext mappingContext = writeContext.getMappingContext();
+
+        if (isStandardAcl(dataBefore)) {
+            deleteStandardAcl(getjVppAclFacade(), id, dataBefore, standardAclContext, mappingContext);
+        } else if (isMacIpAcl(dataBefore)) {
+            deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext);
+        } else {
+            // double check, first one done by validation
+            throw new WriteFailedException.DeleteFailedException(id,
+                    new IllegalArgumentException("Unsupported acl option"));
+        }
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java
new file mode 100644 (file)
index 0000000..fe22f2f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write.factory;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.acl.AclModule;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+
+/**
+ * Created by jsrnicek on 12.12.2016.
+ */
+class AbstractAclWriterFactory {
+
+    @Inject
+    protected FutureJVppAclFacade futureAclFacade;
+
+    @Inject
+    @Named(AclModule.STANDARD_ACL_CONTEXT_NAME)
+    protected NamingContext standardAclContext;
+
+    @Inject
+    @Named(AclModule.MAC_IP_ACL_CONTEXT_NAME)
+    protected NamingContext macIpAClContext;
+
+    @Inject
+    @Named("interface-context")
+    protected NamingContext interfaceContext;
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java
new file mode 100644 (file)
index 0000000..6598aae
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write.factory;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.acl.write.InterfaceAclCustomizer;
+import io.fd.hc2vpp.acl.write.InterfaceAclMacIpCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory {
+
+    private static final InstanceIdentifier<Acl> ACL_IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class)
+            .augmentation(VppAclInterfaceAugmentation.class).child(Acl.class);
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+        registry.subtreeAdd(aclHandledChildren(InstanceIdentifier.create(Acl.class)),
+            new GenericWriter<>(ACL_IID,
+                new InterfaceAclCustomizer(futureAclFacade, interfaceContext, standardAclContext)));
+
+        registry.add(new GenericWriter<>(ACL_IID.child(Ingress.class).child(VppMacipAcl.class),
+            new InterfaceAclMacIpCustomizer(futureAclFacade, macIpAClContext, interfaceContext)));
+    }
+
+    private Set<InstanceIdentifier<?>> aclHandledChildren(final InstanceIdentifier<Acl> parentId) {
+        return ImmutableSet.of(parentId.child(Ingress.class),
+            parentId.child(Ingress.class).child(VppAcls.class),
+            parentId.child(Egress.class),
+            parentId.child(Egress.class).child(VppAcls.class));
+    }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java
new file mode 100644 (file)
index 0000000..546924e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write.factory;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.acl.write.VppAclCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Actions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.VppAceNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.macip.ace.VppMacipAceNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.icmp.header.fields.IcmpCodeRange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.icmp.header.fields.IcmpTypeRange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.IcmpNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.v6.IcmpV6Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.other.OtherNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.tcp.TcpNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory {
+
+    private static Set<InstanceIdentifier<?>> vppAclCustomizerHandledChildren(final InstanceIdentifier<Acl> parentId) {
+        final InstanceIdentifier<Matches> matchesIid =
+            parentId.child(AccessListEntries.class).child(Ace.class).child(Matches.class);
+        return ImmutableSet.of(parentId.child(AccessListEntries.class),
+            parentId.child(AccessListEntries.class).child(Ace.class),
+            parentId.child(AccessListEntries.class).child(Ace.class).child(Matches.class),
+            parentId.child(AccessListEntries.class).child(Ace.class).child(Actions.class),
+            matchesIid,
+            matchesIid.child(VppMacipAceNodes.class),
+            matchesIid.child(VppAceNodes.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpNodes.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpNodes.class).child(IcmpCodeRange.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpNodes.class).child(IcmpTypeRange.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class).child(IcmpCodeRange.class),
+            matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class).child(IcmpTypeRange.class),
+            matchesIid.child(VppAceNodes.class).child(UdpNodes.class),
+            matchesIid.child(VppAceNodes.class).child(UdpNodes.class).child(SourcePortRange.class),
+            matchesIid.child(VppAceNodes.class).child(UdpNodes.class).child(DestinationPortRange.class),
+            matchesIid.child(VppAceNodes.class).child(TcpNodes.class),
+            matchesIid.child(VppAceNodes.class).child(TcpNodes.class).child(SourcePortRange.class),
+            matchesIid.child(VppAceNodes.class).child(TcpNodes.class).child(DestinationPortRange.class),
+            matchesIid.child(VppAceNodes.class).child(OtherNodes.class)
+
+        );
+    }
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+        final InstanceIdentifier<AccessLists> rootNode = InstanceIdentifier.create(AccessLists.class);
+
+        registry.subtreeAdd(vppAclCustomizerHandledChildren(InstanceIdentifier.create(Acl.class)),
+            new GenericListWriter<>(rootNode.child(Acl.class),
+                new VppAclCustomizer(futureAclFacade, standardAclContext, macIpAClContext)));
+    }
+}
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclModuleTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclModuleTest.java
new file mode 100644 (file)
index 0000000..671cd28
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Named;
+import com.google.inject.testing.fieldbinder.Bind;
+import com.google.inject.testing.fieldbinder.BoundFieldModule;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
+import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+
+public class AclModuleTest {
+
+    @Named("honeycomb-context")
+    @Bind
+    @Mock
+    private DataBroker honeycombContext;
+
+    @Named("honeycomb-initializer")
+    @Bind
+    @Mock
+    private DataBroker honeycombInitializer;
+
+    @Named("interface-context")
+    @Bind
+    private NamingContext interfaceContext = new NamingContext("iface", "interface-context");
+
+    @Bind
+    @Mock
+    private JVppRegistry registry;
+
+    @Inject
+    private Set<WriterFactory> writerFactories = new HashSet<>();
+
+    @Inject
+    private Set<ReaderFactory> readerFactories = new HashSet<>();
+
+    @Before
+    public void setUp() throws Exception {
+        initMocks(this);
+        // AclModule adds readers under InterfacesState
+        // because readers for parents need to be present (are part of V3poModule)
+        // add structural readers here (better than maven dependency).
+
+        Guice.createInjector(binder -> Multibinder.newSetBinder(binder, ReaderFactory.class)
+            .addBinding().toInstance(registry -> {
+                registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class),
+                    InterfacesStateBuilder.class);
+                registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class).child(Interface.class),
+                    InterfaceBuilder.class);
+            }), new AclModule(MockJVppAclProvider.class), BoundFieldModule.of(this)).injectMembers(this);
+    }
+
+    @Test
+    public void testWriterFactories() throws Exception {
+        assertThat(writerFactories, is(not(empty())));
+
+        final FlatWriterRegistryBuilder registryBuilder = new FlatWriterRegistryBuilder();
+        writerFactories.forEach(factory -> factory.init(registryBuilder));
+        assertNotNull(registryBuilder.build());
+    }
+
+    @Test
+    public void testReaderFactories() throws Exception {
+        assertThat(readerFactories, is(not(empty())));
+
+        final CompositeReaderRegistryBuilder registryBuilder = new CompositeReaderRegistryBuilder();
+        readerFactories.forEach(factory -> factory.init(registryBuilder));
+        assertNotNull(registryBuilder.build());
+    }
+
+    private static final class MockJVppAclProvider implements Provider<FutureJVppAclFacade> {
+
+        @Override
+        public FutureJVppAclFacade get() {
+            return mock(FutureJVppAclFacade.class);
+        }
+    }
+}
+
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclTestSchemaContext.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/AclTestSchemaContext.java
new file mode 100644 (file)
index 0000000..dd3c1ca
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+
+
+public interface AclTestSchemaContext {
+
+    @SchemaContextProvider
+    default ModuleInfoBackedContext context() {
+        ModuleInfoBackedContext context = ModuleInfoBackedContext.create();
+        context.addModuleInfos(ImmutableSet
+                .of(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.$YangModuleInfoImpl
+                                .getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.$YangModuleInfoImpl
+                                .getInstance()));
+        return context;
+    }
+}
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequestTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequestTest.java
new file mode 100644 (file)
index 0000000..2224d11
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.iface.acl;
+
+import static io.fd.hc2vpp.acl.util.iface.acl.AclInterfaceAssignmentRequest.create;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.collect.ImmutableList;
+import io.fd.hc2vpp.common.test.util.FutureProducer;
+import io.fd.hc2vpp.common.test.util.NamingContextHelper;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList;
+import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclListReply;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class AclInterfaceAssignmentRequestTest implements NamingContextHelper, FutureProducer {
+
+    private static final String INTERFACE_NAME = "iface";
+    private static final int INTERFACE_INDEX = 4;
+
+    private static final String ACL_NAME_1 = "acl-1";
+    private static final String ACL_NAME_2 = "acl-2";
+    private static final String ACL_NAME_3 = "acl-3";
+    private static final String ACL_NAME_4 = "acl-4";
+    private static final String ACL_NAME_5 = "acl-5";
+
+    private static final int ACL_INDEX_1 = 2;
+    private static final int ACL_INDEX_2 = 7;
+    private static final int ACL_INDEX_3 = 4;
+    private static final int ACL_INDEX_4 = 5;
+    private static final int ACL_INDEX_5 = 1;
+
+    @Captor
+    private ArgumentCaptor<AclInterfaceSetAclList> requestCaptor;
+
+    @Mock
+    private FutureJVppAclFacade api;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private InstanceIdentifier<Acl> validIdentifier;
+    private NamingContext interfaceContext;
+    private NamingContext aclContext;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+
+        validIdentifier = InstanceIdentifier.create(Interfaces.class).
+                child(Interface.class, new InterfaceKey(INTERFACE_NAME))
+                .augmentation(VppAclInterfaceAugmentation.class)
+                .child(Acl.class);
+
+        interfaceContext = new NamingContext("iface", "interface-context");
+        aclContext = new NamingContext("acl", "acl-context");
+
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+
+        defineMapping(mappingContext, ACL_NAME_1, ACL_INDEX_1, "acl-context");
+        defineMapping(mappingContext, ACL_NAME_2, ACL_INDEX_2, "acl-context");
+        defineMapping(mappingContext, ACL_NAME_3, ACL_INDEX_3, "acl-context");
+        defineMapping(mappingContext, ACL_NAME_4, ACL_INDEX_4, "acl-context");
+        defineMapping(mappingContext, ACL_NAME_5, ACL_INDEX_5, "acl-context");
+
+        when(api.aclInterfaceSetAclList(any())).thenReturn(future(new AclInterfaceSetAclListReply()));
+    }
+
+    @Test
+    public void verifyNegativeCases() throws WriteFailedException {
+        verifyVariant(create(mappingContext));
+
+        verifyVariant(create(mappingContext).identifier(validIdentifier));
+
+        verifyVariant(create(mappingContext).identifier(validIdentifier).interfaceContext(interfaceContext));
+
+        verifyVariant(create(mappingContext).identifier(validIdentifier).interfaceContext(interfaceContext)
+                .standardAclContext(aclContext));
+
+        verifyVariant(create(mappingContext).identifier(validIdentifier).interfaceContext(interfaceContext)
+                .standardAclContext(aclContext).inputAclNames(Collections.emptyList()));
+
+        verifyVariant(create(mappingContext).identifier(validIdentifier).interfaceContext(interfaceContext)
+                .standardAclContext(aclContext).outputAclNames(Collections.emptyList()));
+    }
+
+    private void verifyVariant(final AclInterfaceAssignmentRequest request) throws WriteFailedException {
+        verifyCreateFailsWithNullPointer(request);
+        verifyUpdateFailsWithNullPointer(request);
+        verifyDeleteFailsWithNullPointer(request);
+    }
+
+    @Test
+    public void executeAsCreate() throws Exception {
+
+        createValidRequest().executeAsCreate(api);
+        createValidRequest().executeAsUpdate(api, mock(Acl.class), mock(Acl.class));
+        createValidRequest().executeAsDelete(api);
+
+        verify(api, times(3)).aclInterfaceSetAclList(requestCaptor.capture());
+        requestCaptor.getAllValues().forEach(AclInterfaceAssignmentRequestTest::verifyValidRequest);
+    }
+
+    private AclInterfaceAssignmentRequest createValidRequest() {
+        return create(mappingContext)
+                .identifier(validIdentifier)
+                .inputAclNames(ImmutableList.of(ACL_NAME_1, ACL_NAME_2, ACL_NAME_3))
+                .outputAclNames(ImmutableList.of(ACL_NAME_4, ACL_NAME_5))
+                .standardAclContext(aclContext)
+                .interfaceContext(interfaceContext);
+    }
+
+    private static void verifyValidRequest(final AclInterfaceSetAclList request) {
+        assertNotNull(request);
+        assertEquals(5, request.count);
+        assertEquals(3, request.nInput);
+        assertTrue(Arrays.equals(new int[]{ACL_INDEX_1, ACL_INDEX_2, ACL_INDEX_3, ACL_INDEX_4, ACL_INDEX_5},
+                request.acls));
+    }
+
+    private void verifyCreateFailsWithNullPointer(final AclInterfaceAssignmentRequest request)
+            throws WriteFailedException {
+        try {
+            request.executeAsCreate(api);
+        } catch (NullPointerException e) {
+            return;
+        }
+        fail("Test should have thrown null pointer");
+    }
+
+    private void verifyUpdateFailsWithNullPointer(final AclInterfaceAssignmentRequest request)
+            throws WriteFailedException {
+        try {
+            request.executeAsUpdate(api, mock(Acl.class), mock(Acl.class));
+        } catch (NullPointerException e) {
+            return;
+        }
+        fail("Test should have thrown null pointer");
+    }
+
+    private void verifyDeleteFailsWithNullPointer(final AclInterfaceAssignmentRequest request)
+            throws WriteFailedException {
+        try {
+            request.executeAsCreate(api);
+        } catch (NullPointerException e) {
+            return;
+        }
+        fail("Test should have thrown null pointer");
+    }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequestTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequestTest.java
new file mode 100644 (file)
index 0000000..e815503
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.iface.macip;
+
+import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.addNew;
+import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.deleteExisting;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import io.fd.hc2vpp.common.test.util.FutureProducer;
+import io.fd.hc2vpp.common.test.util.NamingContextHelper;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceAddDel;
+import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceAddDelReply;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Created by jsrnicek on 13.12.2016.
+ */
+public class MacIpInterfaceAssignmentRequestTest implements NamingContextHelper,FutureProducer {
+
+    private static final String INTERFACE_NAME = "iface";
+    private static final int INTERFACE_INDEX = 4;
+    private static final String ACL_NAME = "mac-ip-acl";
+    private static final int ACL_INDEX = 5;
+
+    @Captor
+    private ArgumentCaptor<MacipAclInterfaceAddDel> requestCaptor;
+
+    @Mock
+    private FutureJVppAclFacade api;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private InstanceIdentifier<VppMacipAcl> validIdentifier;
+    private NamingContext interfaceContext;
+    private NamingContext macIpAclContext;
+
+    @Before
+    public void setUp() throws Exception {
+        initMocks(this);
+
+        validIdentifier = InstanceIdentifier.create(Interfaces.class).
+                child(Interface.class, new InterfaceKey(INTERFACE_NAME))
+                .augmentation(VppAclInterfaceAugmentation.class)
+                .child(Acl.class)
+                .child(Ingress.class)
+                .child(VppMacipAcl.class);
+
+        interfaceContext = new NamingContext("iface", "interface-context");
+        macIpAclContext = new NamingContext("mac-ip-acl", "mac-ip-acl-context");
+
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ACL_NAME, ACL_INDEX, "mac-ip-acl-context");
+        when(api.macipAclInterfaceAddDel(any())).thenReturn(future(new MacipAclInterfaceAddDelReply()));
+    }
+
+    @Test
+    public void testAddNew() throws Exception {
+        addNew(mappingContext)
+                .aclName(ACL_NAME)
+                .identifier(validIdentifier)
+                .interfaceContext(interfaceContext)
+                .macIpAclContext(macIpAclContext)
+                .execute(api);
+        verify(api, times(1)).macipAclInterfaceAddDel(requestCaptor.capture());
+
+        final MacipAclInterfaceAddDel request = requestCaptor.getValue();
+
+        assertNotNull(request);
+        assertEquals(1, request.isAdd);
+        assertEquals(INTERFACE_INDEX, request.swIfIndex);
+        assertEquals(ACL_INDEX, request.aclIndex);
+    }
+
+    @Test
+    public void testDeleteExisting() throws Exception {
+        deleteExisting(mappingContext)
+                .aclName(ACL_NAME)
+                .identifier(validIdentifier)
+                .interfaceContext(interfaceContext)
+                .macIpAclContext(macIpAclContext)
+                .execute(api);
+        verify(api, times(1)).macipAclInterfaceAddDel(requestCaptor.capture());
+
+        final MacipAclInterfaceAddDel request = requestCaptor.getValue();
+
+        assertNotNull(request);
+        assertEquals(0, request.isAdd);
+        assertEquals(INTERFACE_INDEX, request.swIfIndex);
+        assertEquals(ACL_INDEX, request.aclIndex);
+    }
+
+    @Test
+    public void testInvalidCases() throws Exception {
+        verifyFailsWithNullPointer(addNew(mappingContext));
+        verifyFailsWithNullPointer(addNew(mappingContext).aclName(ACL_NAME));
+        verifyFailsWithNullPointer(addNew(mappingContext).aclName(ACL_NAME).interfaceContext(interfaceContext));
+        verifyFailsWithNullPointer(addNew(mappingContext).aclName(ACL_NAME).interfaceContext(interfaceContext)
+                .macIpAclContext(macIpAclContext));
+        verifyFailsWithNullPointer(addNew(mappingContext).aclName(ACL_NAME).interfaceContext(interfaceContext)
+                .identifier(validIdentifier));
+    }
+
+    private void verifyFailsWithNullPointer(final MacIpInterfaceAssignmentRequest request) throws WriteFailedException {
+        try {
+            request.execute(api);
+        } catch (NullPointerException e) {
+            return;
+        }
+        fail("Test should have thrown null pointer");
+    }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducerTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducerTest.java
new file mode 100644 (file)
index 0000000..8f41003
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.util.protocol;
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.acl.AclTestSchemaContext;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.vpp.jvpp.acl.types.AclRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+
+@RunWith(HoneycombTestRunner.class)
+public class ProtoPreBindRuleProducerTest implements ProtoPreBindRuleProducer, AclTestSchemaContext {
+
+    //TODO - remove after resolving how to address identity from different model in textual yang instance identifier
+    private VppAce extractAce(AccessLists accessLists) {
+        return VppAce.class
+                .cast(accessLists.getAcl().get(0).getAccessListEntries().getAce().get(0).getMatches().getAceType());
+    }
+
+    @Test
+    public void testIcmpRule(@InjectTestData(resourcePath = "/rules/icmp-rule.json") AccessLists acls) {
+        final AclRule icmpRule = createPreBindRule(extractAce(acls));
+
+        assertEquals(1, icmpRule.proto);
+        assertEquals(5, icmpRule.srcportOrIcmptypeFirst);
+        assertEquals(8, icmpRule.srcportOrIcmptypeLast);
+        assertEquals(1, icmpRule.dstportOrIcmpcodeFirst);
+        assertEquals(3, icmpRule.dstportOrIcmpcodeLast);
+        assertEquals(0, icmpRule.tcpFlagsMask);
+        assertEquals(0, icmpRule.tcpFlagsValue);
+    }
+
+
+    @Test
+    public void testIcmpv6Rule(@InjectTestData(resourcePath = "/rules/icmp-v6-rule.json") AccessLists acls) {
+        final AclRule icmpv6Rule = createPreBindRule(extractAce(acls));
+
+        assertEquals(58, icmpv6Rule.proto);
+        assertEquals(5, icmpv6Rule.srcportOrIcmptypeFirst);
+        assertEquals(8, icmpv6Rule.srcportOrIcmptypeLast);
+        assertEquals(1, icmpv6Rule.dstportOrIcmpcodeFirst);
+        assertEquals(3, icmpv6Rule.dstportOrIcmpcodeLast);
+        assertEquals(0, icmpv6Rule.tcpFlagsMask);
+        assertEquals(0, icmpv6Rule.tcpFlagsValue);
+    }
+
+    @Test
+    public void testTcpRule(@InjectTestData(resourcePath = "/rules/tcp-rule.json") AccessLists acls) {
+        final AclRule tcpRule = createPreBindRule(extractAce(acls));
+        assertEquals(6, tcpRule.proto);
+        assertEquals(1, tcpRule.srcportOrIcmptypeFirst);
+        assertEquals(5487, tcpRule.srcportOrIcmptypeLast);
+        assertEquals(87, tcpRule.dstportOrIcmpcodeFirst);
+        assertEquals(6745, tcpRule.dstportOrIcmpcodeLast);
+        assertEquals(1, tcpRule.tcpFlagsMask);
+        assertEquals(7, tcpRule.tcpFlagsValue);
+    }
+
+    @Test
+    public void testUdpRule(@InjectTestData(resourcePath = "/rules/udp-rule.json") AccessLists acls) {
+        final AclRule udpRule = createPreBindRule(extractAce(acls));
+        assertEquals(17, udpRule.proto);
+        assertEquals(1, udpRule.srcportOrIcmptypeFirst);
+        assertEquals(5487, udpRule.srcportOrIcmptypeLast);
+        assertEquals(87, udpRule.dstportOrIcmpcodeFirst);
+        assertEquals(6745, udpRule.dstportOrIcmpcodeLast);
+        assertEquals(0, udpRule.tcpFlagsMask);
+        assertEquals(0, udpRule.tcpFlagsValue);
+    }
+
+    @Test
+    public void testOtherRule(@InjectTestData(resourcePath = "/rules/other-rule.json") AccessLists acls) {
+        final AclRule icmpRule = createPreBindRule(extractAce(acls));
+        assertEquals(64, icmpRule.proto);
+        assertEquals(0, icmpRule.srcportOrIcmptypeFirst);
+        assertEquals((short) 65535, icmpRule.srcportOrIcmptypeLast);
+        assertEquals(0, icmpRule.dstportOrIcmpcodeFirst);
+        assertEquals((short) 65535, icmpRule.dstportOrIcmpcodeLast);
+        assertEquals(0, icmpRule.tcpFlagsMask);
+        assertEquals(0, icmpRule.tcpFlagsValue);
+    }
+
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizerTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizerTest.java
new file mode 100644 (file)
index 0000000..cd26197
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write;
+
+import io.fd.hc2vpp.acl.AclTestSchemaContext;
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public class InterfaceAclCustomizerTest extends WriterCustomizerTest implements AclTestSchemaContext {
+
+    @Mock
+    private FutureJVppAclFacade aclApi;
+
+    @Override
+    protected void setUpTest() throws Exception {
+
+    }
+
+    @Test
+    public void writeCurrentAttributes() throws Exception {
+
+    }
+
+    @Test
+    public void updateCurrentAttributes() throws Exception {
+
+    }
+
+    @Test
+    public void deleteCurrentAttributes() throws Exception {
+
+    }
+
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java
new file mode 100644 (file)
index 0000000..d076311
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.acl.write;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.acl.AclTestSchemaContext;
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.acl.dto.AclAddReplace;
+import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply;
+import io.fd.vpp.jvpp.acl.dto.AclDel;
+import io.fd.vpp.jvpp.acl.dto.AclDelReply;
+import io.fd.vpp.jvpp.acl.dto.MacipAclAdd;
+import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import io.fd.vpp.jvpp.acl.types.AclRule;
+import io.fd.vpp.jvpp.acl.types.MacipAclRule;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppAcl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class VppAclCustomizerTest extends WriterCustomizerTest implements AclTestSchemaContext {
+
+    @Mock
+    private FutureJVppAclFacade aclApi;
+
+    @Captor
+    private ArgumentCaptor<AclAddReplace> aclAddReplaceRequestCaptor;
+
+    @Captor
+    private ArgumentCaptor<MacipAclAdd> macipAclAddReplaceRequestCaptor;
+
+    @Captor
+    private ArgumentCaptor<AclDel> aclDelRequestCaptor;
+
+    private InstanceIdentifier<Acl> validId;
+    private InstanceIdentifier<Acl> validMacipId;
+    private VppAclCustomizer aclCustomizer;
+    private NamingContext standardAclContext;
+    private NamingContext macIpAclContext;
+
+
+    @Override
+    protected void setUpTest() throws Exception {
+        validId =
+                InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey("standard-acl", VppAcl.class));
+        validMacipId =
+                InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey("macip-acl", VppAcl.class));
+        standardAclContext = new NamingContext("acl", "acl-context");
+        macIpAclContext = new NamingContext("macip", "macip-context");
+        aclCustomizer = new VppAclCustomizer(aclApi, standardAclContext, macIpAclContext);
+
+        when(aclApi.aclAddReplace(any())).thenReturn(future(new AclAddReplaceReply()));
+        when(aclApi.aclDel(any())).thenReturn(future(new AclDelReply()));
+        when(aclApi.macipAclAdd(any())).thenReturn(future(new MacipAclAddReply()));
+    }
+
+    @Test
+    public void writeCurrentAttributesMacip(@InjectTestData(resourcePath = "/acl/macip/macip-acl.json")
+                                                    AccessLists macipAcl) throws WriteFailedException {
+
+        aclCustomizer.writeCurrentAttributes(validMacipId, macipAcl.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).macipAclAdd(macipAclAddReplaceRequestCaptor.capture());
+
+        final MacipAclAdd request = macipAclAddReplaceRequestCaptor.getValue();
+
+        assertEquals(1, request.count);
+        assertTrue(Arrays.equals("macip-acl".getBytes(), request.tag));
+
+        final MacipAclRule rule = request.r[0];
+
+        assertEquals(0, rule.isIpv6);
+        assertEquals(1, rule.isPermit);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 2}, rule.srcIpAddr));
+        assertEquals(32, rule.srcIpPrefixLen);
+        assertTrue(Arrays.equals(new byte[]{(byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa}, rule.srcMac));
+        assertTrue(Arrays.equals(new byte[]{(byte)0xff, 0, 0, 0, 0, 0}, rule.srcMacMask));
+    }
+
+    @Test
+    public void writeCurrentAttributesIcmpIpv4(@InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json")
+                                                       AccessLists standardAcls) throws Exception {
+        aclCustomizer.writeCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyIcmpIpv4Request(-1);
+    }
+
+    @Test
+    public void updateCurrentAttributesIcmpIpv4(@InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json")
+                                                        AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        final Acl data = standardAcls.getAcl().get(0);
+
+        aclCustomizer.updateCurrentAttributes(validId, data, data, writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyIcmpIpv4Request(4);
+    }
+
+
+    @Test
+    public void writeCurrentAttributesIcmpIpv6(@InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp-v6.json")
+                                                       AccessLists standardAcls) throws Exception {
+        aclCustomizer.writeCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyIcmpv6Request(-1);
+    }
+
+    @Test
+    public void updateCurrentAttributesIcmpIpv6(
+            @InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp-v6.json")
+                    AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        final Acl data = standardAcls.getAcl().get(0);
+        aclCustomizer.updateCurrentAttributes(validId, data, data, writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyIcmpv6Request(4);
+    }
+
+
+    @Test
+    public void writeCurrentAttributesTcp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-tcp.json")
+                                                  AccessLists standardAcls) throws Exception {
+        aclCustomizer.writeCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyTcpRequest(-1);
+    }
+
+    @Test
+    public void updateCurrentAttributesTcp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-tcp.json")
+                                                   AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        final Acl data = standardAcls.getAcl().get(0);
+        aclCustomizer.updateCurrentAttributes(validId, data, data, writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyTcpRequest(4);
+    }
+
+
+    @Test
+    public void writeCurrentAttributesUdp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-udp.json")
+                                                  AccessLists standardAcls) throws Exception {
+        aclCustomizer.writeCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+
+        verifyUdpRequest(-1);
+    }
+
+    @Test
+    public void updateCurrentAttributesUdp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-udp.json")
+                                                   AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        final Acl data = standardAcls.getAcl().get(0);
+        aclCustomizer.updateCurrentAttributes(validId, data, data, writeContext);
+
+        verify(aclApi, times(1)).aclAddReplace(aclAddReplaceRequestCaptor.capture());
+        verifyUdpRequest(4);
+    }
+
+
+    @Test
+    public void deleteCurrentAttributesIcmpIpv4(@InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json")
+                                                        AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        aclCustomizer.deleteCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclDel(aclDelRequestCaptor.capture());
+        assertEquals(4, aclDelRequestCaptor.getValue().aclIndex);
+    }
+
+    @Test
+    public void deleteCurrentAttributesIcmpIpv6(
+            @InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp-v6.json")
+                    AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        aclCustomizer.deleteCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclDel(aclDelRequestCaptor.capture());
+        assertEquals(4, aclDelRequestCaptor.getValue().aclIndex);
+    }
+
+    @Test
+    public void deleteCurrentAttributesTcp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-tcp.json")
+                                                   AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        aclCustomizer.deleteCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclDel(aclDelRequestCaptor.capture());
+        assertEquals(4, aclDelRequestCaptor.getValue().aclIndex);
+    }
+
+    @Test
+    public void deleteCurrentAttributesUdp(@InjectTestData(resourcePath = "/acl/standard/standard-acl-udp.json")
+                                                   AccessLists standardAcls) throws Exception {
+        defineMapping(mappingContext, "standard-acl", 4, "acl-context");
+        aclCustomizer.deleteCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
+
+        verify(aclApi, times(1)).aclDel(aclDelRequestCaptor.capture());
+        assertEquals(4, aclDelRequestCaptor.getValue().aclIndex);
+    }
+
+    private void verifyUdpRequest(final int aclIndex) {
+        final AclAddReplace request = aclAddReplaceRequestCaptor.getValue();
+        assertEquals(aclIndex, request.aclIndex);
+        assertEquals(1, request.count);
+        assertTrue(Arrays.equals("standard-acl".getBytes(), request.tag));
+
+        final AclRule udpRule = request.r[0];
+
+        assertEquals(0, udpRule.isIpv6);
+        assertEquals(1, udpRule.isPermit);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 2}, udpRule.srcIpAddr));
+        assertEquals(32, udpRule.srcIpPrefixLen);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 1}, udpRule.dstIpAddr));
+        assertEquals(24, udpRule.dstIpPrefixLen);
+
+        assertEquals(17, udpRule.proto);
+        assertEquals(1, udpRule.srcportOrIcmptypeFirst);
+        assertEquals(5487, udpRule.srcportOrIcmptypeLast);
+        assertEquals(87, udpRule.dstportOrIcmpcodeFirst);
+        assertEquals(6745, udpRule.dstportOrIcmpcodeLast);
+        assertEquals(0, udpRule.tcpFlagsMask);
+        assertEquals(0, udpRule.tcpFlagsValue);
+    }
+
+    private void verifyTcpRequest(final int aclIndex) {
+        final AclAddReplace request = aclAddReplaceRequestCaptor.getValue();
+        assertEquals(aclIndex, request.aclIndex);
+        assertEquals(1, request.count);
+        assertTrue(Arrays.equals("standard-acl".getBytes(), request.tag));
+
+        final AclRule tcpRule = request.r[0];
+
+        assertEquals(0, tcpRule.isIpv6);
+        assertEquals(1, tcpRule.isPermit);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 2}, tcpRule.srcIpAddr));
+        assertEquals(32, tcpRule.srcIpPrefixLen);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 1}, tcpRule.dstIpAddr));
+        assertEquals(24, tcpRule.dstIpPrefixLen);
+
+        assertEquals(6, tcpRule.proto);
+        assertEquals(1, tcpRule.srcportOrIcmptypeFirst);
+        assertEquals(5487, tcpRule.srcportOrIcmptypeLast);
+        assertEquals(87, tcpRule.dstportOrIcmpcodeFirst);
+        assertEquals(6745, tcpRule.dstportOrIcmpcodeLast);
+        assertEquals(1, tcpRule.tcpFlagsMask);
+        assertEquals(7, tcpRule.tcpFlagsValue);
+    }
+
+    private void verifyIcmpv6Request(final int aclIndex) {
+        final AclAddReplace request = aclAddReplaceRequestCaptor.getValue();
+        assertEquals(aclIndex, request.aclIndex);
+        assertEquals(1, request.count);
+        assertTrue(Arrays.equals("standard-acl".getBytes(), request.tag));
+
+        final AclRule icmpv6Rule = request.r[0];
+
+        assertEquals(1, icmpv6Rule.isIpv6);
+        assertEquals(1, icmpv6Rule.isPermit);
+        assertTrue(
+                Arrays.equals(new byte[]{32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 2},
+                        icmpv6Rule.srcIpAddr));
+        assertEquals(48, icmpv6Rule.srcIpPrefixLen);
+        assertTrue(
+                Arrays.equals(new byte[]{32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1},
+                        icmpv6Rule.dstIpAddr));
+        assertEquals(64, icmpv6Rule.dstIpPrefixLen);
+
+        assertEquals(58, icmpv6Rule.proto);
+        assertEquals(5, icmpv6Rule.srcportOrIcmptypeFirst);
+        assertEquals(8, icmpv6Rule.srcportOrIcmptypeLast);
+        assertEquals(1, icmpv6Rule.dstportOrIcmpcodeFirst);
+        assertEquals(3, icmpv6Rule.dstportOrIcmpcodeLast);
+        assertEquals(0, icmpv6Rule.tcpFlagsMask);
+        assertEquals(0, icmpv6Rule.tcpFlagsValue);
+    }
+
+    private void verifyIcmpIpv4Request(final int aclIndex) {
+        final AclAddReplace request = aclAddReplaceRequestCaptor.getValue();
+        assertEquals(aclIndex, request.aclIndex);
+        assertEquals(1, request.count);
+        assertTrue(Arrays.equals("standard-acl".getBytes(), request.tag));
+
+        final AclRule icmpRule = request.r[0];
+
+        assertEquals(0, icmpRule.isIpv6);
+        assertEquals(1, icmpRule.isPermit);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 2}, icmpRule.srcIpAddr));
+        assertEquals(32, icmpRule.srcIpPrefixLen);
+        assertTrue(Arrays.equals(new byte[]{-64, -88, 2, 1}, icmpRule.dstIpAddr));
+        assertEquals(24, icmpRule.dstIpPrefixLen);
+
+        assertEquals(1, icmpRule.proto);
+        assertEquals(5, icmpRule.srcportOrIcmptypeFirst);
+        assertEquals(8, icmpRule.srcportOrIcmptypeLast);
+        assertEquals(1, icmpRule.dstportOrIcmpcodeFirst);
+        assertEquals(3, icmpRule.dstportOrIcmpcodeLast);
+        assertEquals(0, icmpRule.tcpFlagsMask);
+        assertEquals(0, icmpRule.tcpFlagsValue);
+    }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/acl/macip/macip-acl.json b/acl/acl-impl/src/test/resources/acl/macip/macip-acl.json
new file mode 100644 (file)
index 0000000..b944cd7
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "macip-acl",
+        "acl-type": "vpp-acl:vpp-macip-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "macip-rule",
+              "matches": {
+                "vpp-macip-ace-nodes": {
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "source-mac-address": "aa:aa:aa:aa:aa:aa",
+                  "source-mac-address-mask": "ff:00:00:00:00:00"
+                }
+              },
+              "actions": {
+                "permit": {}
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp-v6.json b/acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp-v6.json
new file mode 100644 (file)
index 0000000..08bc615
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-v6-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv6-network": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+                  "source-ipv6-network": "2001:0db8:0a0b:12f0:0000:0000:0000:0002/48",
+                  "icmp-v6-nodes": {
+                    "icmp-type-range": {
+                      "first": "5",
+                      "last": "8"
+                    },
+                    "icmp-code-range": {
+                      "first": "1",
+                      "last": "3"
+                    }
+                  }
+                }
+              },
+              "actions": {
+                "permit": {}
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp.json b/acl/acl-impl/src/test/resources/acl/standard/standard-acl-icmp.json
new file mode 100644 (file)
index 0000000..ce6ff7c
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/24",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "icmp-nodes": {
+                    "icmp-type-range": {
+                      "first": "5",
+                      "last": "8"
+                    },
+                    "icmp-code-range": {
+                      "first": "1",
+                      "last": "3"
+                    }
+                  }
+                }
+              },
+              "actions": {
+                "permit": {}
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/acl/standard/standard-acl-tcp.json b/acl/acl-impl/src/test/resources/acl/standard/standard-acl-tcp.json
new file mode 100644 (file)
index 0000000..f0a1309
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "tcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/24",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "tcp-nodes": {
+                    "source-port-range": {
+                      "lower-port": "1",
+                      "upper-port": "5487"
+                    },
+                    "destination-port-range": {
+                      "lower-port": "87",
+                      "upper-port": "6745"
+                    },
+                    "tcp-flags-mask": "1",
+                    "tcp-flags-value": "7"
+                  }
+                }
+              },
+              "actions": {
+                "permit": {}
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/acl/standard/standard-acl-udp.json b/acl/acl-impl/src/test/resources/acl/standard/standard-acl-udp.json
new file mode 100644 (file)
index 0000000..77dafeb
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "udp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/24",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "udp-nodes": {
+                    "source-port-range": {
+                      "lower-port": "1",
+                      "upper-port": "5487"
+                    },
+                    "destination-port-range": {
+                      "lower-port": "87",
+                      "upper-port": "6745"
+                    }
+                  }
+                }
+              },
+              "actions": {
+                "permit": {}
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/rules/icmp-rule.json b/acl/acl-impl/src/test/resources/rules/icmp-rule.json
new file mode 100644 (file)
index 0000000..330a448
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/32",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "icmp-nodes": {
+                    "icmp-type-range": {
+                      "first": "5",
+                      "last": "8"
+                    },
+                    "icmp-code-range": {
+                      "first": "1",
+                      "last": "3"
+                    }
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/rules/icmp-v6-rule.json b/acl/acl-impl/src/test/resources/rules/icmp-v6-rule.json
new file mode 100644 (file)
index 0000000..9ea82a1
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv6-network": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+                  "source-ipv6-network": "2001:0db8:0a0b:12f0:0000:0000:0000:0002/64",
+                  "icmp-v6-nodes": {
+                    "icmp-type-range": {
+                      "first": "5",
+                      "last": "8"
+                    },
+                    "icmp-code-range": {
+                      "first": "1",
+                      "last": "3"
+                    }
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/rules/other-rule.json b/acl/acl-impl/src/test/resources/rules/other-rule.json
new file mode 100644 (file)
index 0000000..0e60dcc
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/32",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "other-nodes": {
+                    "protocol": "64"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/rules/tcp-rule.json b/acl/acl-impl/src/test/resources/rules/tcp-rule.json
new file mode 100644 (file)
index 0000000..de3697e
--- /dev/null
@@ -0,0 +1,35 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/32",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "tcp-nodes": {
+                    "source-port-range": {
+                      "lower-port": "1",
+                      "upper-port": "5487"
+                    },
+                    "destination-port-range": {
+                      "lower-port": "87",
+                      "upper-port": "6745"
+                    },
+                    "tcp-flags-mask": "1",
+                    "tcp-flags-value": "7"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/rules/udp-rule.json b/acl/acl-impl/src/test/resources/rules/udp-rule.json
new file mode 100644 (file)
index 0000000..4bc05d4
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "access-lists": {
+    "acl": [
+      {
+        "acl-name": "standard-acl",
+        "acl-type": "vpp-acl:vpp-acl",
+        "access-list-entries": {
+          "ace": [
+            {
+              "rule-name": "imcp-rule",
+              "matches": {
+                "vpp-ace-nodes": {
+                  "destination-ipv4-network": "192.168.2.1/32",
+                  "source-ipv4-network": "192.168.2.2/32",
+                  "udp-nodes": {
+                    "source-port-range": {
+                      "lower-port": "1",
+                      "upper-port": "5487"
+                    },
+                    "destination-port-range": {
+                      "lower-port": "87",
+                      "upper-port": "6745"
+                    }
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
index 2ad6bc3..8f16096 100644 (file)
@@ -29,6 +29,7 @@
 
   <modules>
     <module>acl-api</module>
+    <module>acl-impl</module>
   </modules>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
index a0d292a..3365dab 100644 (file)
@@ -58,8 +58,6 @@ public interface InterfaceDataTranslator extends ByteDataTranslator, JvppReplyCo
     Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000));
     Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000));
 
-    char[] HEX_CHARS = "0123456789abcdef".toCharArray();
-
     int PHYSICAL_ADDRESS_LENGTH = 6;
 
     Collector<SwInterfaceDetails, ?, SwInterfaceDetails> SINGLE_ITEM_COLLECTOR =
@@ -90,12 +88,6 @@ public interface InterfaceDataTranslator extends ByteDataTranslator, JvppReplyCo
         }
     }
 
-    default void appendHexByte(final StringBuilder sb, final byte b) {
-        final int v = b & 0xFF;
-        sb.append(HEX_CHARS[v >>> 4]);
-        sb.append(HEX_CHARS[v & 15]);
-    }
-
     /**
      * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates <p> Replace later with
      * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/
@@ -119,23 +111,6 @@ public interface InterfaceDataTranslator extends ByteDataTranslator, JvppReplyCo
         return printHexBinary(vppPhysAddress, startIndex, endIndex);
     }
 
-    default String printHexBinary(@Nonnull final byte[] bytes) {
-        Objects.requireNonNull(bytes, "bytes array should not be null");
-        return printHexBinary(bytes, 0, bytes.length);
-    }
-
-    default String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
-        StringBuilder str = new StringBuilder();
-
-        appendHexByte(str, bytes[startIndex]);
-        for (int i = startIndex + 1; i < endIndex; i++) {
-            str.append(":");
-            appendHexByte(str, bytes[i]);
-        }
-
-        return str.toString();
-    }
-
     /**
      * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from
      * VPP's interface index to YANG's interface index.
index 17aff0e..d24157b 100644 (file)
 
 package io.fd.hc2vpp.common.translate.util;
 
+import java.util.Objects;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 /**
- * Trait providing logic for working with binary-based data
+ * Trait providing logic for working with binary/hex-based data
  */
 public interface ByteDataTranslator {
 
+    char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
     ByteDataTranslator INSTANCE = new ByteDataTranslator() {
     };
 
@@ -70,6 +73,8 @@ public interface ByteDataTranslator {
         } else if (value == BYTE_TRUE) {
             return Boolean.TRUE;
         }
+
+    char[] HEX_CHARS = "0123456789abcdef".toCharArray();
         throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value));
     }
 
@@ -90,6 +95,8 @@ public interface ByteDataTranslator {
     }
 
     /**
+
+    char[] HEX_CHARS = "0123456789abcdef".toCharArray();
      * Return (interned) string from byte array while removing \u0000. Strings represented as fixed length byte[] from
      * vpp contain \u0000.
      */
@@ -105,4 +112,27 @@ public interface ByteDataTranslator {
     default int toJavaByte(final byte vppByte) {
         return Byte.toUnsignedInt(vppByte);
     }
+
+    default String printHexBinary(@Nonnull final byte[] bytes) {
+        Objects.requireNonNull(bytes, "bytes array should not be null");
+        return printHexBinary(bytes, 0, bytes.length);
+    }
+
+    default String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
+        StringBuilder str = new StringBuilder();
+
+        appendHexByte(str, bytes[startIndex]);
+        for (int i = startIndex + 1; i < endIndex; i++) {
+            str.append(":");
+            appendHexByte(str, bytes[i]);
+        }
+
+        return str.toString();
+    }
+
+    default void appendHexByte(final StringBuilder sb, final byte b) {
+        final int v = b & 0xFF;
+        sb.append(HEX_CHARS[v >>> 4]);
+        sb.append(HEX_CHARS[v & 15]);
+    }
 }
index 05da926..ffef786 100644 (file)
     <nat.version>1.17.01-SNAPSHOT</nat.version>
     <ioam.version>1.17.01-SNAPSHOT</ioam.version>
     <routing.version>1.17.01-SNAPSHOT</routing.version>
+    <acl.version>1.17.01-SNAPSHOT</acl.version>
 
     <distribution.modules>
       io.fd.hc2vpp.common.integration.VppCommonModule,
       io.fd.hc2vpp.lisp.LispModule,
       io.fd.hc2vpp.v3po.V3poModule,
-      io.fd.hc2vpp.v3po.ClassifierIetfAclModule,
+      // io.fd.hc2vpp.v3po.ClassifierIetfAclModule,
+      <!-- Classifier Acl's module disabled by default, can't run in the same time with AclModule -->
       io.fd.hc2vpp.nat.NatModule,
       io.fd.hc2vpp.routing.RoutingModule,
+      io.fd.hc2vpp.acl.AclModule,
       // io.fd.hc2vpp.vppnsh.impl.VppNshModule,
       <!-- Nsh module by default disabled, because it needs vpp-nsh plugin, which is not part of vpp codebase.-->
       // io.fd.hc2vpp.vppioam.impl.VppIoamModule
       <artifactId>vppioam-impl</artifactId>
       <version>${ioam.version}</version>
     </dependency>
+    <dependency>
+      <groupId>io.fd.hc2vpp.acl</groupId>
+      <artifactId>acl-impl</artifactId>
+      <version>${acl.version}</version>
+    </dependency>
   </dependencies>
 </project>