summaryrefslogtreecommitdiffstats
path: root/vpp-classifier/impl/src/main/java/io/fd
diff options
context:
space:
mode:
authorJan Srnicek <jsrnicek@cisco.com>2017-03-08 14:01:34 +0100
committerMarek Gradzki <mgradzki@cisco.com>2017-03-09 07:09:36 +0000
commitbf1d5db448edc1ae352960f14bca9ccb41612186 (patch)
treecdf6f5feebf650050bde23ffe7a9a2f8d6389a94 /vpp-classifier/impl/src/main/java/io/fd
parent6532b1524bb841cac2b559415b85ac6e9d2ff934 (diff)
HC2VPP-7 - split vpp-classifiers to separate module
Split vpp-classifiers and vpp-classifiers acls' to separate modules. Contains TODO's for future change of dependencies Change-Id: I94f92ce2ec8960c67bd406f085f2fe928079ee23 Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'vpp-classifier/impl/src/main/java/io/fd')
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierAclModule.java39
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierIetfAclModule.java32
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierAclModule.java37
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierIetfAclModule.java32
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierAclModule.java46
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierModule.java55
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManager.java106
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManagerImpl.java181
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/InterfaceAclReaderFactory.java76
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/SubInterfaceAclReaderFactory.java83
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/VppClassifierReaderFactory.java60
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/AclWriterFactory.java57
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfaceAclWriterFactory.java77
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfacesClassifierIetfAclWriterFactory.java81
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfaceAclWriterFactory.java78
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfacesClassifierIetfAclWriterFactory.java89
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/VppClassifierHoneycombWriterFactory.java64
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/EgressIetfAClWriterProvider.java39
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/IngressIetfAClWriterProvider.java39
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifySessionReader.java212
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifyTableReader.java177
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/VppNodeReader.java46
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclCustomizer.java119
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclReader.java60
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/SubInterfaceAclCustomizer.java122
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriter.java165
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifyTableWriter.java150
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/VppNodeWriter.java80
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/IetfAclWriter.java105
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AbstractIetfAclWriter.java252
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceEthWriter.java85
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp4Writer.java94
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp6Writer.java99
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIpAndEthWriter.java132
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceWriter.java54
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManager.java53
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManagerImpl.java68
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTranslator.java74
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/IetfAclWriter.java47
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip4AclTranslator.java149
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip6AclTranslator.java182
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/L2AclTranslator.java90
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/PortPair.java126
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/EgressIetfAclWriter.java120
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/IetfAclCustomizer.java85
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/SubInterfaceIetfAclCustomizer.java105
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclCustomizer.java83
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclWriter.java73
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IetfAclCustomizer.java89
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IngressIetfAclWriter.java118
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceAclCustomizer.java93
-rw-r--r--vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceIetfAclCustomizer.java108
52 files changed, 4886 insertions, 0 deletions
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierAclModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierAclModule.java
new file mode 100644
index 000000000..cf8a35a85
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierAclModule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.vpp.classifier.factory.read.InterfaceAclReaderFactory;
+import io.fd.hc2vpp.vpp.classifier.factory.write.InterfaceAclWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+
+public class InterfaceClassifierAclModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(InterfaceAclWriterFactory.class);
+
+ // Readers
+ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readerFactoryBinder.addBinding().to(InterfaceAclReaderFactory.class);
+
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierIetfAclModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierIetfAclModule.java
new file mode 100644
index 000000000..643abd5c2
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/InterfaceClassifierIetfAclModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.vpp.classifier.factory.write.InterfacesClassifierIetfAclWriterFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+
+public class InterfaceClassifierIetfAclModule extends AbstractModule{
+
+ @Override
+ protected void configure() {
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(InterfacesClassifierIetfAclWriterFactory.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierAclModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierAclModule.java
new file mode 100644
index 000000000..018514085
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierAclModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.vpp.classifier.factory.read.SubInterfaceAclReaderFactory;
+import io.fd.hc2vpp.vpp.classifier.factory.write.SubInterfaceAclWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+
+public class SubInterfaceClassifierAclModule extends AbstractModule{
+ @Override
+ protected void configure() {
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(SubInterfaceAclWriterFactory.class);
+
+ // Readers
+ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readerFactoryBinder.addBinding().to(SubInterfaceAclReaderFactory.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierIetfAclModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierIetfAclModule.java
new file mode 100644
index 000000000..338624bc6
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/SubInterfaceClassifierIetfAclModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.vpp.classifier.factory.write.SubInterfacesClassifierIetfAclWriterFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+
+public class SubInterfaceClassifierIetfAclModule extends AbstractModule{
+
+ @Override
+ protected void configure() {
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(SubInterfacesClassifierIetfAclWriterFactory.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierAclModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierAclModule.java
new file mode 100644
index 000000000..3b2cdb975
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierAclModule.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.vpp.classifier.factory.write.AclWriterFactory;
+import io.fd.hc2vpp.vpp.classifier.provider.EgressIetfAClWriterProvider;
+import io.fd.hc2vpp.vpp.classifier.provider.IngressIetfAClWriterProvider;
+import io.fd.hc2vpp.vpp.classifier.write.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.IngressIetfAclWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppClassifierAclModule extends AbstractModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VppClassifierAclModule.class);
+
+ @Override
+ protected void configure() {
+ // Utils
+ bind(IngressIetfAclWriter.class).toProvider(IngressIetfAClWriterProvider.class);
+ bind(EgressIetfAclWriter.class).toProvider(EgressIetfAClWriterProvider.class);
+
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(AclWriterFactory.class);
+
+ LOG.info("Module VppClassifierAcl module successfully configured");
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierModule.java
new file mode 100644
index 000000000..088df72c2
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierModule.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManagerImpl;
+import io.fd.hc2vpp.vpp.classifier.factory.read.VppClassifierReaderFactory;
+import io.fd.hc2vpp.vpp.classifier.factory.write.VppClassifierHoneycombWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import net.jmob.guice.conf.core.ConfigurationModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppClassifierModule extends AbstractModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VppClassifierModule.class);
+
+ @Override
+ protected void configure() {
+ LOG.debug("Installing VppClassifierAcl module");
+ install(ConfigurationModule.create());
+
+ bind(VppClassifierContextManager.class)
+ .annotatedWith(Names.named("classify-table-context"))
+ .toInstance(new VppClassifierContextManagerImpl("classify-table-"));
+
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(VppClassifierHoneycombWriterFactory.class);
+
+ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readerFactoryBinder.addBinding().to(VppClassifierReaderFactory.class);
+
+ // Expose vpp-classfier-context interfaces in operational data
+ readerFactoryBinder.addBinding().to(VppClassifierContextManagerImpl.ContextsReaderFactory.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManager.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManager.java
new file mode 100644
index 000000000..b30f1ee55
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.context;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+
+/**
+ * Manages metadata for vpp-classifier
+ */
+public interface VppClassifierContextManager {
+
+ /**
+ * Creates metadata for classify table.
+ *
+ * @param id classify table index
+ * @param name classify table name
+ * @param classifierNode name of VPP node the table is defined for
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+ @Nonnull final MappingContext ctx);
+
+ /**
+ * Check whether metadata for given classify table metadata is present.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return true if present, false otherwise
+ */
+ boolean containsTable(@Nonnull String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Returns classify table index associated with the given name.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return integer index value matching supplied classify table name
+ * @throws IllegalArgumentException if classify table was not found
+ */
+ int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Retrieves classify table name for given id. If not present, artificial name will be generated.
+ *
+ * @param id classify table index
+ * @param ctx mapping context providing context data for current transaction
+ * @return classify table name matching supplied index
+ */
+ String getTableName(final int id, @Nonnull final MappingContext ctx);
+
+ /**
+ * Returns name of the base vpp node associated with the classify table.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return name of VPP node the table is defined for
+ */
+ Optional<String> getTableBaseNode(final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Removes classify table metadata from current context.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Adds relative node index to node name mapping for given classify table.
+ *
+ * @param tableName classify table name
+ * @param nodeIndex index of a vpp node, relative to table's base node
+ * @param nodeName name of a vpp node
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void addNodeName(@Nonnull String tableName, final int nodeIndex, @Nonnull final String nodeName,
+ @Nonnull final MappingContext ctx);
+
+ /**
+ * Retrieves node name associated with the given classify table and node index.
+ *
+ * @param tableIndex classify table index
+ * @param nodeIndex relative index of a vpp node
+ * @param ctx mapping context providing context data for current transaction
+ * @return name of vpp node
+ */
+ Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx);
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManagerImpl.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManagerImpl.java
new file mode 100644
index 000000000..a74746864
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/context/VppClassifierContextManagerImpl.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.context;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import java.util.List;
+import java.util.stream.Collector;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Named;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Facade on top of {@link MappingContext} that manages {@link ClassifyTableContext}.
+ */
+public final class VppClassifierContextManagerImpl implements VppClassifierContextManager {
+ private static final Collector<ClassifyTableContext, ?, ClassifyTableContext> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ @VisibleForTesting
+ static final InstanceIdentifier<VppClassifierContext>
+ VPP_CLASSIFIER_CONTEXT_IID = KeyedInstanceIdentifier.create(VppClassifierContext.class);
+ private final String artificialNamePrefix;
+
+ /**
+ * Creates new VppClassifierContextManagerImpl.
+ *
+ * @param artificialNamePrefix artificial name to be used to generate names for classify tables without existing
+ * metadata
+ */
+ public VppClassifierContextManagerImpl(@Nonnull final String artificialNamePrefix) {
+ this.artificialNamePrefix =
+ Preconditions.checkNotNull(artificialNamePrefix, "artificialNamePrefix should not be null");
+ }
+
+ private KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> getMappingIid(final String name) {
+ return VPP_CLASSIFIER_CONTEXT_IID.child(ClassifyTableContext.class, new ClassifyTableContextKey(name));
+ }
+
+ @Override
+ public void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+ @Nonnull final MappingContext ctx) {
+ final KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> mappingIid = getMappingIid(name);
+ final ClassifyTableContextBuilder tableCtx = new ClassifyTableContextBuilder().setIndex(id).setName(name);
+ if (classifierNode != null) {
+ tableCtx.setClassifierNodeName(classifierNode.getValue());
+ }
+ ctx.put(mappingIid, tableCtx.build());
+ }
+
+ @Override
+ public boolean containsTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ return read.isPresent();
+ }
+
+ @Override
+ public int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ checkArgument(read.isPresent(), "No mapping stored for name: %s", name);
+ return read.get().getIndex();
+ }
+
+ @Override
+ public String getTableName(final int id, @Nonnull final MappingContext ctx) {
+ if (!containsName(id, ctx)) {
+ final String artificialName = getArtificialName(id);
+ addTable(id, artificialName, null, ctx);
+ }
+
+ final Optional<VppClassifierContext> read = ctx.read(VPP_CLASSIFIER_CONTEXT_IID);
+ checkState(read.isPresent(), "VppClassifierContext for index: %s is not present. But should be", id);
+
+ return read.get().getClassifyTableContext().stream()
+ .filter(t -> t.getIndex().equals(id))
+ .collect(SINGLE_ITEM_COLLECTOR).getName();
+ }
+
+ private boolean containsName(final int index, @Nonnull final MappingContext mappingContext) {
+ final Optional<VppClassifierContext> read = mappingContext.read(VPP_CLASSIFIER_CONTEXT_IID);
+ return read.isPresent()
+ ? read.get().getClassifyTableContext().stream().anyMatch(t -> t.getIndex().equals(index))
+ : false;
+ }
+
+ @Override
+ public Optional<String> getTableBaseNode(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ if (read.isPresent()) {
+ return Optional.fromNullable(read.get().getClassifierNodeName());
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ ctx.delete(getMappingIid(name));
+ }
+
+ @Override
+ public void addNodeName(@Nonnull final String tableName, final int nodeIndex,
+ @Nonnull final String nodeName,
+ @Nonnull final MappingContext ctx) {
+ final KeyedInstanceIdentifier<NodeContext, NodeContextKey> iid =
+ getMappingIid(tableName).child(NodeContext.class, new NodeContextKey(nodeName));
+ ctx.put(iid, new NodeContextBuilder().setName(nodeName).setIndex(nodeIndex).build());
+ }
+
+ @Override
+ public Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx) {
+ if (!containsName(tableIndex, ctx)) {
+ return Optional.absent();
+ }
+ final String tableName = getTableName(tableIndex, ctx);
+ final Optional<ClassifyTableContext> tableCtx = ctx.read(getMappingIid(tableName));
+ final List<NodeContext> nodeContext = tableCtx.get().getNodeContext();
+ if (nodeContext == null) {
+ return Optional.absent();
+ }
+ return Optional.fromNullable(nodeContext.stream()
+ .filter(n -> n.getIndex().equals(nodeIndex))
+ .findFirst()
+ .map(nodes -> nodes.getName())
+ .orElse(null));
+ }
+
+ private String getArtificialName(final int index) {
+ return artificialNamePrefix + index;
+ }
+
+ public static final class ContextsReaderFactory implements ReaderFactory {
+
+ @Inject
+ @Named("honeycomb-context")
+ private DataBroker contextBindingBrokerDependency;
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ registry.add(new BindingBrokerReader<>(VPP_CLASSIFIER_CONTEXT_IID,
+ contextBindingBrokerDependency,
+ LogicalDatastoreType.OPERATIONAL, VppClassifierContextBuilder.class));
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/InterfaceAclReaderFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/InterfaceAclReaderFactory.java
new file mode 100644
index 000000000..f11a475f2
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/InterfaceAclReaderFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.read;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.read.acl.AclCustomizer;
+import io.fd.honeycomb.translate.impl.read.GenericInitReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.vpp._interface.acl.rev161214.VppInterfaceAclStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp._interface.acl.rev161214.VppInterfaceAclStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.IngressBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceAclReaderFactory implements ReaderFactory{
+
+ private static final InstanceIdentifier<Interface> IFC_ID =
+ InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ private static final InstanceIdentifier<VppInterfaceAclStateAugmentation> VPP_IFC_AUG_ID =
+ IFC_ID.augmentation(VppInterfaceAclStateAugmentation.class);
+
+ @Inject
+ private FutureJVppCore jvpp;
+
+ @Inject
+ @Named("interface-context")
+ private NamingContext ifcNamingContext;
+
+ @Inject
+ @Named("classify-table-context")
+ private VppClassifierContextManager classifyTableContext;
+
+ @Override
+ public void init(@Nonnull ModifiableReaderRegistryBuilder registry) {
+ // Acl augmentation(structural)
+ registry.addStructuralReader(VPP_IFC_AUG_ID, VppInterfaceAclStateAugmentationBuilder.class);
+ // Acl(Structural)
+ final InstanceIdentifier<Acl> aclIid = VPP_IFC_AUG_ID.child(Acl.class);
+ registry.addStructuralReader(aclIid, AclBuilder.class);
+ // Ingress(Subtree)
+ final InstanceIdentifier<Ingress> ingressIdRelative = InstanceIdentifier.create(Ingress.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(ingressIdRelative.child(L2Acl.class), ingressIdRelative.child(Ip4Acl.class),
+ ingressIdRelative.child(Ip6Acl.class)),
+ new GenericInitReader<Ingress,IngressBuilder>(aclIid.child(Ingress.class),
+ new AclCustomizer(jvpp, ifcNamingContext, classifyTableContext)));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/SubInterfaceAclReaderFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/SubInterfaceAclReaderFactory.java
new file mode 100644
index 000000000..f93e0e79b
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/SubInterfaceAclReaderFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.read;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.read.acl.SubInterfaceAclCustomizer;
+import io.fd.honeycomb.translate.impl.read.GenericInitReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.subinterface.acl.rev161214.VppSubinterfaceAclStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.subinterface.acl.rev161214.VppSubinterfaceAclStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SubInterfaceAclReaderFactory implements ReaderFactory {
+
+ static final InstanceIdentifier<InterfacesState> IFC_STATE_ID =
+ InstanceIdentifier.create(InterfacesState.class);
+ static final InstanceIdentifier<Interface> IFC_ID = IFC_STATE_ID.child(Interface.class);
+
+ private static final InstanceIdentifier<VppSubinterfaceAclStateAugmentation> SUB_IFC_AUG_ID =
+ IFC_ID.augmentation(SubinterfaceStateAugmentation.class)
+ .child(SubInterfaces.class)
+ .child(SubInterface.class)
+ .augmentation(VppSubinterfaceAclStateAugmentation.class);
+
+ @Inject
+ private FutureJVppCore jvpp;
+
+ @Inject
+ @Named("interface-context")
+ private NamingContext ifcNamingContext;
+
+ @Inject
+ @Named("classify-table-context")
+ private VppClassifierContextManager classifyTableContext;
+
+ @Override
+ public void init(@Nonnull ModifiableReaderRegistryBuilder registry) {
+ // Aug readed(Structural)
+ registry.addStructuralReader(SUB_IFC_AUG_ID, VppSubinterfaceAclStateAugmentationBuilder.class);
+ // Acl(Structural)
+ final InstanceIdentifier<Acl> aclIid = SUB_IFC_AUG_ID.child(Acl.class);
+ registry.addStructuralReader(aclIid, AclBuilder.class);
+ // Ingress(Subtree)
+ final InstanceIdentifier<Ingress> ingressIdRelative = InstanceIdentifier.create(Ingress.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(ingressIdRelative.child(L2Acl.class), ingressIdRelative.child(Ip4Acl.class),
+ ingressIdRelative.child(Ip6Acl.class)),
+ new GenericInitReader<>(aclIid.child(Ingress.class),
+ new SubInterfaceAclCustomizer(jvpp, ifcNamingContext, classifyTableContext)));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/VppClassifierReaderFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/VppClassifierReaderFactory.java
new file mode 100644
index 000000000..46c6e6a6f
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/read/VppClassifierReaderFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.read;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.read.ClassifySessionReader;
+import io.fd.hc2vpp.vpp.classifier.read.ClassifyTableReader;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VppClassifierReaderFactory implements ReaderFactory {
+
+ private final FutureJVppCore jvpp;
+ private final VppClassifierContextManager classifyCtx;
+
+ @Inject
+ public VppClassifierReaderFactory(final FutureJVppCore jvpp,
+ @Named("classify-table-context") final VppClassifierContextManager classifyCtx) {
+ this.jvpp = jvpp;
+ this.classifyCtx = classifyCtx;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+ // VppClassifierState
+ final InstanceIdentifier<VppClassifierState> vppStateId = InstanceIdentifier.create(VppClassifierState.class);
+ registry.addStructuralReader(vppStateId, VppClassifierStateBuilder.class);
+ // ClassifyTable
+ final InstanceIdentifier<ClassifyTable> classTblId = vppStateId.child(ClassifyTable.class);
+ registry.add(new GenericInitListReader<>(classTblId, new ClassifyTableReader(jvpp, classifyCtx)));
+ // ClassifySession
+ final InstanceIdentifier<ClassifySession> classSesId = classTblId.child(ClassifySession.class);
+ registry.add(new GenericListReader<>(classSesId, new ClassifySessionReader(jvpp, classifyCtx)));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/AclWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/AclWriterFactory.java
new file mode 100644
index 000000000..5a13db274
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/AclWriterFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import com.google.common.collect.Sets;
+import io.fd.hc2vpp.vpp.classifier.write.acl.IetfAclWriter;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+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.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.AceIpAndEthNodes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class AclWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<Acl> ACL_ID =
+ InstanceIdentifier.create(AccessLists.class).child(Acl.class);
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+
+ final InstanceIdentifier<Acl> aclIdRelative = InstanceIdentifier.create(Acl.class);
+
+ final InstanceIdentifier<Ace> aceId = aclIdRelative.child(AccessListEntries.class).child(Ace.class);
+ final InstanceIdentifier<Actions> actionsId = aceId.child(Actions.class);
+ final InstanceIdentifier<Matches> matchesId = aceId.child(Matches.class);
+ final InstanceIdentifier<AceIpAndEthNodes> aceIpAndEthId = matchesId.child(AceIpAndEthNodes.class);
+ final InstanceIdentifier<SourcePortRange> srcPortId = matchesId.child((Class)SourcePortRange.class);
+ final InstanceIdentifier<DestinationPortRange> dstPortId = matchesId.child((Class)DestinationPortRange.class);
+
+ registry.subtreeAddBefore(Sets.newHashSet(aceId, actionsId, matchesId, aceIpAndEthId, srcPortId, dstPortId),
+ new GenericListWriter<>(ACL_ID, new IetfAclWriter()),
+ Sets.newHashSet(InterfacesClassifierIetfAclWriterFactory.IETF_ACL_ID, SubInterfacesClassifierIetfAclWriterFactory.SUBIF_IETF_ACL_ID));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfaceAclWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfaceAclWriterFactory.java
new file mode 100644
index 000000000..bc3bc495d
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfaceAclWriterFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import static io.fd.hc2vpp.vpp.classifier.factory.write.VppClassifierHoneycombWriterFactory.CLASSIFY_SESSION_ID;
+import static io.fd.hc2vpp.vpp.classifier.factory.write.VppClassifierHoneycombWriterFactory.CLASSIFY_TABLE_ID;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.AclCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.vpp._interface.acl.rev161214.VppInterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceAclWriterFactory implements WriterFactory {
+
+ private static final InstanceIdentifier<Interface> IFC_ID =
+ InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ private static final InstanceIdentifier<VppInterfaceAclAugmentation> VPP_IFC_ACL_ID =
+ IFC_ID.augmentation(VppInterfaceAclAugmentation.class);
+ static final InstanceIdentifier<Acl> ACL_ID = VPP_IFC_ACL_ID.child(Acl.class);
+ private static final InstanceIdentifier<Ingress> INGRESS_ACL_ID = ACL_ID.child(Ingress.class);
+
+ @Inject
+ private FutureJVppCore jvpp;
+
+ @Inject
+ @Named("interface-context")
+ private NamingContext ifcNamingContext;
+
+ @Inject
+ @Named("classify-table-context")
+ private VppClassifierContextManager classifyTableContext;
+
+
+ @Override
+ public void init(@Nonnull ModifiableWriterRegistryBuilder registry) {
+ // Ingress (execute after classify table and session writers)
+ // also handles L2Acl, Ip4Acl and Ip6Acl:
+ final InstanceIdentifier<Ingress> ingressId = InstanceIdentifier.create(Ingress.class);
+ registry
+ .subtreeAddAfter(
+ Sets.newHashSet(ingressId.child(L2Acl.class), ingressId.child(Ip4Acl.class),
+ ingressId.child(Ip6Acl.class)),
+ new GenericWriter<>(INGRESS_ACL_ID,
+ new AclCustomizer(jvpp, ifcNamingContext, classifyTableContext)),
+ Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfacesClassifierIetfAclWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfacesClassifierIetfAclWriterFactory.java
new file mode 100644
index 000000000..48d782dd2
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/InterfacesClassifierIetfAclWriterFactory.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.write.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.IngressIetfAclWriter;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+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.vpp._interface.acl.rev161214.VppInterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.IetfAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class InterfacesClassifierIetfAclWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<Interface> IFC_ID =
+ InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ public static final InstanceIdentifier<VppInterfaceAclAugmentation> VPP_IFC_AUG_ID =
+ IFC_ID.augmentation(VppInterfaceAclAugmentation.class);
+ public static final InstanceIdentifier<IetfAcl> IETF_ACL_ID = VPP_IFC_AUG_ID.child(IetfAcl.class);
+ public static final InstanceIdentifier<Ingress> INGRESS_IETF_ACL_ID = IETF_ACL_ID.child(Ingress.class);
+ public static final InstanceIdentifier<Egress> EGRESS_IETF_ACL_ID = IETF_ACL_ID.child(Egress.class);
+
+ private final IngressIetfAclWriter ingressAclWriter;
+ private final EgressIetfAclWriter egressAclWriter;
+ private final NamingContext ifcNamingContext;
+
+ @Inject
+ public InterfacesClassifierIetfAclWriterFactory(final IngressIetfAclWriter ingressAclWriter,
+ final EgressIetfAclWriter egressAclWriter,
+ @Named("interface-context") final NamingContext interfaceContextDependency) {
+ this.ingressAclWriter = ingressAclWriter;
+ this.egressAclWriter = egressAclWriter;
+ this.ifcNamingContext = interfaceContextDependency;
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdIngress =
+ InstanceIdentifier.create(Ingress.class).child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdIngress = accessListsIdIngress.child(Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdIngress, aclIdIngress),
+ new GenericWriter<>(INGRESS_IETF_ACL_ID,
+ new io.fd.hc2vpp.vpp.classifier.write.acl.ingress.IetfAclCustomizer(ingressAclWriter, ifcNamingContext)));
+
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdEgress =
+ InstanceIdentifier.create(Egress.class).child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdEgress = accessListsIdEgress.child(Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdEgress, aclIdEgress),
+ new GenericWriter<>(EGRESS_IETF_ACL_ID,
+ new io.fd.hc2vpp.vpp.classifier.write.acl.egress.IetfAclCustomizer(egressAclWriter, ifcNamingContext)));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfaceAclWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfaceAclWriterFactory.java
new file mode 100644
index 000000000..f95cf718e
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfaceAclWriterFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.factory.InterfacesWriterFactory;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.SubInterfaceAclCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.subinterface.acl.rev161214.VppSubinterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SubInterfaceAclWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<SubinterfaceAugmentation> SUB_IFC_AUG_ID =
+ InterfacesWriterFactory.IFC_ID.augmentation(SubinterfaceAugmentation.class);
+ public static final InstanceIdentifier<SubInterface> SUB_IFC_ID =
+ SUB_IFC_AUG_ID.child(SubInterfaces.class).child(SubInterface.class);
+ public static final InstanceIdentifier<VppSubinterfaceAclAugmentation> SUB_IF_ACL_AUG_ID =
+ SUB_IFC_ID.augmentation(VppSubinterfaceAclAugmentation.class);
+
+ public static final InstanceIdentifier<Acl> SUBIF_ACL_ID = SUB_IF_ACL_AUG_ID.child(Acl.class);
+ public static final InstanceIdentifier<Ingress> SUBIF_INGRESS_ACL_ID = SUBIF_ACL_ID.child(Ingress.class);
+
+ @Inject
+ private FutureJVppCore jvpp;
+
+ @Inject
+ @Named("interface-context")
+ private NamingContext ifcNamingContext;
+
+ @Inject
+ @Named("classify-table-context")
+ private VppClassifierContextManager classifyTableContext;
+
+ @Override
+ public void init(@Nonnull ModifiableWriterRegistryBuilder registry) {
+ // Ingress (execute after classify table and session writers)
+ // also handles L2Acl, Ip4Acl and Ip6Acl:
+ final InstanceIdentifier<Ingress> aclId = InstanceIdentifier.create(Ingress.class);
+ registry
+ .subtreeAddAfter(
+ Sets.newHashSet(aclId.child(L2Acl.class), aclId.child(Ip4Acl.class), aclId.child(Ip6Acl.class)),
+ new GenericWriter<>(SUBIF_INGRESS_ACL_ID,
+ new SubInterfaceAclCustomizer(jvpp, ifcNamingContext, classifyTableContext)),
+ Sets.newHashSet(VppClassifierHoneycombWriterFactory.CLASSIFY_TABLE_ID,
+ VppClassifierHoneycombWriterFactory.CLASSIFY_SESSION_ID));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfacesClassifierIetfAclWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfacesClassifierIetfAclWriterFactory.java
new file mode 100644
index 000000000..c04c3642f
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/SubInterfacesClassifierIetfAclWriterFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.factory.InterfacesWriterFactory;
+import io.fd.hc2vpp.vpp.classifier.write.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.IngressIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.SubInterfaceIetfAclCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.IetfAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.subinterface.acl.rev161214.VppSubinterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class SubInterfacesClassifierIetfAclWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<SubinterfaceAugmentation> SUB_IFC_AUG_ID =
+ InterfacesWriterFactory.IFC_ID.augmentation(SubinterfaceAugmentation.class);
+ public static final InstanceIdentifier<SubInterface> SUB_IFC_ID =
+ SUB_IFC_AUG_ID.child(SubInterfaces.class).child(SubInterface.class);
+
+ public static final InstanceIdentifier<VppSubinterfaceAclAugmentation> SUB_IFC_ACL_AUG_ID =
+ SUB_IFC_ID.augmentation(VppSubinterfaceAclAugmentation.class);
+
+ public static final InstanceIdentifier<IetfAcl> SUBIF_IETF_ACL_ID = SUB_IFC_ACL_AUG_ID.child(IetfAcl.class);
+ public static final InstanceIdentifier<Ingress> SUBIF_INGRESS_IETF_ACL_ID = SUBIF_IETF_ACL_ID.child(Ingress.class);
+ public static final InstanceIdentifier<Egress> SUBIF_EGRESS_IETF_ACL_ID = SUBIF_IETF_ACL_ID.child(Egress.class);
+
+ private final IngressIetfAclWriter ingressAclWriter;
+ private final EgressIetfAclWriter egressAclWriter;
+ private final NamingContext ifcContext;
+
+ @Inject
+ public SubInterfacesClassifierIetfAclWriterFactory(final IngressIetfAclWriter ingressAclWriter,
+ final EgressIetfAclWriter egressAclWriter,
+ @Named("interface-context") final NamingContext ifcContext) {
+ this.ingressAclWriter = ingressAclWriter;
+ this.egressAclWriter = egressAclWriter;
+ this.ifcContext = ifcContext;
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdIngress =
+ InstanceIdentifier.create(Ingress.class).child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdIngress = accessListsIdIngress.child(Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdIngress, aclIdIngress),
+ new GenericWriter<>(SUBIF_INGRESS_IETF_ACL_ID,
+ new SubInterfaceIetfAclCustomizer(ingressAclWriter, ifcContext)));
+
+ // Egress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdEgress =
+ InstanceIdentifier.create(Egress.class).child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdEgress = accessListsIdEgress.child(Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdEgress, aclIdEgress),
+ new GenericWriter<>(SUBIF_EGRESS_IETF_ACL_ID,
+ new io.fd.hc2vpp.vpp.classifier.write.acl.egress.SubInterfaceIetfAclCustomizer(
+ egressAclWriter, ifcContext)));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/VppClassifierHoneycombWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/VppClassifierHoneycombWriterFactory.java
new file mode 100644
index 000000000..cf34e910c
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/VppClassifierHoneycombWriterFactory.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.factory.write;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.hc2vpp.vpp.classifier.write.ClassifySessionWriter;
+import io.fd.hc2vpp.vpp.classifier.write.ClassifyTableWriter;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VppClassifierHoneycombWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<ClassifyTable> CLASSIFY_TABLE_ID =
+ InstanceIdentifier.create(VppClassifier.class).child(ClassifyTable.class);
+
+ public static final InstanceIdentifier<ClassifySession> CLASSIFY_SESSION_ID =
+ CLASSIFY_TABLE_ID.child(ClassifySession.class);
+
+ private final FutureJVppCore jvpp;
+ private final VppClassifierContextManager classifyTableContext;
+
+ @Inject
+ public VppClassifierHoneycombWriterFactory(@Nonnull final FutureJVppCore jvpp,
+ @Named("classify-table-context") @Nonnull final VppClassifierContextManager classifyTableContext) {
+ this.jvpp = jvpp;
+ this.classifyTableContext = classifyTableContext;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+ // Ordering here is: First create table, then create sessions and then assign as ACL
+ // ClassifyTable
+ registry.addBefore(
+ new GenericListWriter<>(CLASSIFY_TABLE_ID, new ClassifyTableWriter(jvpp, classifyTableContext)),
+ CLASSIFY_SESSION_ID);
+ // ClassifyTableSession
+ registry.addBefore(
+ new GenericListWriter<>(CLASSIFY_SESSION_ID, new ClassifySessionWriter(jvpp, classifyTableContext)),
+ InterfaceAclWriterFactory.ACL_ID);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/EgressIetfAClWriterProvider.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/EgressIetfAClWriterProvider.java
new file mode 100644
index 000000000..afba2118e
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/EgressIetfAClWriterProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.provider;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AclTableContextManagerImpl;
+import io.fd.hc2vpp.vpp.classifier.write.acl.egress.EgressIetfAclWriter;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+
+public class EgressIetfAClWriterProvider implements Provider<EgressIetfAclWriter> {
+
+ private final FutureJVppCore jvpp;
+
+ @Inject
+ public EgressIetfAClWriterProvider(final FutureJVppCore jvpp) {
+ this.jvpp = jvpp;
+ }
+
+ @Override
+ public EgressIetfAclWriter get() {
+ return new EgressIetfAclWriter(jvpp, new AclTableContextManagerImpl(MappingTable.Direction.Egress));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/IngressIetfAClWriterProvider.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/IngressIetfAClWriterProvider.java
new file mode 100644
index 000000000..ef6c01347
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/provider/IngressIetfAClWriterProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.provider;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AclTableContextManagerImpl;
+import io.fd.hc2vpp.vpp.classifier.write.acl.ingress.IngressIetfAclWriter;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+
+public class IngressIetfAClWriterProvider implements Provider<IngressIetfAclWriter> {
+
+ private final FutureJVppCore jvpp;
+
+ @Inject
+ public IngressIetfAClWriterProvider(final FutureJVppCore jvpp) {
+ this.jvpp = jvpp;
+ }
+
+ @Override
+ public IngressIetfAclWriter get() {
+ return new IngressIetfAclWriter(jvpp, new AclTableContextManagerImpl(MappingTable.Direction.Ingress));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifySessionReader.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifySessionReader.java
new file mode 100644
index 000000000..4b985538e
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifySessionReader.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceDataTranslator;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+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.vpp.jvpp.core.dto.ClassifySessionDetails;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableKey;
+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;
+
+/**
+ * Reader customizer responsible for classify session read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table verbose} command.
+ */
+public class ClassifySessionReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifySession, ClassifySessionKey, ClassifySessionBuilder>,
+ InterfaceDataTranslator, VppNodeReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
+ static final String CACHE_KEY = ClassifySessionReader.class.getName();
+
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifySessionReader(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifySession> readData) {
+ ((ClassifyTableBuilder) builder).setClassifySession(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifySession> id) {
+ return new ClassifySessionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify session: {}", id);
+
+ final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class);
+ Preconditions.checkArgument(key != null, "could not find ClassifySession key in {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", ""));
+ final Optional<ClassifySessionDetails> classifySession =
+ findClassifySessionDetailsByMatch(classifySessionDump, match);
+
+ if (classifySession.isPresent()) {
+ final ClassifySessionDetails detail = classifySession.get();
+ final Optional<VppNode> node =
+ readVppNode(detail.tableId, detail.hitNextIndex, classifyTableContext, ctx.getMappingContext(), LOG);
+ if (node.isPresent()) {
+ builder.setHitNext(node.get());
+ } else {
+ builder.setHitNext(new VppNode(new VppNodeName("unknown"))); // TODO(HC2VPP-9): remove this workaround
+ }
+ if (detail.opaqueIndex != ~0) {
+ // value is specified:
+ builder.setOpaqueIndex(readOpaqueIndex(detail.tableId, detail.opaqueIndex, ctx.getMappingContext()));
+ }
+ builder.setAdvance(detail.advance);
+ builder.setMatch(key.getMatch());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build());
+ }
+ }
+ }
+
+ private OpaqueIndex readOpaqueIndex(final int tableIndex, final int opaqueIndex, final MappingContext ctx) {
+ // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
+ // TODO: HONEYCOMB-118 the approach might fail if the opaqueIndex contains small value that collides
+ // with some of the adjacent nodes
+
+ final Optional<VppNode> node = readVppNode(tableIndex, opaqueIndex, classifyTableContext, ctx, LOG);
+ if (node.isPresent()) {
+ return new OpaqueIndex(node.get());
+ } else {
+ return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
+ }
+ }
+
+ @Nullable
+ private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ Preconditions.checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id);
+
+ final String cacheKey = CACHE_KEY + tableKey;
+
+ ClassifySessionDetailsReplyDump classifySessionDump =
+ (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey);
+ if (classifySessionDump != null) {
+ LOG.debug("Classify sessions is present in cache: {}", cacheKey);
+ return classifySessionDump;
+ }
+
+ final String tableName = tableKey.getName();
+ Preconditions.checkState(classifyTableContext.containsTable(tableName, ctx.getMappingContext()),
+ "Reading classify sessions for table {}, but table index could not be found in the classify table context",
+ tableName);
+ final int tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
+ LOG.debug("Dumping classify sessions for classify table id={}", tableId);
+
+
+ final ClassifySessionDump dumpRequest = new ClassifySessionDump();
+ dumpRequest.tableId = tableId;
+ final int timeOut = 30; // there can be many session with current ietf-acl implementation (could be probably
+ // removed after fixing HONEYCOMB-247)
+ classifySessionDump =
+ getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id, timeOut);
+
+ if (classifySessionDump != null) {
+ // update the cache:
+ ctx.getModificationCache().put(cacheKey, classifySessionDump);
+ }
+
+ return classifySessionDump;
+ }
+
+ private static Optional<ClassifySessionDetails> findClassifySessionDetailsByMatch(
+ @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) {
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ final List<ClassifySessionDetails> details = classifySessionDump.classifySessionDetails;
+ final List<ClassifySessionDetails> filteredSessions = details.stream()
+ .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList());
+ if (filteredSessions.isEmpty()) {
+ return Optional.absent();
+ } else if (filteredSessions.size() == 1) {
+ return Optional.of(filteredSessions.get(0));
+ } else {
+ throw new IllegalStateException(String.format(
+ "Found %d classify sessions witch given match. Single session expected.",
+ filteredSessions.size()));
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifySessionKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify sessions: {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ return classifySessionDump.classifySessionDetails.stream()
+ .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match))))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifyTableReader.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifyTableReader.java
new file mode 100644
index 000000000..27d3e1075
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/ClassifyTableReader.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceDataTranslator;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIds;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIdsReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfo;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfoReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableKey;
+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;
+
+/**
+ * Reader customizer responsible for classify table read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table} command.
+ */
+public class ClassifyTableReader extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader,
+ MacTranslator, InterfaceDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifyTableReader(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifyTable> readData) {
+ ((VppClassifierStateBuilder) builder).setClassifyTable(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifyTable> id) {
+ return new ClassifyTableBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify table: {}", id);
+
+ final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class);
+ Preconditions.checkArgument(key != null, "could not find ClassifyTable key in {}", id);
+ final ClassifyTableInfo request = new ClassifyTableInfo();
+
+ final String tableName = key.getName();
+ if (!classifyTableContext.containsTable(tableName, ctx.getMappingContext())) {
+ LOG.debug("Could not find classify table {} in the naming context", tableName);
+ return;
+ }
+ request.tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
+
+
+ final ClassifyTableInfoReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id);
+
+ // mandatory values:
+ builder.setName(tableName);
+ builder.setKey(key);
+ builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets));
+ builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors));
+
+ // optional value read from context
+ final Optional<String> tableBaseNode =
+ classifyTableContext.getTableBaseNode(tableName, ctx.getMappingContext());
+ if (tableBaseNode.isPresent()) {
+ builder.setClassifierNode(new VppNodeName(tableBaseNode.get()));
+ }
+
+ final Optional<VppNode> node =
+ readVppNode(reply.tableId, reply.missNextIndex, classifyTableContext, ctx.getMappingContext(), LOG);
+ if (node.isPresent()) {
+ builder.setMissNext(node.get());
+ } else {
+ builder.setMissNext(new VppNode(new VppNodeName("unknown"))); // TODO(HC2VPP-9): remove this workaround
+ }
+ builder.setMask(new HexString(printHexBinary(reply.mask)));
+ builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions));
+
+ if (reply.nextTableIndex != ~0) {
+ // next table index is present:
+ builder.setNextTable(classifyTableContext.getTableName(reply.nextTableIndex, ctx.getMappingContext()));
+ }
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifyTableKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify tables: {}", id);
+
+ final ClassifyTableIdsReply classifyTableIdsReply =
+ getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(),
+ id);
+ if (classifyTableIdsReply.ids != null) {
+ return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> {
+ final String tableName = classifyTableContext.getTableName(i, context.getMappingContext());
+ LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i);
+ return new ClassifyTableKey(tableName);
+ }).collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable> init(
+ @Nonnull final InstanceIdentifier<ClassifyTable> id, @Nonnull final ClassifyTable readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableBuilder(readValue)
+ .setName(readValue.getName())
+ .build());
+ }
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable> getCfgId(
+ final InstanceIdentifier<ClassifyTable> id) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey(id.firstKeyOf(ClassifyTable.class).getName()));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/VppNodeReader.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/VppNodeReader.java
new file mode 100644
index 000000000..8fe4786bc
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/VppNodeReader.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.slf4j.Logger;
+
+interface VppNodeReader {
+
+ /**
+ * Converts vpp node index to YANG representation of vpp node.
+ *
+ * @param nodeIndex index of vpp node treated as signed integer.
+ * @return vpp node representation
+ */
+ default Optional<VppNode> readVppNode(final int tableIndex, final int nodeIndex,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final Logger log) {
+ final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex);
+ if (action == null) {
+ return vppClassifierContextManager.getNodeName(tableIndex, nodeIndex, ctx)
+ .transform(nodeName -> new VppNode(new VppNodeName(nodeName)));
+ }
+ return Optional.of(new VppNode(action));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclCustomizer.java
new file mode 100644
index 000000000..6d5fde4e5
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclCustomizer.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read.acl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp._interface.acl.rev161214.VppInterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.IngressBuilder;
+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;
+
+/**
+ * Customizer for reading ingress ACLs enabled on given interface.
+ */
+public class AclCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Ingress, IngressBuilder>, AclReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ingress readValue) {
+ ((AclBuilder) parentBuilder).setIngress(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public IngressBuilder getBuilder(@Nonnull final InstanceIdentifier<Ingress> id) {
+ return new IngressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final IngressBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface ACL: {}", id);
+ final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class);
+ checkArgument(interfaceKey != null, "No parent interface key found");
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(interfaceKey.getName(), ctx.getMappingContext());
+
+ final ClassifyTableByInterfaceReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Override
+ public Initialized<Ingress> init(
+ @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new IngressBuilder()
+ .setL2Acl(readValue.getL2Acl())
+ .setIp4Acl(readValue.getIp4Acl())
+ .setIp6Acl(readValue.getIp6Acl())
+ .build());
+ }
+
+ private InstanceIdentifier<Ingress> getCfgId(
+ final InstanceIdentifier<Ingress> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAclAugmentation.class)
+ .child(Acl.class)
+ .child(Ingress.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclReader.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclReader.java
new file mode 100644
index 000000000..7c74a330b
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/AclReader.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read.acl;
+
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2AclBuilder;
+
+interface AclReader {
+
+ @Nonnull
+ default L2Acl readL2Acl(final int l2TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (l2TableId == ~0) {
+ return null;
+ }
+ return new L2AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(l2TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip4TableId == ~0) {
+ return null;
+ }
+ return new Ip4AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(ip4TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip6TableId == ~0) {
+ return null;
+ }
+ return new Ip6AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(ip6TableId, mappingContext)).build();
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/SubInterfaceAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..a2671f15e
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/read/acl/SubInterfaceAclCustomizer.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.read.acl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.interfacesstate.SubInterfaceCustomizer;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.IngressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.subinterface.acl.rev161214.VppSubinterfaceAclAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+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;
+
+/**
+ * Customizer for reading ingress ACLs enabled on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Ingress, IngressBuilder>, AclReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ingress readValue) {
+ ((AclBuilder) parentBuilder).setIngress(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public IngressBuilder getBuilder(@Nonnull final InstanceIdentifier<Ingress> id) {
+ return new IngressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final IngressBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface ACL: {}", id);
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ checkArgument(parentInterfacekey != null, "No parent interface key found");
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ checkArgument(subInterfacekey != null, "No sub-interface key found");
+ final String subInterfaceName =
+ getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+
+ final ClassifyTableByInterfaceReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Override
+ public Initialized<Ingress> init(
+ @Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id), readValue);
+ }
+
+ static InstanceIdentifier<Ingress> getCfgId(
+ final InstanceIdentifier<Ingress> id) {
+ return SubInterfaceCustomizer.getCfgId(RWUtils.cutId(id, SubInterface.class))
+ .augmentation(VppSubinterfaceAclAugmentation.class)
+ .child(Acl.class)
+ .child(Ingress.class);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriter.java
new file mode 100644
index 000000000..00e858955
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriter.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+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.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify session create/delete.<br> Sends {@code classify_add_del_session} message
+ * to VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifySessionWriter extends VppNodeWriter
+ implements ListWriterCustomizer<ClassifySession, ClassifySessionKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifySessionWriter(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter);
+ try {
+ classifyAddDelSession(true, id, dataAfter, writeContext);
+ LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify session update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore);
+ try {
+ classifyAddDelSession(false, id, dataBefore, writeContext);
+ LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession classifySession,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ Preconditions.checkArgument(tableKey != null, "could not find classify table key in {}", id);
+
+ final String tableName = tableKey.getName();
+ Preconditions.checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
+ "Could not find classify table index for {} in the classify table context", tableName);
+ final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
+
+ final ClassifyTable classifyTable =
+ getClassifyTable(writeContext, id.firstIdentifierOf(ClassifyTable.class), isAdd);
+ final int hitNextIndex = getNodeIndex(classifySession.getHitNext(), classifyTable, classifyTableContext,
+ writeContext.getMappingContext(), id);
+ final int opaqueIndex =
+ getOpaqueIndex(classifySession.getOpaqueIndex(), classifyTable, writeContext.getMappingContext(), id);
+
+ final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
+ .classifyAddDelSession(
+ getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex, hitNextIndex, opaqueIndex));
+
+ getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private ClassifyTable getClassifyTable(final WriteContext writeContext,
+ @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ final boolean isAdd) {
+ final Optional<ClassifyTable> classifyTable;
+ if (isAdd) {
+ classifyTable = writeContext.readAfter(id);
+ } else {
+ classifyTable = writeContext.readBefore(id);
+ }
+ return classifyTable.get();
+ }
+
+ private ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd,
+ @Nonnull final ClassifySession classifySession,
+ final int tableIndex,
+ final int hitNextIndex,
+ final int opaqueIndex) {
+ ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+ request.hitNextIndex = hitNextIndex;
+ request.opaqueIndex = opaqueIndex;
+
+ // default 0:
+ request.advance = classifySession.getAdvance();
+
+ request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", ""));
+ return request;
+ }
+
+ private int getOpaqueIndex(@Nullable final OpaqueIndex opaqueIndex, final ClassifyTable classifyTable,
+ final MappingContext ctx, final InstanceIdentifier<ClassifySession> id)
+ throws VppBaseCallException, WriteFailedException {
+ if (opaqueIndex == null) {
+ return ~0; // value not specified
+ }
+ if (opaqueIndex.getUint32() != null) {
+ return opaqueIndex.getUint32().intValue();
+ } else {
+ return getNodeIndex(opaqueIndex.getVppNode(), classifyTable, classifyTableContext, ctx, id);
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifyTableWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifyTableWriter.java
new file mode 100644
index 000000000..a88620b35
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifyTableWriter.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+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.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
+ * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifyTableWriter extends VppNodeWriter
+ implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifyTableWriter(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter);
+ try {
+ final int newTableIndex =
+ classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */,
+ writeContext.getMappingContext());
+
+ // Add classify table name <-> vpp index mapping to the naming context:
+ classifyTableContext.addTable(newTableIndex, dataAfter.getName(), dataAfter.getClassifierNode(),
+ writeContext.getMappingContext());
+ LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify table update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
+ final String tableName = dataBefore.getName();
+ Preconditions.checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
+ "Removing classify table {}, but index could not be found in the classify table context", tableName);
+
+ final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
+ try {
+ classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
+
+ // Remove deleted interface from interface context:
+ classifyTableContext.removeTable(dataBefore.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
+ throws VppBaseCallException, WriteFailedException {
+
+ final int missNextIndex =
+ getNodeIndex(table.getMissNext(), table, classifyTableContext, ctx, id);
+
+ final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
+ getFutureJVpp()
+ .classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, missNextIndex, ctx));
+
+ final ClassifyAddDelTableReply reply =
+ getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ return reply.newTableIndex;
+ }
+
+ private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifyTable table,
+ final int missNextIndex,
+ @Nonnull final MappingContext ctx) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory, all u32 values are permitted:
+ request.nbuckets = table.getNbuckets().intValue();
+ request.memorySize = table.getMemorySize().intValue();
+ request.skipNVectors = table.getSkipNVectors().intValue();
+
+ // mandatory
+ request.missNextIndex = missNextIndex;
+
+ final String nextTable = table.getNextTable();
+ if (isAdd && nextTable != null) {
+ request.nextTableIndex = classifyTableContext.getTableIndex(nextTable, ctx);
+ } else {
+ request.nextTableIndex = ~0; // value not specified
+ }
+ request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", ""));
+ checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16.");
+ request.matchNVectors = request.mask.length / 16;
+
+ return request;
+ }
+} \ No newline at end of file
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/VppNodeWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/VppNodeWriter.java
new file mode 100644
index 000000000..c513e8cd7
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/VppNodeWriter.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.GetNextIndex;
+import io.fd.vpp.jvpp.core.dto.GetNextIndexReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+abstract class VppNodeWriter extends FutureJVppCustomizer implements JvppReplyConsumer {
+
+ protected VppNodeWriter(@Nonnull final FutureJVppCore futureJvpp) {
+ super(futureJvpp);
+ }
+
+ protected int getNodeIndex(@Nonnull final VppNode node, @Nonnull final ClassifyTable classifyTable,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+ throws VppBaseCallException, WriteFailedException {
+ if (node.getPacketHandlingAction() != null) {
+ return node.getPacketHandlingAction().getIntValue();
+ } else {
+ return nodeNameToIndex(classifyTable, node.getVppNodeName().getValue(), vppClassifierContextManager, ctx,
+ id);
+ }
+ }
+
+ private int nodeNameToIndex(@Nonnull final ClassifyTable classifyTable, @Nonnull final String nextNodeName,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+ throws WriteFailedException {
+ checkArgument(classifyTable != null && classifyTable.getClassifierNode() != null,
+ "to use relative node names, table classifier node needs to be provided");
+ final GetNextIndex request = new GetNextIndex();
+ request.nodeName = classifyTable.getClassifierNode().getValue().getBytes();
+ request.nextName = nextNodeName.getBytes();
+ final CompletionStage<GetNextIndexReply> getNextIndexCompletionStage =
+ getFutureJVpp().getNextIndex(request);
+
+ final GetNextIndexReply reply;
+ try {
+ reply = getReplyForRead(getNextIndexCompletionStage.toCompletableFuture(), id);
+
+ // vpp does not provide relative node index to node name conversion (https://jira.fd.io/browse/VPP-219)
+ // as a workaround we need to add mapping to vpp-classfier-context
+ vppClassifierContextManager.addNodeName(classifyTable.getName(), reply.nextIndex, nextNodeName, ctx);
+ } catch (ReadFailedException e) {
+ throw new WriteFailedException(id, String.format("Failed to get node index for %s relative to %s",
+ nextNodeName, classifyTable.getClassifierNode()), e);
+ }
+ return reply.nextIndex;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/IetfAclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/IetfAclWriter.java
new file mode 100644
index 000000000..41ca796e7
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/IetfAclWriter.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.Optional;
+import java.util.stream.Stream;
+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.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.AclKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp._interface.acl.rev161214.VppInterfaceAclAugmentation;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for Access Control Lists management. Does not send any messages to VPP. All the config
+ * data are stored in HC and used when acl is assigned/unassigned to/from an interface.
+ *
+ * ACLs that are currently assigned to an interface cannot be updated/deleted.
+ */
+public class IetfAclWriter implements ListWriterCustomizer<Acl, AclKey> {
+
+ public static final InstanceIdentifier<AccessLists> ACL_ID =
+ InstanceIdentifier.create(AccessLists.class);
+
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclWriter.class);
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating ACL: iid={} dataAfter={}", id, dataAfter);
+
+ // no vpp call, just updates DataTree
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Updating ACL: iid={} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+
+ if (isAssigned(dataAfter, writeContext)) {
+ throw new WriteFailedException(id,
+ String.format("Failed to update data at %s: acl %s is already assigned", id, dataAfter));
+ }
+
+ LOG.debug("Updating unassigned ACL: iid={} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+
+ // no vpp call, just updates DataTree
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Deleting ACL: iid={} dataBefore={}", id, dataBefore);
+
+ if (isAssigned(dataBefore, writeContext)) {
+ throw new WriteFailedException(id,
+ String.format("Failed to delete data at %s: acl %s is already assigned", id, dataBefore));
+ }
+
+ LOG.debug("Deleting unassigned ACL: iid={} dataBefore={}", id, dataBefore);
+
+ // no vpp call, just updates DataTree
+ }
+
+ private static boolean isAssigned(@Nonnull final Acl acl,
+ @Nonnull final WriteContext writeContext) {
+ final String aclName = acl.getAclName();
+ final Class<? extends AclBase> aclType = acl.getAclType();
+ final Interfaces interfaces = writeContext.readAfter(InstanceIdentifier.create(Interfaces.class)).get();
+
+ return interfaces.getInterface().stream()
+ .map(i -> Optional.ofNullable(i.getAugmentation(VppInterfaceAclAugmentation.class))
+ .map(aug -> aug.getIetfAcl())
+ .map(ietfAcl -> ietfAcl.getIngress())
+ .map(ingress -> ingress.getAccessLists())
+ .map(accessLists -> accessLists.getAcl()))
+ .flatMap(iacl -> iacl.isPresent()
+ ? iacl.get().stream()
+ : Stream.empty())
+ .filter(assignedAcl -> aclName.equals(assignedAcl.getName()) && aclType.equals(assignedAcl.getType()))
+ .findFirst().isPresent();
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AbstractIetfAclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AbstractIetfAclWriter.java
new file mode 100644
index 000000000..59d314c03
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AbstractIetfAclWriter.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+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.AclKey;
+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.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.matches.AceType;
+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.ace.type.AceEth;
+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.ace.type.AceIp;
+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.ace.type.ace.ip.AceIpVersion;
+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.ace.type.ace.ip.ace.ip.version.AceIpv4;
+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.ace.type.ace.ip.ace.ip.version.AceIpv6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractIetfAclWriter implements IetfAclWriter, JvppReplyConsumer, AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractIetfAclWriter.class);
+ protected static final int NOT_DEFINED = -1;
+ protected final FutureJVppCore jvpp;
+
+ private Map<AclType, AceWriter<? extends AceType>> aceWriters = new HashMap<>();
+
+ public AbstractIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) {
+ this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null");
+ aceWriters.put(AclType.ETH, new AceEthWriter());
+ aceWriters.put(AclType.IP4, new AceIp4Writer());
+ aceWriters.put(AclType.IP6, new AceIp6Writer());
+ aceWriters.put(AclType.ETH_AND_IP, new AceIpAndEthWriter());
+ }
+
+ private static Stream<Ace> aclToAceStream(@Nonnull final Acl assignedAcl,
+ @Nonnull final WriteContext writeContext) {
+ final String aclName = assignedAcl.getName();
+ final Class<? extends AclBase> aclType = assignedAcl.getType();
+
+ // ietf-acl updates are handled first, so we use writeContext.readAfter
+ final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl>
+ aclOptional =
+ writeContext.readAfter(io.fd.hc2vpp.vpp.classifier.write.acl.IetfAclWriter.ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class,
+ new AclKey(aclName, aclType)));
+ checkArgument(aclOptional.isPresent(), "Acl lists not configured");
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl
+ acl = aclOptional.get();
+
+ final AccessListEntries accessListEntries = acl.getAccessListEntries();
+ checkArgument(accessListEntries != null, "access list entries not configured");
+
+ return accessListEntries.getAce().stream();
+ }
+
+ protected void removeClassifyTables(@Nonnull final InstanceIdentifier<?> id, @Nonnull final MappingEntry entry)
+ throws WriteFailedException {
+ removeClassifyTable(id, entry.getL2TableId());
+ removeClassifyTable(id, entry.getIp4TableId());
+ removeClassifyTable(id, entry.getIp6TableId());
+ }
+
+ private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex)
+ throws WriteFailedException {
+
+ if (tableIndex == -1) {
+ return; // classify table id is absent
+ }
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.delChain = 1;
+ request.tableIndex = tableIndex;
+ final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
+ getReplyForDelete(cs.toCompletableFuture(), id);
+ }
+
+ protected static boolean appliesToIp4Path(final Ace ace) {
+ final AceType aceType = ace.getMatches().getAceType();
+ final AclType aclType = AclType.fromAce(ace);
+ if (aclType == AclType.IP4) {
+ return true;
+ }
+ if (aclType == AclType.ETH) {
+ return true; // L2 only rules are possible for IP4 traffic
+ }
+ if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType).getAceIpAndEthNodes()
+ .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv4) {
+ return true;
+ }
+ return false;
+ }
+
+ protected static boolean appliesToIp6Path(final Ace ace) {
+ final AceType aceType = ace.getMatches().getAceType();
+ final AclType aclType = AclType.fromAce(ace);
+ if (aclType == AclType.IP6) {
+ return true;
+ }
+ if (aclType == AclType.ETH) {
+ return true; // L2 only rules are possible for IP6 traffic
+ }
+ if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType).getAceIpAndEthNodes()
+ .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv6) {
+ return true;
+ }
+ return false;
+ }
+
+ protected static List<Ace> getACEs(@Nonnull final List<Acl> acls, @Nonnull final WriteContext writeContext,
+ final Predicate<? super Ace> filter) {
+ return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter)
+ .collect(Collectors.toList());
+ }
+
+ protected int writeAces(final InstanceIdentifier<?> id, final List<Ace> aces,
+ final AccessLists.DefaultAction defaultAction, final InterfaceMode mode,
+ final int vlanTags) throws WriteFailedException {
+ if (aces.isEmpty()) {
+ return NOT_DEFINED;
+ }
+
+ int nextTableIndex = configureDefaultAction(id, defaultAction);
+ final ListIterator<Ace> iterator = aces.listIterator(aces.size());
+ while (iterator.hasPrevious()) {
+ final Ace ace = iterator.previous();
+ LOG.trace("Processing ACE: {}", ace);
+
+ final AceWriter aceWriter =
+ aceWriters.get(AclType.fromAce(ace));
+ if (aceWriter == null) {
+ LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass());
+ } else {
+ final AceType aceType = ace.getMatches().getAceType();
+ final PacketHandling action = ace.getActions().getPacketHandling();
+ final ClassifyAddDelTable ctRequest = aceWriter.createTable(aceType, mode, nextTableIndex, vlanTags);
+ nextTableIndex = createClassifyTable(id, ctRequest);
+ final List<ClassifyAddDelSession> sessionRequests =
+ aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags);
+ for (ClassifyAddDelSession csRequest : sessionRequests) {
+ createClassifySession(id, csRequest);
+ }
+ }
+ }
+ return nextTableIndex;
+ }
+
+ private int configureDefaultAction(@Nonnull final InstanceIdentifier<?> id,
+ final AccessLists.DefaultAction defaultAction)
+ throws WriteFailedException {
+ ClassifyAddDelTable ctRequest = createTable(-1);
+ if (AccessLists.DefaultAction.Permit.equals(defaultAction)) {
+ ctRequest.missNextIndex = -1;
+ } else {
+ ctRequest.missNextIndex = 0;
+ }
+ ctRequest.mask = new byte[16];
+ ctRequest.skipNVectors = 0;
+ ctRequest.matchNVectors = 1;
+ return createClassifyTable(id, ctRequest);
+ }
+
+ private int createClassifyTable(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ClassifyAddDelTable request)
+ throws WriteFailedException {
+ final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
+
+ final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id);
+ return reply.newTableIndex;
+ }
+
+ private void createClassifySession(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ClassifyAddDelSession request)
+ throws WriteFailedException {
+ final CompletionStage<ClassifyAddDelSessionReply> cs = jvpp.classifyAddDelSession(request);
+
+ getReplyForWrite(cs.toCompletableFuture(), id);
+ }
+
+ private enum AclType {
+ ETH, IP4, IP6, ETH_AND_IP;
+
+ @Nonnull
+ private static AclType fromAce(final Ace ace) {
+ AclType result = null;
+ final AceType aceType;
+ try {
+ aceType = ace.getMatches().getAceType();
+ if (aceType instanceof AceEth) {
+ result = ETH;
+ } else if (aceType instanceof AceIp) {
+ final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion();
+ if (aceIpVersion == null) {
+ throw new IllegalArgumentException("Incomplete ACE (ip-version was not provided): " + ace);
+ }
+ if (aceIpVersion instanceof AceIpv4) {
+ result = IP4;
+ } else if (aceIpVersion instanceof AceIpv6) {
+ result = IP6;
+ }
+ } else if (aceType instanceof AceIpAndEth) {
+ result = ETH_AND_IP;
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException("Incomplete ACE: " + ace, e);
+ }
+ if (result == null) {
+ throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType));
+ }
+ return result;
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceEthWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceEthWriter.java
new file mode 100644
index 000000000..2a88239cc
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceEthWriter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceEthWriter implements AceWriter<AceEth>, AclTranslator, L2AclTranslator {
+
+ @VisibleForTesting
+ static final int MATCH_N_VECTORS = 1;
+ private static final Logger LOG = LoggerFactory.getLogger(AceEthWriter.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceEth aceEth,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ final ClassifyAddDelTable request = createTable(nextTableIndex);
+
+ request.mask = new byte[16];
+ boolean aceIsEmpty =
+ destinationMacAddressMask(aceEth.getDestinationMacAddressMask(), aceEth.getDestinationMacAddress(),
+ request);
+ aceIsEmpty &=
+ sourceMacAddressMask(aceEth.getSourceMacAddressMask(), aceEth.getSourceMacAddress(), request);
+
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceEth.toString()));
+ }
+
+ request.skipNVectors = 0;
+ request.matchNVectors = MATCH_N_VECTORS;
+
+ LOG.debug("ACE rule={} translated to table={}.", aceEth, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceEth aceEth,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+
+ request.match = new byte[16];
+ boolean noMatch = destinationMacAddressMatch(aceEth.getDestinationMacAddress(), request);
+ noMatch &= sourceMacAddressMatch(aceEth.getSourceMacAddress(), request);
+
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define neither source nor destination MAC address",
+ aceEth.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceEth, request);
+ return Collections.singletonList(request);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp4Writer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp4Writer.java
new file mode 100644
index 000000000..0ae1315a8
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp4Writer.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.matches.ace.type.AceIp;
+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.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceIp4Writer implements AceWriter<AceIp>, AclTranslator, Ip4AclTranslator {
+
+ @VisibleForTesting
+ static final int MATCH_N_VECTORS = 3; // number of 16B vectors
+ private static final int TABLE_MASK_LENGTH = 48;
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
+ final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
+
+ final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ request.skipNVectors = 0; // match entire L2 and L3 header
+ request.matchNVectors = MATCH_N_VECTORS;
+ request.mask = new byte[TABLE_MASK_LENGTH];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean aceIsEmpty = ip4Mask(baseOffset, mode, aceIp, ipVersion, request);
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", aceIp, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
+ final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
+
+ final List<PortPair> portPairs = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange());
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[TABLE_MASK_LENGTH];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean noMatch = ip4Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request);
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp6Writer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp6Writer.java
new file mode 100644
index 000000000..2004d4e06
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIp6Writer.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.matches.ace.type.AceIp;
+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.ace.type.ace.ip.ace.ip.version.AceIpv6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceIp6Writer implements AceWriter<AceIp>, AclTranslator, Ip6AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
+ final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
+
+ final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ request.skipNVectors = 0; // match entire L2 and L3 header
+ request.mask = new byte[getTableMaskLength(vlanTags)];
+ request.matchNVectors = request.mask.length/16;
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean aceIsEmpty = ip6Mask(baseOffset, mode, aceIp, ipVersion, request);
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", aceIp, request);
+ return request;
+ }
+
+ private static int getTableMaskLength(final int vlanTags) {
+ if (vlanTags == 2) {
+ return 80;
+ } else {
+ return 64;
+ }
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
+ final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
+ final List<PortPair> portPairs =
+ PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange());
+
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[getTableMaskLength(vlanTags)];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean noMatch = ip6Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request);
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIpAndEthWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIpAndEthWriter.java
new file mode 100644
index 000000000..8efe3564e
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceIpAndEthWriter.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.AceIpAndEthNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.AceIpVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv6;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class AceIpAndEthWriter
+ implements AceWriter<AceIpAndEth>, AclTranslator, L2AclTranslator, Ip4AclTranslator, Ip6AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AceIpAndEthWriter.class);
+
+ private static int maskLength(@Nonnull final AceIpAndEth ace, final int vlanTags) {
+ if (ace.getAceIpAndEthNodes().getAceIpVersion() != null) {
+ if (ace.getAceIpAndEthNodes().getAceIpVersion() instanceof AceIpv4) {
+ return 48;
+ } else {
+ return vlanTags == 2
+ ? 80
+ : 64;
+ }
+ }
+ return 16;
+ }
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIpAndEth ace, @Nullable final InterfaceMode mode,
+ final int nextTableIndex, final int vlanTags) {
+ final AceIpAndEthNodes nodes = ace.getAceIpAndEthNodes();
+ final int numberOfSessions = PortPair.fromRange(nodes.getSourcePortRange(), nodes.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ final int maskLength = maskLength(ace, vlanTags);
+ request.mask = new byte[maskLength];
+ request.skipNVectors = 0;
+ request.matchNVectors = maskLength / 16;
+
+ boolean aceIsEmpty =
+ destinationMacAddressMask(nodes.getDestinationMacAddressMask(), nodes.getDestinationMacAddress(), request);
+ aceIsEmpty &= sourceMacAddressMask(nodes.getSourceMacAddressMask(), nodes.getSourceMacAddress(), request);
+
+ // if we use classifier API, we need to know ip version (fields common for ip4 and ip6 have different offsets):
+ final AceIpVersion aceIpVersion = nodes.getAceIpVersion();
+ checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion");
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ if (aceIpVersion instanceof AceIpv4) {
+ final AceIpv4 ipVersion = (AceIpv4) aceIpVersion;
+ aceIsEmpty &= ip4Mask(baseOffset, mode, nodes, ipVersion, request);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ aceIsEmpty &= ip6Mask(baseOffset, mode, nodes, ipVersion, request);
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion));
+ }
+
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", ace.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", ace, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIpAndEth ace,
+ @Nullable final InterfaceMode mode, final int tableIndex,
+ final int vlanTags) {
+ final AceIpAndEthNodes nodes = ace.getAceIpAndEthNodes();
+ final List<PortPair> portPairs = PortPair.fromRange(nodes.getSourcePortRange(), nodes.getDestinationPortRange());
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[maskLength(ace, vlanTags)];
+
+ boolean noMatch = destinationMacAddressMatch(nodes.getDestinationMacAddress(), request);
+ noMatch &= sourceMacAddressMatch(nodes.getSourceMacAddress(), request);
+
+ final AceIpVersion aceIpVersion = nodes.getAceIpVersion();
+ checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion");
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ if (aceIpVersion instanceof AceIpv4) {
+ final AceIpv4 ipVersion = (AceIpv4) aceIpVersion;
+ noMatch &= ip4Match(baseOffset, mode, nodes, ipVersion, pair.getSrc(), pair.getDst(), request);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ noMatch &= ip6Match(baseOffset, mode, nodes, ipVersion, pair.getSrc(), pair.getDst(), request);
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion));
+ }
+
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", ace.toString()));
+ }
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, ace, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceWriter.java
new file mode 100644
index 000000000..228527f69
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AceWriter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.matches.AceType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+
+/**
+ * Writer responsible for translation of ietf-acl model ACEs to VPP's classify tables and sessions.
+ *
+ * @param <T> type of access control list entry
+ */
+interface AceWriter<T extends AceType> {
+ /**
+ * @param ace access list entry
+ * @param mode interface mode (L2/L3)
+ * @param nextTableIndex index of the next classify table in chain
+ * @param vlanTags number of vlan tags
+ */
+ @Nonnull
+ ClassifyAddDelTable createTable(@Nonnull final T ace, @Nullable final InterfaceMode mode, final int nextTableIndex,
+ final int vlanTags);
+
+ /**
+ * @param action to be taken when packet does match the specified ace
+ * @param ace access list entry
+ * @param mode interface mode (L2/L3)
+ * @param tableIndex index of corresponding classify table
+ * @param vlanTags number of vlan tags
+ */
+ @Nonnull
+ List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action, @Nonnull T ace,
+ @Nullable final InterfaceMode mode, final int tableIndex, final int vlanTags);
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManager.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManager.java
new file mode 100644
index 000000000..ed7960dd9
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManager.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+
+/**
+ * Manages interface metadata for ietf-acl model.
+ */
+public interface AclTableContextManager {
+
+ /**
+ * Obtains mapping entry for given interface.
+ *
+ * @param index interface index
+ * @param mappingContext mapping context providing context data for current transaction
+ * @return ietf-acl metadata for given interface
+ */
+ Optional<MappingEntry> getEntry(final int index, @Nonnull final MappingContext mappingContext);
+
+ /**
+ * Adds mapping entry.
+ *
+ * @param entry to be added
+ * @param mappingContext mapping context providing context data for current transaction
+ */
+ void addEntry(@Nonnull final MappingEntry entry, @Nonnull final MappingContext mappingContext);
+
+ /**
+ * Removes entry for given interface (if present).
+ *
+ * @param index interface index
+ * @param mappingContext mapping context providing context data for current transaction
+ */
+ void removeEntry(final int index, @Nonnull final MappingContext mappingContext);
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManagerImpl.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManagerImpl.java
new file mode 100644
index 000000000..16848acfd
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTableContextManagerImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.AclMappingEntryCtxAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.AclMappingEntryContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@ThreadSafe
+public class AclTableContextManagerImpl implements AclTableContextManager {
+
+ private MappingTable.Direction direction;
+
+ public AclTableContextManagerImpl(@Nonnull final MappingTable.Direction direction) {
+ this.direction = checkNotNull(direction, "direction should not be null");
+ }
+
+ @Nonnull
+ @Override
+ public synchronized Optional<MappingEntry> getEntry(final int swIfIndex, @Nonnull final MappingContext mappingContext) {
+ return mappingContext.read(getId(swIfIndex));
+ }
+
+ @Override
+ public synchronized void addEntry(@Nonnull final MappingEntry entry, @Nonnull final MappingContext mappingContext) {
+ mappingContext.put(getId(entry.getIndex()), entry);
+ }
+
+ @Override
+ public synchronized void removeEntry(final int swIfIndex, @Nonnull final MappingContext mappingContext) {
+ mappingContext.delete(getId(swIfIndex));
+ }
+
+ @VisibleForTesting
+ protected InstanceIdentifier<MappingEntry> getId(final int index) {
+ return InstanceIdentifier.create(Contexts.class)
+ .augmentation(AclMappingEntryCtxAugmentation.class)
+ .child(AclMappingEntryContext.class)
+ .child(MappingTable.class, new MappingTableKey(direction))
+ .child(MappingEntry.class, new MappingEntryKey(index));
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTranslator.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTranslator.java
new file mode 100644
index 000000000..e75d0af24
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/AclTranslator.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import javax.annotation.Nonnegative;
+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.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.Permit;
+
+/**
+ * Utility that helps translating of ietf-acl model ACEs to VPP's classify tables and sessions.
+ */
+interface AclTranslator {
+ int TABLE_MEM_SIZE = 8 * 1024;
+ int VLAN_TAG_LEN = 4;
+
+ default ClassifyAddDelTable createTable(final int nextTableIndex) {
+ return createTable(nextTableIndex, 1);
+ }
+
+ default ClassifyAddDelTable createTable(final int nextTableIndex, @Nonnegative final int numberOfSessions) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = 1;
+ request.tableIndex = -1; // value not present
+ request.nbuckets = numberOfSessions;
+ request.nextTableIndex = nextTableIndex;
+
+
+ // TODO: HONEYCOMB-181 minimise memory used by classify tables (we create a lot of them to make ietf-acl model
+ // mapping more convenient):
+ // according to https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers#Creating_a_classifier_table,
+ // classify table needs 16*(1 + match_n_vectors) bytes, but this does not quite work,
+ // so setting 8K +1k*numberOfSessions for now
+ checkArgument(numberOfSessions>0, "negative numberOfSessions %s", numberOfSessions);
+ request.memorySize = TABLE_MEM_SIZE+1024*(numberOfSessions-1);
+ request.missNextIndex = -1; // value not set, but anyway it is ignored for tables in chain
+ return request;
+ }
+
+ default ClassifyAddDelSession createSession(@Nonnull final PacketHandling action, final int tableIndex) {
+ final ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = 1;
+ request.tableIndex = tableIndex;
+ request.opaqueIndex = ~0; // value not used
+
+ if (action instanceof Permit) {
+ request.hitNextIndex = -1;
+ } // deny (0) is default value
+
+ return request;
+ }
+
+ default int getVlanTagsLen(final int vlanTags) {
+ return vlanTags * VLAN_TAG_LEN;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/IetfAclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/IetfAclWriter.java
new file mode 100644
index 000000000..7f31dc06d
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/IetfAclWriter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.List;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface IetfAclWriter {
+ default void write(@Nonnull final InstanceIdentifier<?> id, final int ifIndex, @Nonnull final List<Acl> acls,
+ final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ write(id, ifIndex, acls, defaultAction, mode, writeContext, 0, mappingContext);
+ }
+
+ void write(@Nonnull final InstanceIdentifier<?> id, int ifIndex, @Nonnull final List<Acl> acls,
+ final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException;
+
+ void deleteAcl(@Nonnull final InstanceIdentifier<?> id, int ifIndex, @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException;
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip4AclTranslator.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip4AclTranslator.java
new file mode 100644
index 000000000..ad70fd844
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip4AclTranslator.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import com.google.common.primitives.Ints;
+import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+
+interface Ip4AclTranslator extends Ipv4Translator {
+ int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
+ int DSCP_OFFSET = 15;
+ int DSCP_MASK = 0xfc;
+
+ int IP_PROTOCOL_OFFSET = ETHER_TYPE_OFFSET + 11;
+ int IP_PROTOCOL_MASK = 0xff;
+
+ int IP4_LEN = 4;
+ int IP4_MASK_BIT_LENGTH = 32;
+ int SRC_IP_OFFSET = ETHER_TYPE_OFFSET + 14;
+ int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN;
+ int SRC_PORT_OFFSET = DST_IP_OFFSET + IP4_LEN;
+ int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2;
+
+ default boolean ip4Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv4HeaderFields ip4, final ClassifyAddDelTable request) {
+ boolean aceIsEmpty = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // in L2 mode we need to match ether type
+ request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDscp() != null) {
+ aceIsEmpty = false;
+ request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ aceIsEmpty = false;
+ request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (ip4.getSourceIpv4Network() != null) {
+ aceIsEmpty = false;
+ System.arraycopy(Impl.toByteMask(ip4.getSourceIpv4Network()), 0, request.mask,
+ baseOffset + SRC_IP_OFFSET, IP4_LEN);
+ }
+ if (ip4.getDestinationIpv4Network() != null) {
+ aceIsEmpty = false;
+ System.arraycopy(Impl.toByteMask(ip4.getDestinationIpv4Network()), 0, request.mask,
+ baseOffset + DST_IP_OFFSET, IP4_LEN);
+ }
+ return aceIsEmpty;
+ }
+
+ default boolean ip4Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv4HeaderFields ip4, final Integer srcPort,
+ final Integer dstPort, final ClassifyAddDelSession request) {
+ boolean noMatch = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // match IP4 etherType (0x0800)
+ request.match[baseOffset + ETHER_TYPE_OFFSET] = 0x08;
+ request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = 0x00;
+ }
+ if (header.getDscp() != null) {
+ noMatch = false;
+ request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (header.getDscp().getValue() << 2));
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ noMatch = false;
+ request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
+ }
+ if (srcPort != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8);
+ request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort);
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8);
+ request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort);
+ }
+ if (ip4.getSourceIpv4Network() != null) {
+ noMatch = false;
+ System.arraycopy(Impl.toMatchValue(ip4.getSourceIpv4Network()), 0, request.match,
+ baseOffset + SRC_IP_OFFSET, IP4_LEN);
+
+ }
+ if (ip4.getDestinationIpv4Network() != null) {
+ noMatch = false;
+ System.arraycopy(Impl.toMatchValue(ip4.getDestinationIpv4Network()), 0, request.match,
+ baseOffset + DST_IP_OFFSET, IP4_LEN);
+
+ }
+ return noMatch;
+ }
+
+ class Impl {
+ private static byte[] toByteMask(final int prefixLength) {
+ final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength);
+ return Ints.toByteArray((int) mask);
+ }
+
+ private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) {
+ final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]);
+ return toByteMask(prefixLength);
+ }
+
+ private static byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) {
+ final String[] split = ipv4Prefix.getValue().split("/");
+ final byte[] addressBytes = Ipv4Translator.INSTANCE.ipv4AddressNoZoneToArray(split[0]);
+ final byte[] mask = Impl.toByteMask(Byte.valueOf(split[1]));
+ for (int i = 0; i < addressBytes.length; ++i) {
+ addressBytes[i] &= mask[i];
+ }
+ return addressBytes;
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip6AclTranslator.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip6AclTranslator.java
new file mode 100644
index 000000000..f11a3d6a3
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/Ip6AclTranslator.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.BitSet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields;
+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.classifier.acl.rev161214.InterfaceMode;
+
+interface Ip6AclTranslator {
+
+ int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
+ int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2;
+ int DSCP_MASK1 = 0x0f;
+ int DSCP_MASK2 = 0xc0;
+ int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6;
+ int IP_PROTOCOL_MASK = 0xff;
+ int IP6_LEN = 16;
+ int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
+ int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
+ int SRC_PORT_OFFSET = DST_IP_OFFSET + IP6_LEN;
+ int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2;
+
+ default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request) {
+ boolean aceIsEmpty = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // in L2 mode we need to match ether type
+ request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDscp() != null) {
+ aceIsEmpty = false;
+ // DCSP (bits 4-9 of IP6 header)
+ request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ aceIsEmpty = false;
+ request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
+ }
+ if (ip6.getFlowLabel() != null) {
+ aceIsEmpty = false;
+ // bits 12-31
+ request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff;
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (ip6.getSourceIpv6Network() != null) {
+ aceIsEmpty = false;
+ final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network());
+ System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
+ }
+ if (ip6.getDestinationIpv6Network() != null) {
+ aceIsEmpty = false;
+ final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network());
+ System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
+ }
+ return aceIsEmpty;
+ }
+
+ default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv6HeaderFields ip6, final Integer srcPort, final Integer dstPort, final ClassifyAddDelSession request) {
+ boolean noMatch = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // match IP6 etherType (0x86dd)
+ request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86;
+ request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd;
+ }
+ if (header.getDscp() != null) {
+ noMatch = false;
+ final int dcsp = header.getDscp().getValue();
+ // set bits 4-9 of IP6 header:
+ request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2));
+ request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6));
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ noMatch = false;
+ request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
+ }
+ if (ip6.getFlowLabel() != null) {
+ noMatch = false;
+ final int flowLabel = ip6.getFlowLabel().getValue().intValue();
+ // bits 12-31
+ request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16));
+ request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8));
+ request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel);
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8);
+ request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort);
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8);
+ request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort);
+ }
+ if (ip6.getSourceIpv6Network() != null) {
+ noMatch = false;
+ final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network());
+ System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
+ }
+ if (ip6.getDestinationIpv6Network() != null) {
+ noMatch = false;
+ final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network());
+ System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
+ }
+ return noMatch;
+ }
+
+ class Impl {
+ private static final int IP6_MASK_BIT_LENGTH = 128;
+
+ private static byte[] toByteMask(final int prefixLength) {
+ final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH);
+ mask.set(0, prefixLength, true);
+ if (prefixLength < IP6_MASK_BIT_LENGTH) {
+ mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false);
+ }
+ return mask.toByteArray();
+ }
+
+ private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) {
+ final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]);
+ return toByteMask(prefixLength);
+ }
+
+ private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) {
+ final String[] split = ipv6Prefix.getValue().split("/");
+ final byte[] addressBytes;
+ try {
+ addressBytes = InetAddress.getByName(split[0]).getAddress();
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid IP6 address", e);
+ }
+ final byte[] mask = toByteMask(Short.valueOf(split[1]));
+ int pos = 0;
+ for (; pos < mask.length; ++pos) {
+ addressBytes[pos] &= mask[pos];
+ }
+ // mask can be shorter that address, so we need to clear rest of the address:
+ for (; pos < addressBytes.length; ++pos) {
+ addressBytes[pos] = 0;
+ }
+ return addressBytes;
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/L2AclTranslator.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/L2AclTranslator.java
new file mode 100644
index 000000000..7addf28da
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/L2AclTranslator.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+
+interface L2AclTranslator extends MacTranslator {
+
+ default boolean destinationMacAddressMask(final MacAddress dstMask, final MacAddress dstAddress,
+ final ClassifyAddDelTable request) {
+ // destination-mac-address or destination-mac-address-mask is present =>
+ // ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00
+ if (dstMask != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(dstMask.getValue());
+ int i = 0;
+ for (String part : parts) {
+ request.mask[i++] = parseHexByte(part);
+ }
+ return false;
+ } else if (dstAddress != null) {
+ for (int i = 0; i < 6; ++i) {
+ request.mask[i] = (byte) 0xff;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean sourceMacAddressMask(final MacAddress srcMask, final MacAddress srcAddress,
+ final ClassifyAddDelTable request) {
+ // source-mac-address or source-mac-address-mask =>
+ // 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00
+ if (srcMask != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(srcMask.getValue());
+ int i = 6;
+ for (String part : parts) {
+ request.mask[i++] = parseHexByte(part);
+ }
+ return false;
+ } else if (srcAddress != null) {
+ for (int i = 6; i < 12; ++i) {
+ request.mask[i] = (byte) 0xff;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean destinationMacAddressMatch(final MacAddress dstAddress, final ClassifyAddDelSession request) {
+ if (dstAddress != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(dstAddress.getValue());
+ int i = 0;
+ for (String part : parts) {
+ request.match[i++] = parseHexByte(part);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean sourceMacAddressMatch(final MacAddress srcAddress, final ClassifyAddDelSession request) {
+ if (srcAddress != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(srcAddress.getValue());
+ int i = 6;
+ for (String part : parts) {
+ request.match[i++] = parseHexByte(part);
+ }
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/PortPair.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/PortPair.java
new file mode 100644
index 000000000..339102117
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/common/PortPair.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import javax.annotation.Nullable;
+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;
+
+/**
+ * Utility that produces cartesian product out of src and dst port ranges (used to translate ranges into
+ * list of classify sessions).
+ */
+final class PortPair {
+ private final Integer src;
+ private final Integer dst;
+
+ PortPair(@Nullable final Integer src, @Nullable final Integer dst) {
+ this.src = src;
+ this.dst = dst;
+ }
+
+ Integer getSrc() {
+ return src;
+ }
+
+ Integer getDst() {
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + src + "," + dst + ")";
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final PortPair that = (PortPair) o;
+ if (!Objects.equals(src, that.src)) {
+ return false;
+ }
+ if (!Objects.equals(dst, that.dst)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(src, dst);
+ }
+
+ static List<PortPair> fromRange(final SourcePortRange srcRange,
+ final DestinationPortRange dstRange) {
+ final List<PortPair> result = new ArrayList<>();
+ if (srcRange == null && dstRange == null) {
+ result.add(new PortPair(null, null));
+ } else if (srcRange != null && dstRange == null) {
+ processSingleRange(result, srcRange.getLowerPort(), srcRange.getUpperPort(), PortPair::new);
+ } else if (srcRange == null && dstRange != null) {
+ processSingleRange(result, dstRange.getLowerPort(), dstRange.getUpperPort(),
+ (dst, src) -> new PortPair(src, dst));
+ } else {
+ processDoubleRange(result, srcRange, dstRange);
+ }
+ return result;
+ }
+
+ private static void processSingleRange(final List<PortPair> result,
+ final PortNumber lowerPort,
+ final PortNumber upperPort,
+ final BiFunction<Integer, Integer, PortPair> f) {
+ int low = lowerPort.getValue(); // mandatory
+ int hi = low;
+ if (upperPort != null) {
+ hi = upperPort.getValue();
+ }
+ for (; low <= hi; ++low) {
+ result.add(f.apply(low, null));
+ }
+ }
+
+ private static void processDoubleRange(final List<PortPair> result, final SourcePortRange srcRange,
+ final DestinationPortRange dstRange) {
+ int srcL = srcRange.getLowerPort().getValue();
+ int srcH = srcL;
+ if (srcRange.getUpperPort() != null) {
+ srcH = srcRange.getUpperPort().getValue();
+ }
+ int dstL = dstRange.getLowerPort().getValue();
+ int dstH = dstL;
+ if (dstRange.getUpperPort() != null) {
+ dstH = dstRange.getUpperPort().getValue();
+ }
+ for (int i=srcL; i <= srcH; ++i) {
+ for (int j=dstL; j <= dstH; ++j) {
+ result.add(new PortPair(i, j));
+ }
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/EgressIetfAclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/EgressIetfAclWriter.java
new file mode 100644
index 000000000..c279722af
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/EgressIetfAclWriter.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AbstractIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AclTableContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2Tables;
+import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2TablesReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class EgressIetfAclWriter extends AbstractIetfAclWriter {
+ private final AclTableContextManager aclCtx;
+
+ public EgressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull AclTableContextManager aclCtx) {
+ super(futureJVppCore);
+ this.aclCtx = checkNotNull(aclCtx, "aclCtx should not be null");
+ }
+
+ @Override
+ public void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ Optional<MappingEntry> optional = aclCtx.getEntry(swIfIndex, mappingContext);
+ checkState(optional.isPresent(), "Removing ACL id=%s, but acl mapping entry is not present", id);
+ final MappingEntry entry = optional.get();
+ unassignClassifyTables(id, swIfIndex);
+ removeClassifyTables(id, entry);
+ aclCtx.removeEntry(swIfIndex, mappingContext);
+ }
+
+ private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex)
+ throws WriteFailedException {
+ final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables();
+ request.swIfIndex = swIfIndex;
+ request.ip4TableIndex = NOT_DEFINED;
+ request.ip6TableIndex = NOT_DEFINED;
+ request.otherTableIndex = NOT_DEFINED;
+ request.isInput = 0; // egress
+ final CompletionStage<ClassifySetInterfaceL2TablesReply> cs = jvpp.classifySetInterfaceL2Tables(request);
+ getReplyForDelete(cs.toCompletableFuture(), id);
+ }
+
+ @Override
+ public void write(@Nonnull final InstanceIdentifier<?> id, int swIfIndex, @Nonnull final List<Acl> acls,
+ @Nonnull final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range");
+ checkArgument(InterfaceMode.L2.equals(mode), "Writing egress Acls is supported only in L2 mode");
+
+ final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables();
+ request.isInput = 0; // egress
+ request.swIfIndex = swIfIndex;
+
+ // applied to packets according to their ether type
+ final List<Ace> ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path));
+ request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path));
+ request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> aces = getACEs(acls, writeContext, EgressIetfAclWriter::isNotIpRule);
+ request.otherTableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags);
+
+ final MappingEntry entry = new MappingEntryBuilder().setIndex(swIfIndex)
+ .setIp4TableId(request.ip4TableIndex)
+ .setIp6TableId(request.ip6TableIndex)
+ .setL2TableId(request.otherTableIndex)
+ .build();
+ aclCtx.addEntry(entry, mappingContext);
+
+ try {
+ getReplyForWrite(jvpp.classifySetInterfaceL2Tables(request).toCompletableFuture(), id);
+ } catch (WriteFailedException e) {
+ removeClassifyTables(id, entry);
+ throw e;
+ }
+ }
+
+ private static boolean isNotIpRule(final Ace ace) {
+ final Matches matches = ace.getMatches();
+ checkArgument(matches != null, "Incomplete ACE: %s", ace);
+ return matches.getAceType() instanceof AceEth;
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/IetfAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/IetfAclCustomizer.java
new file mode 100644
index 000000000..1d457ac52
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/IetfAclCustomizer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.IetfAclWriter;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Egress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IetfAclCustomizer implements WriterCustomizer<Egress> {
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
+ private final IetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public IetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Adding egress ACLs for interface={}(id={}): {}", ifName, ifIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ if (!InterfaceMode.L2.equals(accessLists.getMode())) {
+ LOG.debug("Writing egress Acls is supported only in L2 mode. Ignoring config: {}", dataAfter);
+ return;
+ }
+
+ aclWriter.write(id, ifIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for interface={}(id={}): {}", ifName, ifIndex, dataBefore);
+ aclWriter.deleteAcl(id, ifIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/SubInterfaceIetfAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/SubInterfaceIetfAclCustomizer.java
new file mode 100644
index 000000000..9873a3143
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/egress/SubInterfaceIetfAclCustomizer.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.IetfAclWriter;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<Egress> {
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
+ private final IetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Egress> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Adding IETF-ACL for sub-interface: {}(id={}): {}", subInterfaceName, subInterfaceIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ final Optional<SubInterface> subInterfaceOptional =
+ writeContext.readAfter(id.firstIdentifierOf(SubInterface.class));
+ checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id);
+ final SubInterface subInterface = subInterfaceOptional.get();
+
+ if (!InterfaceMode.L2.equals(accessLists.getMode())) {
+ LOG.debug("Writing egress Acls is supported only in L2 mode. Ignoring config: {}", dataAfter);
+ return;
+ }
+
+ aclWriter
+ .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, getNumberOfTags(subInterface.getTags()), writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Sub-interface ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("Sub-interface ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("Sub-interface ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore);
+ aclWriter.deleteAcl(id, subInterfaceIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclCustomizer.java
new file mode 100644
index 000000000..fb2c2180d
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclCustomizer.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+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.core.future.FutureJVppCore;
+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.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs on given interface based on low lever classfier model.
+ */
+public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Ingress>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final Ingress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(false, id, dataBefore, writeContext);
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress acl,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, ifIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclWriter.java
new file mode 100644
index 000000000..7a3e5c5a0
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/AclWriter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+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.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.AclBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+interface AclWriter extends ByteDataTranslator, JvppReplyConsumer {
+
+ default void inputAclSetInterface(@Nonnull final FutureJVppCore futureJVppCore, final boolean isAdd,
+ @Nonnull final InstanceIdentifier<?> id, @Nonnull final AclBaseAttributes acl,
+ @Nonnegative final int ifIndex,
+ @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = booleanToByte(isAdd);
+ request.swIfIndex = ifIndex;
+ request.l2TableIndex = ~0; // skip
+ request.ip4TableIndex = ~0; // skip
+ request.ip6TableIndex = ~0; // skip
+
+ final L2Acl l2Acl = acl.getL2Acl();
+ if (l2Acl != null) {
+ final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null");
+ request.l2TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+ final Ip4Acl ip4Acl = acl.getIp4Acl();
+ if (ip4Acl != null) {
+ final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null");
+ request.ip4TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+ final Ip6Acl ip6Acl = acl.getIp6Acl();
+ if (ip6Acl != null) {
+ final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null");
+ request.ip6TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ futureJVppCore.inputAclSetInterface(request);
+
+ getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IetfAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IetfAclCustomizer.java
new file mode 100644
index 000000000..842c1596f
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IetfAclCustomizer.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+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 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.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs for given interface (as defined in ietf-acl model).
+ *
+ * The customizer assumes it owns classify table management for interfaces where ietf-acl container is present. Using
+ * low level classifier model or direct changes to classify tables in combination with ietf-acls are not supported and
+ * can result in unpredictable behaviour.
+ */
+public class IetfAclCustomizer implements WriterCustomizer<Ingress> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
+ private final IngressIetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public IetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter,
+ @Nonnull final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Adding ACLs for interface={}(id={}): {}", ifName, ifIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ aclWriter.write(id, ifIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for interface={}(id={}): {}", ifName, ifIndex, dataBefore);
+ aclWriter.deleteAcl(id, ifIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IngressIetfAclWriter.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IngressIetfAclWriter.java
new file mode 100644
index 000000000..42b18aeb8
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/IngressIetfAclWriter.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AbstractIetfAclWriter;
+import io.fd.hc2vpp.vpp.classifier.write.acl.common.AclTableContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class IngressIetfAclWriter extends AbstractIetfAclWriter {
+ private final AclTableContextManager aclCtx;
+
+ public IngressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull AclTableContextManager aclCtx) {
+ super(futureJVppCore);
+ this.aclCtx = checkNotNull(aclCtx, "aclCtx should not be null");
+ }
+
+ @Override
+ public void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ Optional<MappingEntry> optional = aclCtx.getEntry(swIfIndex, mappingContext);
+ checkState(optional.isPresent(), "Removing ACL id=%s, but acl mapping entry is not present", id);
+ final MappingEntry entry = optional.get();
+ unassignClassifyTables(id, entry);
+ removeClassifyTables(id, entry);
+ aclCtx.removeEntry(swIfIndex, mappingContext);
+ }
+
+ private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final MappingEntry entry)
+ throws WriteFailedException {
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = 0;
+ request.swIfIndex = entry.getIndex();
+ request.l2TableIndex = entry.getL2TableId();
+ request.ip4TableIndex = entry.getIp4TableId();
+ request.ip6TableIndex = entry.getIp6TableId();
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ jvpp.inputAclSetInterface(request);
+ getReplyForDelete(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ @Override
+ public void write(@Nonnull final InstanceIdentifier<?> id, int swIfIndex, @Nonnull final List<Acl> acls,
+ @Nonnull final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range");
+
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = 1;
+ request.swIfIndex = swIfIndex;
+ request.l2TableIndex = NOT_DEFINED;
+ request.ip4TableIndex = NOT_DEFINED;
+ request.ip6TableIndex = NOT_DEFINED;
+
+ if (InterfaceMode.L2.equals(mode)) {
+ final List<Ace> aces = getACEs(acls, writeContext, ace -> true);
+ request.l2TableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags);
+ } else {
+ final List<Ace> ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path));
+ request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path));
+ request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags);
+ }
+
+ final MappingEntry entry = new MappingEntryBuilder().setIndex(swIfIndex)
+ .setIp4TableId(request.ip4TableIndex)
+ .setIp6TableId(request.ip6TableIndex)
+ .setL2TableId(request.l2TableIndex)
+ .build();
+ aclCtx.addEntry(entry, mappingContext);
+
+ try {
+ getReplyForWrite(jvpp.inputAclSetInterface(request).toCompletableFuture(), id);
+ } catch (WriteFailedException e) {
+ removeClassifyTables(id, entry);
+ throw e;
+ }
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..d864a9811
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceAclCustomizer.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
+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.core.future.FutureJVppCore;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements WriterCustomizer<Ingress>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore vppApi,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final Ingress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(false, id, dataBefore, writeContext);
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress acl,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ final String subInterfaceName = SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, subInterfaceIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceIetfAclCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceIetfAclCustomizer.java
new file mode 100644
index 000000000..6f161b858
--- /dev/null
+++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/acl/ingress/SubInterfaceIetfAclCustomizer.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017 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.vpp.classifier.write.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.vpp.acl.attributes.ietf.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs for given sub-interface (as defined in ietf-acl model).
+ *
+ * The customizer assumes it owns classify table management for sub-interfaces where ietf-acl container is present.
+ * Using low level classifier model or direct changes to classify tables in combination with ietf-acls are not supported
+ * and can result in unpredictable behaviour.
+ */
+public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<Ingress> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
+ private final IngressIetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter,
+ @Nonnull final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Ingress> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Adding IETF-ACL for sub-interface: {}(id={}): {}", subInterfaceName, subInterfaceIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ final Optional<SubInterface> subInterfaceOptional =
+ writeContext.readAfter(id.firstIdentifierOf(SubInterface.class));
+ checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id);
+ final SubInterface subInterface = subInterfaceOptional.get();
+
+ aclWriter
+ .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, getNumberOfTags(subInterface.getTags()), writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Sub-interface ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("Sub-interface ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("Sub-interface ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore);
+ aclWriter.deleteAcl(id, subInterfaceIndex, writeContext.getMappingContext());
+ }
+}