From 4616f0300655582153362a21910bd1f0b14937ae Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Fri, 10 Mar 2017 12:50:53 +0100 Subject: HC2VPP-55: policer&policer assignment CRUD support Change-Id: I627d2a56ab2a282744ea0172b4a0c72240b0032f Signed-off-by: Marek Gradzki --- .../ns/yang/policer/rev170315/DscpTypeBuilder.java | 39 ++++ .../api/src/main/yang/interface-policer.yang | 34 ++-- vpp-classifier/api/src/main/yang/policer.yang | 11 +- .../java/io/fd/hc2vpp/policer/PolicerModule.java | 50 +++++ .../policer/read/InterfacePolicerCustomizer.java | 122 ++++++++++++ .../read/InterfacePolicerReaderFactory.java | 59 ++++++ .../fd/hc2vpp/policer/read/PolicerCustomizer.java | 218 +++++++++++++++++++++ .../hc2vpp/policer/read/PolicerReaderFactory.java | 50 +++++ .../policer/write/InterfacePolicerCustomizer.java | 97 +++++++++ .../write/InterfacePolicerWriterFactory.java | 60 ++++++ .../fd/hc2vpp/policer/write/PolicerCustomizer.java | 165 ++++++++++++++++ .../hc2vpp/policer/write/PolicerWriterFactory.java | 52 +++++ .../hc2vpp/vpp/classifier/VppClassifierModule.java | 9 +- .../write/VppClassifierHoneycombWriterFactory.java | 8 +- .../classifier/write/ClassifySessionWriter.java | 45 +++-- .../write/ClassifySessionWriterTest.java | 3 +- vpp-integration/minimal-distribution/pom.xml | 1 + 17 files changed, 984 insertions(+), 39 deletions(-) create mode 100644 vpp-classifier/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/policer/rev170315/DscpTypeBuilder.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/PolicerModule.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerCustomizer.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerReaderFactory.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerCustomizer.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerReaderFactory.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerCustomizer.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerWriterFactory.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerCustomizer.java create mode 100644 vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerWriterFactory.java 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 index 000000000..f204f8c6b --- /dev/null +++ b/vpp-classifier/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/policer/rev170315/DscpTypeBuilder.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 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)); + } +} diff --git a/vpp-classifier/api/src/main/yang/interface-policer.yang b/vpp-classifier/api/src/main/yang/interface-policer.yang index d92faa9bf..2fd7b6b83 100644 --- a/vpp-classifier/api/src/main/yang/interface-policer.yang +++ b/vpp-classifier/api/src/main/yang/interface-policer.yang @@ -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"; + } } } diff --git a/vpp-classifier/api/src/main/yang/policer.yang b/vpp-classifier/api/src/main/yang/policer.yang index 1f730b6a5..637967128 100644 --- a/vpp-classifier/api/src/main/yang/policer.yang +++ b/vpp-classifier/api/src/main/yang/policer.yang @@ -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 index 000000000..86ad72a2c --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/PolicerModule.java @@ -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 writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(PolicerWriterFactory.class); + writerFactoryBinder.addBinding().to(InterfacePolicerWriterFactory.class); + + // Readers + final Multibinder 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 index 000000000..c681758f1 --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerCustomizer.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.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, + 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 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() + .withExecutor(executor()) + .acceptOnly(PolicerClassifyDetailsReplyDump.class) + .build(); + } + + private EntityDumpExecutor 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 instanceIdentifier) { + return new PolicerBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier 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 ip4 = readTableIndex(id, ifcIndex, TABLE_IP4, ctx.getModificationCache()); + if (ip4.isPresent()) { + builder.setIp4Table(classifyTableContext.getTableName(ip4.get(), ctx.getMappingContext())); + } + final Optional ip6 = readTableIndex(id, ifcIndex, TABLE_IP6, ctx.getModificationCache()); + if (ip6.isPresent()) { + builder.setIp6Table(classifyTableContext.getTableName(ip6.get(), ctx.getMappingContext())); + } + final Optional l2 = readTableIndex(id, ifcIndex, TABLE_L2, ctx.getModificationCache()); + if (l2.isPresent()) { + builder.setL2Table(classifyTableContext.getTableName(l2.get(), ctx.getMappingContext())); + } + } + + private Optional readTableIndex(@Nonnull final InstanceIdentifier id, final int ifcIndex, + final byte type, + final ModificationCache cache) throws ReadFailedException { + final com.google.common.base.Optional 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 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 index 000000000..da027310a --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/InterfacePolicerReaderFactory.java @@ -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 IFC_ID = + InstanceIdentifier.create(InterfacesState.class).child(Interface.class); + private static final InstanceIdentifier POLICER_IFC_ID = + IFC_ID.augmentation(PolicerInterfaceStateAugmentation.class); + + private static final InstanceIdentifier 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 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 index 000000000..9d4c40f50 --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerCustomizer.java @@ -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, + JvppReplyConsumer, ByteDataTranslator { + + private final DumpCacheManager dumpManager; + + PolicerCustomizer(@Nonnull final FutureJVppCore futureJVppCore) { + super(futureJVppCore); + dumpManager = new DumpCacheManager.DumpCacheManagerBuilder() + .withExecutor( + (id, param) -> getReplyForRead(getFutureJVpp().policerDump(new PolicerDump()).toCompletableFuture(), + id)) + .acceptOnly(PolicerDetailsReplyDump.class) + .build(); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final Optional 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 builder, @Nonnull final List list) { + ((PolicersStateBuilder) builder).setPolicer(list); + } + + @Nonnull + @Override + public PolicerBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new PolicerBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final PolicerBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final Optional 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 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 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 init(@Nonnull final InstanceIdentifier 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 getCfgId( + final InstanceIdentifier 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 index 000000000..3636d0f95 --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/read/PolicerReaderFactory.java @@ -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 ROOT_IID = InstanceIdentifier.create(PolicersState.class); + private static final InstanceIdentifier POLICER_IID = ROOT_IID.child(Policer.class); + + @Inject + private FutureJVppCore vppApi; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + InstanceIdentifier 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 index 000000000..d2c094f0d --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerCustomizer.java @@ -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, + 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 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 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 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 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 index 000000000..f07998fe2 --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/InterfacePolicerWriterFactory.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.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 IFC_ID = + InstanceIdentifier.create(Interfaces.class).child(Interface.class); + private static final InstanceIdentifier POLICER_IFC_ID = + IFC_ID.augmentation(PolicerInterfaceAugmentation.class); + static final InstanceIdentifier 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 index 000000000..69eff100a --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerCustomizer.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.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, + 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 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 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 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 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 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 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 index 000000000..43c2f5ef9 --- /dev/null +++ b/vpp-classifier/impl/src/main/java/io/fd/hc2vpp/policer/write/PolicerWriterFactory.java @@ -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_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 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))); + } +} 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 index 088df72c2..8a1515ca4 100644 --- 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 @@ -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 writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); 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 index cf34e910c..7f5d46471 100644 --- 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 @@ -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); } } 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 index 8b1db57b7..be9d944c6 100644 --- 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 @@ -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 createClassifyTableReplyCompletionStage = getFutureJVpp() - .classifyAddDelSession( - getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex, hitNextIndex, opaqueIndex)); + .classifyAddDelSession(request); getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); } + private void translateNode(final ClassifyAddDelSession request, final InstanceIdentifier 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 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(); diff --git a/vpp-classifier/impl/src/test/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriterTest.java b/vpp-classifier/impl/src/test/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriterTest.java index abc3901b6..31d7ad7f7 100644 --- a/vpp-classifier/impl/src/test/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriterTest.java +++ b/vpp-classifier/impl/src/test/java/io/fd/hc2vpp/vpp/classifier/write/ClassifySessionWriterTest.java @@ -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); diff --git a/vpp-integration/minimal-distribution/pom.xml b/vpp-integration/minimal-distribution/pom.xml index 1e73862c6..3bfa03039 100644 --- a/vpp-integration/minimal-distribution/pom.xml +++ b/vpp-integration/minimal-distribution/pom.xml @@ -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, // io.fd.hc2vpp.vppioam.impl.VppIoamModule -- cgit 1.2.3-korg