HC2VPP-55: policer&policer assignment CRUD support 31/5731/3
authorMarek Gradzki <[email protected]>
Fri, 10 Mar 2017 11:50:53 +0000 (12:50 +0100)
committerMarek Gradzki <[email protected]>
Tue, 14 Mar 2017 13:31:10 +0000 (14:31 +0100)
Change-Id: I627d2a56ab2a282744ea0172b4a0c72240b0032f
Signed-off-by: Marek Gradzki <[email protected]>
17 files changed:
vpp-classifier/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/policer/rev170315/DscpTypeBuilder.java [new file with mode: 0644]
vpp-classifier/api/src/main/yang/interface-policer.yang
vpp-classifier/api/src/main/yang/policer.yang
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/PolicerModule.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerCustomizer.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerReaderFactory.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerCustomizer.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerReaderFactory.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerCustomizer.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerWriterFactory.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerCustomizer.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerWriterFactory.java [new file with mode: 0644]
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/VppClassifierModule.java
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/factory/write/VppClassifierHoneycombWriterFactory.java
vpp-classifier/impl/src/main/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriter.java
vpp-classifier/impl/src/test/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriterTest.java
vpp-integration/minimal-distribution/pom.xml

diff --git a/vpp-classifier/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/policer/rev170315/DscpTypeBuilder.java b/vpp-classifier/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/policer/rev170315/DscpTypeBuilder.java
new file mode 100644 (file)
index 0000000..f204f8c
--- /dev/null
@@ -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 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp;
+
+/**
+ * The purpose of generated class in src/main/java for Union types is to create new instances of unions from a string representation.
+ * In some cases it is very difficult to automate it since there can be unions such as (uint32 - uint16), or (string - uint32).
+ *
+ * The reason behind putting it under src/main/java is:
+ * This class is generated in form of a stub and needs to be finished by the user. This class is generated only once to prevent
+ * loss of user code.
+ *
+ */
+public class DscpTypeBuilder {
+
+    public static DscpType getDefaultInstance(java.lang.String defaultValue) {
+        final VppDscpType vppDscpType = VppDscpType.valueOf(defaultValue);
+        if (vppDscpType != null) {
+            return new DscpType(vppDscpType);
+        }
+        return new DscpType(Dscp.getDefaultInstance(defaultValue));
+    }
+}
index d92faa9..2fd7b6b 100644 (file)
@@ -27,23 +27,25 @@ module interface-policer {
     }
 
     grouping interface-policer-attributes {
-        description
-            "Defines references to policer classify tables.
-            At least one table reference should be specified.";
-        leaf l2-table {
-            type vpp-classifier:classify-table-ref;
+        container policer {
             description
-                "An L2 policer table";
-        }
-        leaf ip4-table {
-            type vpp-classifier:classify-table-ref;
-            description
-                "An IPv4 policer table";
-        }
-        leaf ip6-table {
-            type vpp-classifier:classify-table-ref;
-            description
-                "An IPv6 policer table";
+                "Defines references to policer classify tables.
+                 At least one table reference should be specified.";
+            leaf l2-table {
+                type vpp-classifier:classify-table-ref;
+                description
+                    "An L2 policer table";
+            }
+            leaf ip4-table {
+                type vpp-classifier:classify-table-ref;
+                description
+                    "An IPv4 policer table";
+            }
+            leaf ip6-table {
+                type vpp-classifier:classify-table-ref;
+                description
+                    "An IPv6 policer table";
+            }
         }
     }
 
index 1f730b6..6379671 100644 (file)
@@ -91,7 +91,7 @@ module policer {
         "transmit action type in a meter";
     }
 
-    typedef vpp-dcsp-type {
+    typedef vpp-dscp-type {
         description
             "DSCP field values supported by VPP";
         type enumeration {
@@ -162,9 +162,9 @@ module policer {
         default CS0;
     }
 
-    typedef dcsp-type {
+    typedef dscp-type {
         type union {
-            type vpp-dcsp-type;
+            type vpp-dscp-type;
             type inet:dscp;
         }
     }
@@ -182,7 +182,7 @@ module policer {
       }
       leaf dscp {
         when "../meter-action-type = meter-action-mark-dscp";
-        type dcsp-type;
+        type dscp-type;
         description
           "dscp marking";
       }
@@ -217,12 +217,15 @@ module policer {
             type boolean;
         }
         container conform-action {
+            presence "Defines conform action";
             uses meter-action-params;
         }
         container exceed-action {
+            presence "Defines exceed action";
             uses meter-action-params;
         }
         container violate-action {
+            presence "Defines violate action";
             uses meter-action-params;
         }
     }
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/PolicerModule.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/PolicerModule.java
new file mode 100644 (file)
index 0000000..86ad72a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.policer;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.policer.read.InterfacePolicerReaderFactory;
+import io.fd.hc2vpp.policer.read.PolicerReaderFactory;
+import io.fd.hc2vpp.policer.write.InterfacePolicerWriterFactory;
+import io.fd.hc2vpp.policer.write.PolicerWriterFactory;
+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 PolicerModule extends AbstractModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PolicerModule.class);
+
+    @Override
+    protected void configure() {
+        LOG.debug("Installing PolicerModule module");
+        install(ConfigurationModule.create());
+
+        // Writers
+        final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+        writerFactoryBinder.addBinding().to(PolicerWriterFactory.class);
+        writerFactoryBinder.addBinding().to(InterfacePolicerWriterFactory.class);
+
+        // Readers
+        final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+        readerFactoryBinder.addBinding().to(PolicerReaderFactory.class);
+        readerFactoryBinder.addBinding().to(InterfacePolicerReaderFactory.class);
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerCustomizer.java
new file mode 100644 (file)
index 0000000..c681758
--- /dev/null
@@ -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.policer.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+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.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.PolicerClassifyDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.PolicerClassifyDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Optional;
+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.opendaylight.params.xml.ns.yang._interface.policer.rev170315.PolicerInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.policer.rev170315._interface.policer.attributes.Policer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.policer.rev170315._interface.policer.attributes.PolicerBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class InterfacePolicerCustomizer extends FutureJVppCustomizer
+    implements ReaderCustomizer<Policer, PolicerBuilder>,
+    JvppReplyConsumer, ByteDataTranslator {
+
+    private static final byte TABLE_IP4 = 0;
+    private static final byte TABLE_IP6 = 1;
+    private static final byte TABLE_L2 = 2;
+
+    private final DumpCacheManager<PolicerClassifyDetailsReplyDump, Byte> dumpManager;
+    private final NamingContext interfaceContext;
+    private final VppClassifierContextManager classifyTableContext;
+
+    InterfacePolicerCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+                               @Nonnull final NamingContext interfaceContext,
+                               @Nonnull final VppClassifierContextManager classifyTableContext) {
+        super(futureJVppCore);
+        this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+        this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+        dumpManager = new DumpCacheManager.DumpCacheManagerBuilder<PolicerClassifyDetailsReplyDump, Byte>()
+            .withExecutor(executor())
+            .acceptOnly(PolicerClassifyDetailsReplyDump.class)
+            .build();
+    }
+
+    private EntityDumpExecutor<PolicerClassifyDetailsReplyDump, Byte> executor() {
+        return (id, type) -> {
+            PolicerClassifyDump request = new PolicerClassifyDump();
+            request.type = type;
+            return getReplyForRead(getFutureJVpp().policerClassifyDump(request).toCompletableFuture(), id);
+        };
+    }
+
+    @Nonnull
+    @Override
+    public PolicerBuilder getBuilder(@Nonnull final InstanceIdentifier<Policer> instanceIdentifier) {
+        return new PolicerBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                      @Nonnull final PolicerBuilder builder,
+                                      @Nonnull final ReadContext ctx)
+        throws ReadFailedException {
+        final String ifcName = id.firstKeyOf(Interface.class).getName();
+        final int ifcIndex = interfaceContext.getIndex(ifcName, ctx.getMappingContext());
+        // FIXME: only first dump will result in jvpp call, so either we improve
+        // DumpCacheManager(HONEYCOMB-348) or we need to do it directly (probably without caching):
+        final Optional<Integer> ip4 = readTableIndex(id, ifcIndex, TABLE_IP4, ctx.getModificationCache());
+        if (ip4.isPresent()) {
+            builder.setIp4Table(classifyTableContext.getTableName(ip4.get(), ctx.getMappingContext()));
+        }
+        final Optional<Integer> ip6 = readTableIndex(id, ifcIndex, TABLE_IP6, ctx.getModificationCache());
+        if (ip6.isPresent()) {
+            builder.setIp6Table(classifyTableContext.getTableName(ip6.get(), ctx.getMappingContext()));
+        }
+        final Optional<Integer> l2 = readTableIndex(id, ifcIndex, TABLE_L2, ctx.getModificationCache());
+        if (l2.isPresent()) {
+            builder.setL2Table(classifyTableContext.getTableName(l2.get(), ctx.getMappingContext()));
+        }
+    }
+
+    private Optional<Integer> readTableIndex(@Nonnull final InstanceIdentifier<Policer> id, final int ifcIndex,
+                                             final byte type,
+                                             final ModificationCache cache) throws ReadFailedException {
+        final com.google.common.base.Optional<PolicerClassifyDetailsReplyDump> dump =
+            dumpManager.getDump(id, cache, type);
+        if (!dump.isPresent() || dump.get().policerClassifyDetails.isEmpty()) {
+            return Optional.empty();
+        }
+        return dump.get().policerClassifyDetails.stream().filter(detail -> detail.swIfIndex == ifcIndex).findFirst()
+            .map(details -> details.tableIndex);
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final Policer policer) {
+        ((PolicerInterfaceStateAugmentationBuilder) builder).setPolicer(policer);
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerReaderFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerReaderFactory.java
new file mode 100644 (file)
index 0000000..da02731
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.policer.read;
+
+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.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.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._interface.policer.rev170315.PolicerInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.policer.rev170315.PolicerInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.policer.rev170315._interface.policer.attributes.Policer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfacePolicerReaderFactory implements ReaderFactory {
+    private static final InstanceIdentifier<Interface> IFC_ID =
+        InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    private static final InstanceIdentifier<PolicerInterfaceStateAugmentation> POLICER_IFC_ID =
+        IFC_ID.augmentation(PolicerInterfaceStateAugmentation.class);
+
+    private static final InstanceIdentifier<Policer> POLICER_IID = POLICER_IFC_ID.child(Policer.class);
+
+    @Inject
+    private FutureJVppCore vppApi;
+    @Inject
+    @Named("interface-context")
+    private NamingContext ifcContext;
+    @Inject
+    @Named("classify-table-context")
+    private VppClassifierContextManager classifyTableContext;
+
+    @Override
+    public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+        InstanceIdentifier<Policer> IID = InstanceIdentifier.create(Policer.class);
+        registry.addStructuralReader(POLICER_IFC_ID, PolicerInterfaceStateAugmentationBuilder.class);
+        registry.add(
+            new GenericReader<>(POLICER_IID, new InterfacePolicerCustomizer(vppApi, ifcContext, classifyTableContext)));
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerCustomizer.java
new file mode 100644 (file)
index 0000000..9d4c40f
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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.policer.read;
+
+import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.Longs;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+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.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.PolicerDetails;
+import io.fd.vpp.jvpp.core.dto.PolicerDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.PolicerDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.math.BigInteger;
+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.inet.types.rev130715.Dscp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.DscpType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionDrop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionMarkDscp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionTransmit;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.PolicerRateType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.PolicerRoundType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.Policers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.PolicersStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.VppDscpType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ConformAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ConformActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ExceedAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ExceedActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ViolateAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ViolateActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.state.Policer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.state.PolicerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.state.PolicerKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class PolicerCustomizer extends FutureJVppCustomizer
+    implements InitializingListReaderCustomizer<Policer, PolicerKey, PolicerBuilder>,
+    JvppReplyConsumer, ByteDataTranslator {
+
+    private final DumpCacheManager<PolicerDetailsReplyDump, Void> dumpManager;
+
+    PolicerCustomizer(@Nonnull final FutureJVppCore futureJVppCore) {
+        super(futureJVppCore);
+        dumpManager = new DumpCacheManager.DumpCacheManagerBuilder<PolicerDetailsReplyDump, Void>()
+            .withExecutor(
+                (id, param) -> getReplyForRead(getFutureJVpp().policerDump(new PolicerDump()).toCompletableFuture(),
+                    id))
+            .acceptOnly(PolicerDetailsReplyDump.class)
+            .build();
+    }
+
+    @Nonnull
+    @Override
+    public List<PolicerKey> getAllIds(@Nonnull final InstanceIdentifier<Policer> id,
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
+        final Optional<PolicerDetailsReplyDump> dump = dumpManager.getDump(id, ctx.getModificationCache(), NO_PARAMS);
+
+        if (!dump.isPresent() || dump.get().policerDetails.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return dump.get().policerDetails.stream().map(detail -> new PolicerKey(toString(detail.name)))
+            .collect(Collectors.toList());
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<Policer> list) {
+        ((PolicersStateBuilder) builder).setPolicer(list);
+    }
+
+    @Nonnull
+    @Override
+    public PolicerBuilder getBuilder(@Nonnull final InstanceIdentifier<Policer> id) {
+        return new PolicerBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                      @Nonnull final PolicerBuilder builder,
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
+        final Optional<PolicerDetailsReplyDump> dump = dumpManager.getDump(id, ctx.getModificationCache(), NO_PARAMS);
+
+        if (!dump.isPresent() || dump.get().policerDetails.isEmpty()) {
+            return;
+        }
+        final PolicerKey key = id.firstKeyOf(Policer.class);
+        final java.util.Optional<PolicerDetails> result =
+            dump.get().policerDetails.stream().filter(detail -> key.equals(new PolicerKey(toString(detail.name)))).findFirst();
+        if (!result.isPresent()) {
+            return;
+        }
+        final PolicerDetails details = result.get();
+        builder.setName(toString(details.name));
+        builder.setCir(UnsignedInts.toLong(details.cir));
+        builder.setEir(UnsignedInts.toLong(details.eir));
+        // TODO(HC2VPP-117): policer init fails if cb is configured (looks like byte ordering issue on VPP side)
+        builder.setCb(toUnsignedBigInteger(details.cb));
+        builder.setEb(toUnsignedBigInteger(details.eb));
+        builder.setRateType(PolicerRateType.forValue(details.rateType));
+        builder.setRoundType(PolicerRoundType.forValue(details.roundType));
+        builder.setType(MeterType.forValue(details.type));
+        builder.setColorAware(byteToBoolean(details.colorAware));
+        builder.setConformAction(parseConformAction(details));
+        builder.setExceedAction(parseExceedAction(details));
+        builder.setViolateAction(parseViolateAction(details));
+
+        // operational only data:
+        builder.setSingleRate(byteToBoolean(details.singleRate));
+        builder.setScale(UnsignedInts.toLong(details.scale));
+        builder.setCirTokensPerPeriod(UnsignedInts.toLong(details.cirTokensPerPeriod));
+        builder.setPirTokensPerPeriod(UnsignedInts.toLong(details.pirTokensPerPeriod));
+        builder.setCurrentLimit(UnsignedInts.toLong(details.currentLimit));
+        builder.setCurrentBucket(UnsignedInts.toLong(details.currentBucket));
+        builder.setExtendedLimit(UnsignedInts.toLong(details.extendedLimit));
+        builder.setExtendedBucket(UnsignedInts.toLong(details.extendedBucket));
+        builder.setLastUpdateTime(toUnsignedBigInteger(details.lastUpdateTime));
+    }
+
+    private BigInteger toUnsignedBigInteger(final long value) {
+        return new BigInteger(1, Longs.toByteArray(value));
+    }
+
+    private Class<? extends MeterActionType> parseMeterActionType(final byte actionType) {
+        switch (actionType) {
+            case 0:
+                return MeterActionDrop.class;
+            case 1:
+                return MeterActionTransmit.class;
+            case 2:
+                return MeterActionMarkDscp.class;
+            default:
+                throw new IllegalArgumentException("Unsupported meter action type " + actionType);
+        }
+    }
+
+    private DscpType parseDscp(final byte dscp, final byte conformActionType) {
+        if (dscp == -1 || conformActionType != 2) {
+            return null;
+        }
+        VppDscpType vppDcspType = VppDscpType.forValue(dscp);
+        if (vppDcspType != null) {
+            return new DscpType(vppDcspType);
+        }
+        return new DscpType(new Dscp((short) dscp));
+    }
+
+    private ConformAction parseConformAction(final PolicerDetails details) {
+        ConformActionBuilder action = new ConformActionBuilder();
+        action.setMeterActionType(parseMeterActionType(details.conformActionType));
+        action.setDscp(parseDscp(details.conformDscp, details.conformActionType));
+        return action.build();
+    }
+
+
+    private ExceedAction parseExceedAction(final PolicerDetails details) {
+        ExceedActionBuilder action = new ExceedActionBuilder();
+        action.setMeterActionType(parseMeterActionType(details.exceedActionType));
+        action.setDscp(parseDscp(details.exceedDscp, details.conformActionType));
+        return action.build();
+    }
+
+    private ViolateAction parseViolateAction(final PolicerDetails details) {
+        ViolateActionBuilder action = new ViolateActionBuilder();
+        action.setMeterActionType(parseMeterActionType(details.violateActionType));
+        action.setDscp(parseDscp(details.violateDscp, details.conformActionType));
+        return action.build();
+    }
+
+    @Nonnull
+    @Override
+    public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<Policer> id,
+                                                  @Nonnull final Policer policer,
+                                                  @Nonnull final ReadContext readContext) {
+        return Initialized.create(getCfgId(id),
+            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.PolicerBuilder(
+                policer)
+                .setName(policer.getName())
+                .build());
+    }
+
+    private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.Policer> getCfgId(
+        final InstanceIdentifier<Policer> id) {
+        final PolicerKey key = id.firstKeyOf(Policer.class);
+        return InstanceIdentifier.create(Policers.class).child(
+            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.Policer.class,
+            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.PolicerKey(
+                key.getName()));
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerReaderFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerReaderFactory.java
new file mode 100644 (file)
index 0000000..3636d0f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.policer.read;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+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.policer.rev170315.PolicersState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.PolicersStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ConformAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ExceedAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ViolateAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.state.Policer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class PolicerReaderFactory implements ReaderFactory {
+    private static final InstanceIdentifier<PolicersState> ROOT_IID = InstanceIdentifier.create(PolicersState.class);
+    private static final InstanceIdentifier<Policer> POLICER_IID = ROOT_IID.child(Policer.class);
+
+    @Inject
+    private FutureJVppCore vppApi;
+
+    @Override
+    public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+        InstanceIdentifier<Policer> IID = InstanceIdentifier.create(Policer.class);
+        registry.addStructuralReader(ROOT_IID, PolicersStateBuilder.class);
+        registry.subtreeAdd(
+            Sets.newHashSet(IID.child(ConformAction.class), IID.child(ExceedAction.class),
+                IID.child(ViolateAction.class)),
+            new GenericInitListReader<>(POLICER_IID, new PolicerCustomizer(vppApi)));
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerCustomizer.java
new file mode 100644 (file)
index 0000000..d2c094f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.policer.write;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+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.vpp.classifier.context.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+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.dto.PolicerClassifySetInterface;
+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._interface.policer.rev170315._interface.policer.attributes.Policer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class InterfacePolicerCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Policer>,
+    ByteDataTranslator, JvppReplyConsumer {
+    private static final Logger LOG = LoggerFactory.getLogger(InterfacePolicerCustomizer.class);
+
+    private final NamingContext interfaceContext;
+    private final VppClassifierContextManager classifyTableContext;
+
+    InterfacePolicerCustomizer(@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<Policer> id,
+                                       @Nonnull final Policer dataAfter, @Nonnull final WriteContext writeContext)
+        throws WriteFailedException {
+        LOG.debug("Applying policer id={}: {} to interface", id, dataAfter);
+        assignPolicer(id, dataAfter, true, writeContext.getMappingContext());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                        @Nonnull final Policer dataBefore, @Nonnull final Policer dataAfter,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        LOG.debug("Updating policer-interface assignment id={} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+        assignPolicer(id, dataAfter, true, writeContext.getMappingContext());
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                        @Nonnull final Policer dataBefore, @Nonnull final WriteContext writeContext)
+        throws WriteFailedException {
+        LOG.debug("Removing policer-interface assignment id={} dataBefore={}", id, dataBefore);
+        assignPolicer(id, dataBefore, true, writeContext.getMappingContext());
+    }
+
+    private void assignPolicer(final InstanceIdentifier<Policer> id, final Policer policer, final boolean isAdd,
+                               final MappingContext ctx) throws WriteFailedException {
+        final PolicerClassifySetInterface request = new PolicerClassifySetInterface();
+        request.isAdd = booleanToByte(isAdd);
+
+        request.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), ctx);
+        request.ip4TableIndex = ~0;
+        request.ip6TableIndex = ~0;
+        request.l2TableIndex = ~0;
+        if (policer.getL2Table() != null) {
+            request.l2TableIndex = classifyTableContext.getTableIndex(policer.getL2Table(), ctx);
+        }
+        if (policer.getIp4Table() != null) {
+            request.ip4TableIndex = classifyTableContext.getTableIndex(policer.getIp4Table(), ctx);
+        }
+        if (policer.getIp6Table() != null) {
+            request.ip6TableIndex = classifyTableContext.getTableIndex(policer.getIp6Table(), ctx);
+        }
+        getReplyForWrite(getFutureJVpp().policerClassifySetInterface(request).toCompletableFuture(), id);
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerWriterFactory.java
new file mode 100644 (file)
index 0000000..f07998f
--- /dev/null
@@ -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.policer.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.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._interface.policer.rev170315.PolicerInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.policer.rev170315._interface.policer.attributes.Policer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfacePolicerWriterFactory implements WriterFactory {
+    private static final InstanceIdentifier<Interface> IFC_ID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+    private static final InstanceIdentifier<PolicerInterfaceAugmentation> POLICER_IFC_ID =
+        IFC_ID.augmentation(PolicerInterfaceAugmentation.class);
+    static final InstanceIdentifier<Policer> POLICER_ID = POLICER_IFC_ID.child(Policer.class);
+
+    @Inject
+    private FutureJVppCore vppApi;
+    @Inject
+    @Named("interface-context")
+    private NamingContext ifcContext;
+    @Inject
+    @Named("classify-table-context")
+    private VppClassifierContextManager classifyTableContext;
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+        registry.addAfter(
+            new GenericWriter<>(POLICER_ID, new InterfacePolicerCustomizer(vppApi, ifcContext, classifyTableContext)),
+            Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerCustomizer.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerCustomizer.java
new file mode 100644 (file)
index 0000000..69eff10
--- /dev/null
@@ -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.policer.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+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.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.PolicerAddDel;
+import io.fd.vpp.jvpp.core.dto.PolicerAddDelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.DscpType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionDrop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionMarkDscp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionParams;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionTransmit;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.MeterActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ConformAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ExceedAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ViolateAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.Policer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.PolicerKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PolicerCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Policer, PolicerKey>,
+    JvppReplyConsumer, ByteDataTranslator {
+    private static final Logger LOG = LoggerFactory.getLogger(PolicerCustomizer.class);
+    private final NamingContext policerContext;
+
+    public PolicerCustomizer(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull final NamingContext policerContext) {
+        super(futureJVppCore);
+        this.policerContext = checkNotNull(policerContext, "policerContext should not be null");
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id, @Nonnull final Policer dataAfter,
+                                       @Nonnull final WriteContext ctx) throws WriteFailedException {
+        LOG.debug("Writing Policer {} dataAfter={}", id, dataAfter);
+        final int policerIndex = policerAddDel(id, dataAfter, true);
+        policerContext.addName(policerIndex, dataAfter.getName(), ctx.getMappingContext());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                        @Nonnull final Policer dataBefore,
+                                        @Nonnull final Policer dataAfter, @Nonnull final WriteContext ctx)
+        throws WriteFailedException {
+        LOG.debug("Updating Policer {} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+        policerAddDel(id, dataAfter, true);
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Policer> id,
+                                        @Nonnull final Policer dataBefore,
+                                        @Nonnull final WriteContext ctx)
+        throws WriteFailedException {
+        LOG.debug("Removing Policer {} dataBefore={}", id, dataBefore);
+        policerAddDel(id, dataBefore, false);
+        policerContext.removeName(dataBefore.getName(), ctx.getMappingContext());
+    }
+
+    private int policerAddDel(final InstanceIdentifier<Policer> id, final Policer policer, final boolean isAdd)
+        throws WriteFailedException {
+        final PolicerAddDel request = new PolicerAddDel();
+        request.isAdd = booleanToByte(isAdd);
+        request.name = policer.getName().getBytes(StandardCharsets.US_ASCII);
+
+        // policer_add_del expects host order unlike most of the other VPP APIs
+        // jvpp by default converts ordering to network order, so we need additional reverse
+        if (policer.getCir() != null) {
+            request.cir = Integer.reverseBytes(policer.getCir().intValue());
+        }
+        if (policer.getEir() != null) {
+            request.eir = Integer.reverseBytes(policer.getEir().intValue());
+        }
+        if (policer.getCb() != null) {
+            request.cb = Long.reverseBytes(policer.getCb().longValue());
+        }
+        if (policer.getEb() != null) {
+            request.eb = Long.reverseBytes(policer.getEb().longValue());
+        }
+        if (policer.getRateType() != null) {
+            request.rateType = (byte) policer.getRateType().getIntValue();
+        }
+        if (policer.getRoundType() != null) {
+            request.roundType = (byte) policer.getRoundType().getIntValue();
+        }
+        if (policer.getType() != null) {
+            request.type = (byte) policer.getType().getIntValue();
+        }
+        request.colorAware = booleanToByte(policer.isColorAware());
+        final ConformAction conformAction = policer.getConformAction();
+        if (conformAction != null) {
+            request.conformActionType = parseActiontype(conformAction.getMeterActionType());
+            request.conformDscp = parseDscp(conformAction);
+        }
+        final ExceedAction exceedAction = policer.getExceedAction();
+        if (exceedAction != null) {
+            request.exceedActionType = parseActiontype(exceedAction.getMeterActionType());
+            request.exceedDscp = parseDscp(exceedAction);
+        }
+        final ViolateAction violateAction = policer.getViolateAction();
+        if (violateAction != null) {
+            request.violateActionType = parseActiontype(violateAction.getMeterActionType());
+            request.violateDscp = parseDscp(violateAction);
+        }
+        LOG.debug("Policer config change id={} request={}", id, request);
+        final PolicerAddDelReply reply =
+            getReplyForWrite(getFutureJVpp().policerAddDel(request).toCompletableFuture(), id);
+        return reply.policerIndex;
+    }
+
+    private byte parseDscp(@Nonnull MeterActionParams actionParams) {
+        final DscpType dscp = actionParams.getDscp();
+        if (dscp == null) {
+            return 0;
+        }
+        final Class<? extends MeterActionType> meterActionType = actionParams.getMeterActionType();
+        checkArgument(MeterActionMarkDscp.class == meterActionType,
+            "dcsp is supported only for meter-action-mark-dscp, but %s defined", meterActionType);
+        if (dscp.getVppDscpType() != null) {
+            return (byte) dscp.getVppDscpType().getIntValue();
+        }
+        if (dscp.getDscp() != null) {
+            return dscp.getDscp().getValue().byteValue();
+        }
+        return 0;
+    }
+
+    private byte parseActiontype(@Nonnull final Class<? extends MeterActionType> meterActionType) {
+        if (MeterActionDrop.class == meterActionType) {
+            return 0;
+        } else if (MeterActionTransmit.class == meterActionType) {
+            return 1;
+        } else if (MeterActionMarkDscp.class == meterActionType) {
+            return 2;
+        } else {
+            throw new IllegalArgumentException("Unsupported meter action type " + meterActionType);
+        }
+    }
+}
diff --git a/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerWriterFactory.java b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerWriterFactory.java
new file mode 100644 (file)
index 0000000..43c2f5e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.policer.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.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.policer.rev170315.Policers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ConformAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ExceedAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policer.base.attributes.ViolateAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.policer.rev170315.policers.Policer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class PolicerWriterFactory implements WriterFactory {
+    private static final InstanceIdentifier<Policer> POLICER_IID = InstanceIdentifier.create(Policers.class).child(Policer.class);
+
+    @Inject
+    private FutureJVppCore vppApi;
+    @Inject
+    @Named("policer-context")
+    private NamingContext policerContext;
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+        InstanceIdentifier<Policer> IID = InstanceIdentifier.create(Policer.class);
+        registry.subtreeAdd(
+            Sets.newHashSet(IID.child(ConformAction.class), IID.child(ExceedAction.class),
+                IID.child(ViolateAction.class)),
+            new GenericListWriter<>(POLICER_IID, new PolicerCustomizer(vppApi, policerContext)));
+    }
+}
index 088df72..8a1515c 100644 (file)
@@ -19,6 +19,7 @@ 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.common.translate.util.NamingContext;
 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;
@@ -39,8 +40,12 @@ public class VppClassifierModule extends AbstractModule {
         install(ConfigurationModule.create());
 
         bind(VppClassifierContextManager.class)
-                .annotatedWith(Names.named("classify-table-context"))
-                .toInstance(new VppClassifierContextManagerImpl("classify-table-"));
+            .annotatedWith(Names.named("classify-table-context"))
+            .toInstance(new VppClassifierContextManagerImpl("classify-table-"));
+
+        bind(NamingContext.class)
+            .annotatedWith(Names.named("policer-context"))
+            .toInstance(new NamingContext("policer-", "policer-context"));
 
         // Writers
         final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
index cf34e91..7f5d464 100644 (file)
@@ -18,6 +18,7 @@ package io.fd.hc2vpp.vpp.classifier.factory.write;
 
 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.ClassifySessionWriter;
 import io.fd.hc2vpp.vpp.classifier.write.ClassifyTableWriter;
@@ -41,12 +42,15 @@ public final class VppClassifierHoneycombWriterFactory implements WriterFactory
 
     private final FutureJVppCore jvpp;
     private final VppClassifierContextManager classifyTableContext;
+    private NamingContext policerContext;
 
     @Inject
     public VppClassifierHoneycombWriterFactory(@Nonnull final FutureJVppCore jvpp,
-                                               @Named("classify-table-context") @Nonnull final VppClassifierContextManager classifyTableContext) {
+                                               @Named("classify-table-context") @Nonnull final VppClassifierContextManager classifyTableContext,
+                                               @Named("policer-context") @Nonnull final NamingContext policerContext) {
         this.jvpp = jvpp;
         this.classifyTableContext = classifyTableContext;
+        this.policerContext = policerContext;
     }
 
     @Override
@@ -58,7 +62,7 @@ public final class VppClassifierHoneycombWriterFactory implements WriterFactory
                 CLASSIFY_SESSION_ID);
         //  ClassifyTableSession
         registry.addBefore(
-                new GenericListWriter<>(CLASSIFY_SESSION_ID, new ClassifySessionWriter(jvpp, classifyTableContext)),
+                new GenericListWriter<>(CLASSIFY_SESSION_ID, new ClassifySessionWriter(jvpp, classifyTableContext, policerContext)),
                 InterfaceAclWriterFactory.ACL_ID);
     }
 }
index 8b1db57..be9d944 100644 (file)
@@ -22,6 +22,7 @@ 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.common.translate.util.NamingContext;
 import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
 import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
@@ -36,6 +37,8 @@ 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.session.attributes.NextNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.session.attributes.next_node.Policer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.session.attributes.next_node.Standard;
 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;
@@ -54,11 +57,14 @@ public class ClassifySessionWriter extends VppNodeWriter
 
     private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
     private final VppClassifierContextManager classifyTableContext;
+    private final NamingContext policerContext;
 
     public ClassifySessionWriter(@Nonnull final FutureJVppCore futureJVppCore,
-                                 @Nonnull final VppClassifierContextManager classifyTableContext) {
+                                 @Nonnull final VppClassifierContextManager classifyTableContext,
+                                 @Nonnull final NamingContext policerContext) {
         super(futureJVppCore);
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+        this.policerContext = checkNotNull(policerContext, "policerContext should not be null");
     }
 
     @Override
@@ -109,19 +115,34 @@ public class ClassifySessionWriter extends VppNodeWriter
 
         final ClassifyTable classifyTable =
                 getClassifyTable(writeContext, id.firstIdentifierOf(ClassifyTable.class), isAdd);
-        final int hitNextIndex = getNodeIndex(((Standard)classifySession.getNextNode()).getHitNext(),
-            classifyTable, classifyTableContext,
-                writeContext.getMappingContext(), id);
-        final int opaqueIndex =
-                getOpaqueIndex(((Standard)classifySession.getNextNode()).getOpaqueIndex(), classifyTable, writeContext.getMappingContext(), id);
-
+        final ClassifyAddDelSession request = getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex);
+
+        // TODO(HC2VPP-9): registry of next_node translators would allow to weaken dependency between policer
+        // and vpp-classifier models
+        final NextNode nextNode = classifySession.getNextNode();
+        if (nextNode instanceof Standard) {
+            translateNode(request, id, (Standard)nextNode, classifyTable, writeContext.getMappingContext());
+        } else if (nextNode instanceof Policer) {
+            translateNode(request, (Policer)nextNode, writeContext.getMappingContext());
+        }
         final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
-                .classifyAddDelSession(
-                        getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex, hitNextIndex, opaqueIndex));
+                .classifyAddDelSession(request);
 
         getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
     }
 
+    private void translateNode(final ClassifyAddDelSession request, final InstanceIdentifier<ClassifySession> id,
+                               final Standard nextNode, final ClassifyTable classifyTable, final MappingContext ctx)
+        throws VppBaseCallException, WriteFailedException {
+        request.hitNextIndex = getNodeIndex(nextNode.getHitNext(), classifyTable, classifyTableContext, ctx, id);
+        request.opaqueIndex = getOpaqueIndex(nextNode.getOpaqueIndex(), classifyTable, ctx, id);
+    }
+
+    private void translateNode(final ClassifyAddDelSession request, final Policer policer, final MappingContext ctx) {
+        request.hitNextIndex = policerContext.getIndex(policer.getPolicerHitNext(), ctx);
+        request.opaqueIndex = policer.getColorClassfier().getIntValue();
+    }
+
     private ClassifyTable getClassifyTable(final WriteContext writeContext,
                                            @Nonnull final InstanceIdentifier<ClassifyTable> id,
                                            final boolean isAdd) {
@@ -136,14 +157,10 @@ public class ClassifySessionWriter extends VppNodeWriter
 
     private ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd,
                                                                   @Nonnull final ClassifySession classifySession,
-                                                                  final int tableIndex,
-                                                                  final int hitNextIndex,
-                                                                  final int opaqueIndex) {
+                                                                  final int tableIndex) {
         ClassifyAddDelSession request = new ClassifyAddDelSession();
         request.isAdd = booleanToByte(isAdd);
         request.tableIndex = tableIndex;
-        request.hitNextIndex = hitNextIndex;
-        request.opaqueIndex = opaqueIndex;
 
         // default 0:
         request.advance = classifySession.getAdvance();
index abc3901..31d7ad7 100644 (file)
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
 
 import com.google.common.base.Optional;
 import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
 import io.fd.hc2vpp.vpp.classifier.context.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import io.fd.vpp.jvpp.VppBaseCallException;
@@ -91,7 +92,7 @@ public class ClassifySessionWriterTest extends WriterCustomizerTest {
 
     @Override
     public void setUpTest() throws Exception {
-        customizer = new ClassifySessionWriter(api, classfierContext);
+        customizer = new ClassifySessionWriter(api, classfierContext, new NamingContext("policer-", "policer-context-"));
 
         when(classfierContext.containsTable(TABLE_NAME, mappingContext)).thenReturn(true);
         when(classfierContext.getTableIndex(TABLE_NAME, mappingContext)).thenReturn(TABLE_INDEX);
index 1e73862..3bfa030 100644 (file)
@@ -60,6 +60,7 @@
       io.fd.hc2vpp.routing.RoutingModule,
       io.fd.hc2vpp.acl.AclModule,
       io.fd.hc2vpp.dhcp.DhcpModule,
+      io.fd.hc2vpp.policer.PolicerModule,
       // io.fd.hc2vpp.vppnsh.impl.VppNshModule,
       <!-- Nsh module by default disabled, because it needs vpp-nsh plugin, which is not part of vpp codebase.-->
       // io.fd.hc2vpp.vppioam.impl.VppIoamModule