diff options
Diffstat (limited to 'samples')
14 files changed, 694 insertions, 0 deletions
diff --git a/samples/asciidoc/Readme.adoc b/samples/asciidoc/Readme.adoc new file mode 100644 index 000000000..82961d0fe --- /dev/null +++ b/samples/asciidoc/Readme.adoc @@ -0,0 +1,3 @@ += samples + +Overview of samples
\ No newline at end of file diff --git a/samples/pom.xml b/samples/pom.xml new file mode 100644 index 000000000..a2e058e49 --- /dev/null +++ b/samples/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>hc2vpp-aggregator</artifactId> + <groupId>io.fd.hc2vpp</groupId> + <version>1.17.04-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <groupId>io.fd.hc2vpp.samples</groupId> + <artifactId>samples</artifactId> + <packaging>pom</packaging> + + <modules> + <module>samples-api</module> + <module>samples-impl</module> + </modules> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/samples/samples-api/asciidoc/Readme.adoc b/samples/samples-api/asciidoc/Readme.adoc new file mode 100644 index 000000000..7bc14dc6f --- /dev/null +++ b/samples/samples-api/asciidoc/Readme.adoc @@ -0,0 +1,3 @@ += samples-api + +Overview of samples-api
\ No newline at end of file diff --git a/samples/samples-api/pom.xml b/samples/samples-api/pom.xml new file mode 100644 index 000000000..a6fa1f63b --- /dev/null +++ b/samples/samples-api/pom.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>api-parent</artifactId> + <version>1.17.04-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <groupId>io.fd.hc2vpp.common</groupId> + <artifactId>samples-api</artifactId> + <version>1.17.01-SNAPSHOT</version> + <packaging>bundle</packaging> + + <dependencies> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-inet-types-2013-07-15</artifactId> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/samples/samples-api/src/main/yang/sample-plugin.yang b/samples/samples-api/src/main/yang/sample-plugin.yang new file mode 100644 index 000000000..099ab65b8 --- /dev/null +++ b/samples/samples-api/src/main/yang/sample-plugin.yang @@ -0,0 +1,42 @@ +module sample-plugin { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:sample:plugin"; + prefix "samples"; + + revision 2016-12-14 { + description "Sample model for demonstration of transation code"; + } + + import ietf-inet-types { + prefix "inet"; + } + + grouping sample-plugin-params { + container vxlans { + list vxlan-tunnel { + + key id; + leaf id { + type string; + } + + leaf src { + type inet:ip-address; + } + leaf dst { + type inet:ip-address; + } + } + } + } + + container sample-plugin-state { + config false; + uses sample-plugin-params; + } + + container sample-plugin { + uses sample-plugin-params; + } +}
\ No newline at end of file diff --git a/samples/samples-impl/asciidoc/Readme.adoc b/samples/samples-impl/asciidoc/Readme.adoc new file mode 100644 index 000000000..893c0ebfb --- /dev/null +++ b/samples/samples-impl/asciidoc/Readme.adoc @@ -0,0 +1,3 @@ += samples-impl + +Overview of samples-impl
\ No newline at end of file diff --git a/samples/samples-impl/pom.xml b/samples/samples-impl/pom.xml new file mode 100644 index 000000000..72938cbca --- /dev/null +++ b/samples/samples-impl/pom.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.hc2vpp.common</groupId> + <artifactId>vpp-impl-parent</artifactId> + <version>1.17.04-SNAPSHOT</version> + <relativePath>../../vpp-common/vpp-impl-parent</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>samples-impl</artifactId> + <version>1.17.01-SNAPSHOT</version> + + <dependencies> + <!-- Api classes generated from yang model --> + <dependency> + <groupId>io.fd.hc2vpp.common</groupId> + <artifactId>samples-api</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Infrastructure communication interfaces --> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-spi</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Vpp api java wrapped --> + <dependency> + <groupId>io.fd.vpp</groupId> + <artifactId>jvpp-core</artifactId> + </dependency> + <!-- Infrastructure utils for translation code --> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-utils</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Jvpp specific utils for translation code --> + <dependency> + <groupId>io.fd.hc2vpp.common</groupId> + <artifactId>vpp-translate-utils</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Generic implementations for communication interfaces--> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-impl</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Initialization interfaces for infrastructure--> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>cfg-init</artifactId> + <version>${project.version}</version> + </dependency> + <!-- Google juice injection --> + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + </dependency> + <!-- Google juice multibindings --> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + </dependency> + <!-- Configuration injection --> + <dependency> + <groupId>net.jmob</groupId> + <artifactId>guice.conf</artifactId> + </dependency> + </dependencies> + +</project>
\ No newline at end of file diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java new file mode 100644 index 000000000..d6f38caaf --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.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.samples; + +import com.google.inject.AbstractModule; +import com.google.inject.multibindings.Multibinder; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.samples.read.ModuleStateReaderFactory; +import io.fd.hc2vpp.samples.write.ModuleWriterFactory; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; + + +/** + * Module class instantiating sample-plugin plugin components. + */ +public final class Module extends AbstractModule { + + @Override + protected void configure() { + // requests injection of properties + install(ConfigurationModule.create()); + requestInjection(ModuleConfiguration.class); + + // bind naming context instance for reader and writer factories + // the first parameter is artificial name prefix in cases a name needs to be reconstructed for a vxlan tunnel + // that is present in VPP but not in Honeycomb (could be extracted into configuration) + // the second parameter is just the naming context ID (could be extracted into configuration) + binder().bind(NamingContext.class).toInstance(new NamingContext("vxlan-tunnel", "vxlan-tunnel-context")); + + // creates reader factory binding + // can hold multiple binding for separate yang modules + final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class); + readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class); + + // create writer factory binding + // can hold multiple binding for separate yang modules + final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(ModuleWriterFactory.class); + + + // Disable notification producer for now +// Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding() +// .to(SampleNotificationProducer.class); + } +}
\ No newline at end of file diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java new file mode 100644 index 000000000..6766213ab --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java @@ -0,0 +1,29 @@ +/* + * 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.samples; + + +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +@BindConfig(value = "module", syntax = Syntax.JSON) +public class ModuleConfiguration { + + // inject property from resource file + @InjectConfig(value = "some.prop.name") + String somePropValue; +} diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java new file mode 100644 index 000000000..83e91a2ad --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java @@ -0,0 +1,70 @@ +/* + * 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.samples.read; + +import com.google.inject.Inject; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePluginState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePluginStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.Vxlans; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.VxlansBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import javax.annotation.Nonnull; + +/** + * Factory producing readers for sample-plugin plugin's data. + */ +public final class ModuleStateReaderFactory implements ReaderFactory { + + public static final InstanceIdentifier<SamplePluginState> ROOT_STATE_CONTAINER_ID = + InstanceIdentifier.create(SamplePluginState.class); + + /** + * Injected vxlan naming context shared with writer, provided by this plugin + */ + @Inject + private NamingContext vxlanNamingContext; + /** + * Injected jvpp core APIs, provided by Honeycomb's infrastructure + */ + @Inject + private FutureJVppCore jvppCore; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + // register reader that only delegate read's to its children + registry.addStructuralReader(ROOT_STATE_CONTAINER_ID, SamplePluginStateBuilder.class); + // register reader that only delegate read's to its children + registry.addStructuralReader(ROOT_STATE_CONTAINER_ID.child(Vxlans.class), VxlansBuilder.class); + + // just adds reader to the structure + // use addAfter/addBefore if you want to add specific order to readers on the same level of tree + // use subtreeAdd if you want to handle multiple nodes in single customizer/subtreeAddAfter/subtreeAddBefore if you also want to add order + // be aware that instance identifier passes to subtreeAdd/subtreeAddAfter/subtreeAddBefore should define subtree, + // therefore it should be relative from handled node down - InstanceIdentifier.create(HandledNode), not parent.child(HandledNode.class) + registry.add(new GenericListReader<>( + // What part of subtree this reader handles is identified by an InstanceIdentifier + ROOT_STATE_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class), + // Customizer (the actual translation code to do the heavy lifting) + new VxlanReadCustomizer(jvppCore, vxlanNamingContext))); + } +}
\ No newline at end of file diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java new file mode 100644 index 000000000..133155b6f --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java @@ -0,0 +1,173 @@ +/* + * 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.samples.read; + + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetails; +import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.VxlanTunnelDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.VxlansBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * Reader for {@link VxlanTunnel} list node from our YANG model. + */ +public final class VxlanReadCustomizer implements + ListReaderCustomizer<VxlanTunnel, VxlanTunnelKey, VxlanTunnelBuilder>, + // provides utility methods to translate binary data + ByteDataTranslator, + // provides utility methods to translate Ipv4,Ipv6,Mac addresses. + // in case that just one address family processing is needed,use *address-family-name*Translator, + // for ex Ipv4Translator + AddressTranslator, + // provides utility methods to consume results of jvpp api calls + JvppReplyConsumer { + + // JVpp core. This is the Java API for VPP's core API. + private final FutureJVppCore jVppCore; + // Naming context for interfaces + // Honeycomb provides a "context" storage for plugins. This storage is used for storing metadata required during + // data translation (just like in this plugin). An example of such metadata would be interface identifier. In Honeycomb + // we use string names for interfaces, however VPP uses only indices (that are created automatically). + // This means that translation layer has to store the mapping between HC interface name <-> VPP' interface index. + // And since vxlan tunnel is a type of interface in VPP, the same applies here + // + // Honeycomb provides a couple utilities on top of context storage such as NamingContext. It is just a map + // backed by context storage that makes the lookup and storing easier. + private final NamingContext vxlanNamingContext; + + // Dump manager that provides intelligent caching based on provided contextual key + private DumpCacheManager<VxlanTunnelDetailsReplyDump, Integer> dumpManager; + + public VxlanReadCustomizer(final FutureJVppCore jVppCore, final NamingContext vxlanNamingContext) { + this.jVppCore = jVppCore; + this.vxlanNamingContext = vxlanNamingContext; + + this.dumpManager = new DumpCacheManager.DumpCacheManagerBuilder<VxlanTunnelDetailsReplyDump, Integer>() + // executor handles dumping of data itself, based on provided lambda + // instanceIdentifier - identifier of entity that we are caching, should be the one passed as parameter + // to getAllIds or readCurrentAttributes. Caching is by default performed based on this key + // param - can be anything that needs to be bind to request + .withExecutor((instanceIdentifier, param) -> { + // creates dump request + final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump(); + // binds parameters, in this case index of interface + vxlanTunnelDump.swIfIndex = param; + // perform dump action with default timeout and either return result or throw ReadFailedException + // identified by provided instanceIdentifier + return getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), instanceIdentifier); + }) + // this provides type-awareness for caching, so multiple DumpManagers can be used withing the same + // customizer, using same instance identifiers, as long as they handle different data types + .acceptOnly(VxlanTunnelDetailsReplyDump.class) + + // either acceptOnly is required or custom cache key factory must be provided to tell manager, + // how to produce keys. can be used to change caching scope of data + //.withCacheKeyFactory() + + // serves as post-dump processing of any kind, triggered only once after calling executor + //.withPostProcessingFunction() + .build(); + } + + /** + * Provide a list of IDs for all VXLANs in VPP + */ + @Nonnull + @Override + public List<VxlanTunnelKey> getAllIds(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final ReadContext context) + throws ReadFailedException { + + final Optional<VxlanTunnelDetailsReplyDump> dump = dumpManager.getDump(id, context.getModificationCache(), 0); + + if (!dump.isPresent()) { + return Collections.emptyList(); + } + + return dump.get().vxlanTunnelDetails.stream() + // Need a name of an interface here. Use context to look it up from index + // In case the naming context does not contain such mapping, it creates an artificial one + .map(a -> new VxlanTunnelKey(vxlanNamingContext.getName(a.swIfIndex, context.getMappingContext()))) + .collect(Collectors.toList()); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<VxlanTunnel> readData) { + // Just set the readValue into parent builder + // The cast has to be performed here + ((VxlansBuilder) builder).setVxlanTunnel(readData); + } + + @Nonnull + @Override + public VxlanTunnelBuilder getBuilder(@Nonnull final InstanceIdentifier<VxlanTunnel> id) { + // Setting key from id is not necessary, builder will take care of that + return new VxlanTunnelBuilder(); + } + + /** + * Read all the attributes of a single VXLAN tunnel + */ + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnelBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + // The ID received here contains the name of a particular interface that should be read + // It was either requested directly by HC users or is one of the IDs from getAllIds that could have been invoked + // just before this method invocation + final String vxlanName = id.firstKeyOf(VxlanTunnel.class).getId(); + + // Naming context must contain the mapping because: + // 1. The vxlan tunnel was created in VPP using HC + this plugin meaning we stored the mapping in write customizer + // 2. The vxlan tunnel was already present in VPP, but HC reconciliation mechanism took care of that (as long as proper Initializer is provided by this plugin) + + final Optional<VxlanTunnelDetailsReplyDump> dump = dumpManager.getDump(id, ctx.getModificationCache(), + vxlanNamingContext.getIndex(vxlanName, ctx.getMappingContext())); + + + Preconditions.checkState(dump.isPresent() && dump.get().vxlanTunnelDetails != null); + final VxlanTunnelDetails singleVxlanDetail = dump.get().vxlanTunnelDetails.stream().findFirst().get(); + + // Now translate all attributes into provided builder + final Boolean isIpv6 = byteToBoolean(singleVxlanDetail.isIpv6); + builder.setSrc(arrayToIpAddress(isIpv6, singleVxlanDetail.srcAddress)); + builder.setDst(arrayToIpAddress(isIpv6, singleVxlanDetail.dstAddress)); + // There are additional attributes of a vxlan tunnel that wont be used here + } +}
\ No newline at end of file diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java new file mode 100644 index 000000000..346141429 --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.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.samples.write; + +import com.google.inject.Inject; +import io.fd.hc2vpp.common.translate.util.NamingContext; +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 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePlugin; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.Vxlans; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import javax.annotation.Nonnull; + +/** + * Factory producing writers for sample-plugin plugin's data. + */ +public final class ModuleWriterFactory implements WriterFactory { + + private static final InstanceIdentifier<SamplePlugin> ROOT_CONTAINER_ID = InstanceIdentifier.create(SamplePlugin.class); + + /** + * Injected vxlan naming context shared with writer, provided by this plugin + */ + @Inject + private NamingContext vxlanNamingContext; + /** + * Injected jvpp core APIs, provided by Honeycomb's infrastructure + */ + @Inject + private FutureJVppCore jvppCore; + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + // Unlike ReaderFactory, there's no need to add structural writers, just the writers that actually do something + + // register writer for vxlan tunnel + registry.add(new GenericWriter<>( + // What part of subtree this writer handles is identified by an InstanceIdentifier + ROOT_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class), + // Customizer (the actual translation code to do the heavy lifting) + new VxlanWriteCustomizer(jvppCore, vxlanNamingContext))); + } +}
\ No newline at end of file diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java new file mode 100644 index 000000000..77c67b290 --- /dev/null +++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java @@ -0,0 +1,111 @@ +/* + * 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.samples.write; + + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnel; +import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnelReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import javax.annotation.Nonnull; + +/** + * Writer for {@link VxlanTunnel} list node from our YANG model. + */ +public final class VxlanWriteCustomizer implements ListWriterCustomizer<VxlanTunnel, VxlanTunnelKey>, + ByteDataTranslator, + AddressTranslator, + JvppReplyConsumer { + + /** + * JVpp APIs + */ + private final FutureJVppCore jvppCore; + /** + * Shared vxlan tunnel naming context + */ + private final NamingContext vxlanTunnelNamingContext; + + public VxlanWriteCustomizer(final FutureJVppCore jvppCore, final NamingContext vxlanTunnelNamingContext) { + this.jvppCore = jvppCore; + this.vxlanTunnelNamingContext = vxlanTunnelNamingContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // Create and set vxlan tunnel add request + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + // 1 for add, 0 for delete + vxlanAddDelTunnel.isAdd = 1; + // dataAfter is the new vxlanTunnel configuration + final boolean isIpv6 = dataAfter.getSrc().getIpv6Address() != null; + vxlanAddDelTunnel.isIpv6 = booleanToByte(isIpv6); + vxlanAddDelTunnel.srcAddress = ipAddressToArray(isIpv6, dataAfter.getSrc()); + vxlanAddDelTunnel.dstAddress = ipAddressToArray(isIpv6, dataAfter.getDst()); + // There are other input parameters that are not exposed by our YANG model, default values will be used + + + final VxlanAddDelTunnelReply replyForWrite = getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id); + + // VPP returns the index of new vxlan tunnel + final int newVxlanTunnelIndex = replyForWrite.swIfIndex; + // It's important to store it in context so that reader knows to which name a vxlan tunnel is mapped + vxlanTunnelNamingContext.addName(newVxlanTunnelIndex, dataAfter.getId(), writeContext.getMappingContext()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataBefore, + @Nonnull final VxlanTunnel dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + // Not supported at VPP API level, throw exception + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Vxlan tunnel update is not supported by VPP")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id, + @Nonnull final VxlanTunnel dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // Create and set vxlan tunnel add request + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + // 1 for add, 0 for delete + vxlanAddDelTunnel.isAdd = 0; + // Vxlan tunnel is identified by its attributes when deleting, not index, so set all attributes + // dataBefore is the vxlan tunnel that's being deleted + final boolean isIpv6 = dataBefore.getSrc().getIpv6Address() != null; + vxlanAddDelTunnel.isIpv6 = booleanToByte(isIpv6); + vxlanAddDelTunnel.srcAddress = ipAddressToArray(isIpv6, dataBefore.getSrc()); + vxlanAddDelTunnel.dstAddress = ipAddressToArray(isIpv6, dataBefore.getDst()); + // There are other input parameters that are not exposed by our YANG model, default values will be used + + final VxlanAddDelTunnelReply replyForWrite = getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id); + // It's important to remove the mapping from context + vxlanTunnelNamingContext.removeName(dataBefore.getId(), writeContext.getMappingContext()); + } +}
\ No newline at end of file diff --git a/samples/samples-impl/src/main/resources/module.json b/samples/samples-impl/src/main/resources/module.json new file mode 100644 index 000000000..da70698d2 --- /dev/null +++ b/samples/samples-impl/src/main/resources/module.json @@ -0,0 +1,3 @@ +{ + "some.prop.name":"someValue" +}
\ No newline at end of file |