1 = Developing plugins for VPP
3 link:release_notes.html[< Home]
5 Honeycomb's primary use case is to provide an agent for VPP. This section provides a tutorial for how to develop a Honeycomb plugin that translates YANG modeled data into VPP binary API invocation.
8 For this tutorial, VPP's VXLAN management API. Honeycomb already contains VXLAN management translation code inside V3PO plugin. This will be a simplified version.
10 Looking at VPP's API definition file, there are 3 calls related to VXLAN:
12 vxlan_add_del_tunnel - Creates and Deletes VXLAN tunnel (Update not supported)
13 vxlan_tunnel_dump - Reads all VXLAN tunnels
14 These are the shared-memory, binary APIs of VPP that would be difficult to use from Java. But VPP contains a jvpp component, that's completely generated from VPP's API definition file and allows Java applications to manage VPP in plain Java using JNI in the background. Honeycomb provides a component that can be included in a distribution.
16 == Updating sample-plugin to manage VPP
18 This tutorial starts where the previous one left and will continue to modify the sample plugin in order to be able to manage VPP's VXLAN tunnels.
20 === Updating YANG models
21 YANG models need to reflect the intent of managing VXLAN tunnels in VPP. As mentioned before, VPP exposes 2 calls to manage VXLAN tunnels. Each vxlan tunnel has a set of attributes, but for simplicity, only 2 of them will be exposed in YANG : source IP address and destination IP address. Rest of attributes will be set to default values in the code.
23 So let's update the sample-plugin-params grouping to:
27 grouping sample-plugin-params {
47 Since ietf-inet-types YANG model is used for the ip-address type, it needs to be imported (after the prefix statement):
51 import ietf-inet-types { prefix "inet"; }
54 NOTE: The reason this works is that there are some general YANG models such as ietf-inet-types added to *-api module in its pom.xml.
56 Now rebuild the *-api module.
59 Another important thing that the plugin needs is dependency to VPP's JVpp (Java APIs). To do so, just update *-impl's pom.xml with:
61 [source,xml,subs="+attributes"]
63 <!-- VPP's core Java APIs -->
65 <groupId>io.fd.vpp</groupId>
66 <artifactId>jvpp-core</artifactId>
67 <version>{project-vpp-snapshot-version}</version>
71 Also add vpp-translate-utils dependency so that writing translation code is easier:
73 [source,xml,subs="+attributes"]
76 <groupId>io.fd.honeycomb.vpp</groupId>
77 <artifactId>vpp-translate-utils</artifactId>
78 <version>{project-version}</version>
82 Do not rebuild yet, since the APIs for this plugin have changed and the compilation would fail. But make sure to update the project if using an IDE to pick up the Jvpp dependency.
84 === Updating the customizers
86 First of all, remove CrudService interface and ElementCrudService class. Will not be needed now.
88 ==== Changes to ElementStateCustomizer
90 Rename it to VxlanReadCustomzier. Update the code to:
94 package io.fd.honeycomb.tutorial.read;
96 import com.google.common.base.Preconditions;
97 import io.fd.honeycomb.translate.read.ReadContext;
98 import io.fd.honeycomb.translate.read.ReadFailedException;
99 import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
100 import io.fd.honeycomb.translate.v3po.util.NamingContext;
101 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
102 import java.util.Collections;
103 import java.util.List;
104 import java.util.stream.Collectors;
105 import javax.annotation.Nonnull;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.VxlansBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelBuilder;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelKey;
110 import org.opendaylight.yangtools.concepts.Builder;
111 import org.opendaylight.yangtools.yang.binding.DataObject;
112 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
113 import org.openvpp.jvpp.VppBaseCallException;
114 import org.openvpp.jvpp.core.dto.VxlanTunnelDetails;
115 import org.openvpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump;
116 import org.openvpp.jvpp.core.dto.VxlanTunnelDump;
117 import org.openvpp.jvpp.core.future.FutureJVppCore;
120 * Reader for {@link VxlanTunnel} list node from our YANG model.
122 public final class VxlanReadCustomizer implements
123 ListReaderCustomizer<VxlanTunnel, VxlanTunnelKey, VxlanTunnelBuilder> {
125 // JVpp core. This is the Java API for VPP's core API.
126 private final FutureJVppCore jVppCore;
127 // Naming context for interfaces
128 // Honeycomb provides a "context" storage for plugins. This storage is used for storing metadata required during
129 // data translation (just like in this plugin). An example of such metadata would be interface identifier. In Honeycomb
130 // we use string names for interfaces, however VPP uses only indices (that are created automatically).
131 // This means that translation layer has to store the mapping between HC interface name <-> VPP' interface index.
132 // And since vxlan tunnel is a type of interface in VPP, the same applies here
134 // Honeycomb provides a couple utilities on top of context storage such as NamingContext. It is just a map
135 // backed by context storage that makes the lookup and storing easier.
136 private final NamingContext vxlanNamingContext;
138 public VxlanReadCustomizer(final FutureJVppCore jVppCore, final NamingContext vxlanNamingContext) {
139 this.jVppCore = jVppCore;
140 this.vxlanNamingContext = vxlanNamingContext;
144 * Provide a list of IDs for all VXLANs in VPP
148 public List<VxlanTunnelKey> getAllIds(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
149 @Nonnull final ReadContext context)
150 throws ReadFailedException {
151 // Create Dump request
152 final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump();
153 // Set Dump request attributes
154 // Set interface index to 0, so all interfaces are dumped and we can get the list of all IDs
155 vxlanTunnelDump.swIfIndex = 0;
156 final VxlanTunnelDetailsReplyDump reply;
158 reply = TranslateUtils.getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), id);
159 } catch (VppBaseCallException e) {
160 throw new ReadFailedException(id, e);
163 // Check for empty response (no vxlan tunnels to read)
164 if (reply == null || reply.vxlanTunnelDetails == null) {
165 return Collections.emptyList();
168 return reply.vxlanTunnelDetails.stream()
169 // Need a name of an interface here. Use context to look it up from index
170 // In case the naming context does not contain such mapping, it creates an artificial one
171 .map(a -> new VxlanTunnelKey(vxlanNamingContext.getName(a.swIfIndex, context.getMappingContext())))
172 .collect(Collectors.toList());
176 public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<VxlanTunnel> readData) {
177 // Just set the readValue into parent builder
178 // The cast has to be performed here
179 ((VxlansBuilder) builder).setVxlanTunnel(readData);
184 public VxlanTunnelBuilder getBuilder(@Nonnull final InstanceIdentifier<VxlanTunnel> id) {
185 // Setting key from id is not necessary, builder will take care of that
186 return new VxlanTunnelBuilder();
190 * Read all the attributes of a single VXLAN tunnel
193 public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
194 @Nonnull final VxlanTunnelBuilder builder,
195 @Nonnull final ReadContext ctx) throws ReadFailedException {
196 // The ID received here contains the name of a particular interface that should be read
197 // It was either requested directly by HC users or is one of the IDs from getAllIds that could have been invoked
198 // just before this method invocation
200 // Create Dump request
201 final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump();
202 // Set Dump request attributes
203 // Set the vxlan index from naming context
204 // Naming context must contain the mapping because:
205 // 1. The vxlan tunnel was created in VPP using HC + this plugin meaning we stored the mapping in write customizer
206 // 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)
207 final String vxlanName = id.firstKeyOf(VxlanTunnel.class).getId();
208 vxlanTunnelDump.swIfIndex = vxlanNamingContext.getIndex(vxlanName, ctx.getMappingContext());
210 final VxlanTunnelDetailsReplyDump reply;
212 reply = TranslateUtils.getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), id);
213 } catch (VppBaseCallException e) {
214 throw new ReadFailedException(id, e);
217 Preconditions.checkState(reply != null && reply.vxlanTunnelDetails != null);
218 final VxlanTunnelDetails singleVxlanDetail = reply.vxlanTunnelDetails.stream().findFirst().get();
220 // Now translate all attributes into provided builder
221 final Boolean isIpv6 = TranslateUtils.byteToBoolean(singleVxlanDetail.isIpv6);
222 builder.setSrc(TranslateUtils.arrayToIpAddress(isIpv6, singleVxlanDetail.srcAddress));
223 builder.setDst(TranslateUtils.arrayToIpAddress(isIpv6, singleVxlanDetail.dstAddress));
224 // There are additional attributes of a vxlan tunnel that wont be used here
229 The '"ReaderFactory also needs to be updated:
233 package io.fd.honeycomb.tutorial.read;
235 import com.google.inject.Inject;
236 import io.fd.honeycomb.translate.impl.read.GenericListReader;
237 import io.fd.honeycomb.translate.read.ReaderFactory;
238 import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
239 import io.fd.honeycomb.translate.v3po.util.NamingContext;
240 import javax.annotation.Nonnull;
241 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginState;
242 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginStateBuilder;
243 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.Vxlans;
244 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.VxlansBuilder;
245 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel;
246 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
247 import org.openvpp.jvpp.core.future.FutureJVppCore;
250 * Factory producing readers for sample-plugin plugin's data.
252 public final class ModuleStateReaderFactory implements ReaderFactory {
254 public static final InstanceIdentifier<SamplePluginState> ROOT_STATE_CONTAINER_ID =
255 InstanceIdentifier.create(SamplePluginState.class);
258 * Injected vxlan naming context shared with writer, provided by this plugin
261 private NamingContext vxlanNamingContext;
263 * Injected jvpp core APIs, provided by Honeycomb's infrastructure
266 private FutureJVppCore jvppCore;
269 public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
270 // register reader that only delegate read's to its children
271 registry.addStructuralReader(ROOT_STATE_CONTAINER_ID, SamplePluginStateBuilder.class);
272 // register reader that only delegate read's to its children
273 registry.addStructuralReader(ROOT_STATE_CONTAINER_ID.child(Vxlans.class), VxlansBuilder.class);
275 // just adds reader to the structure
276 // use addAfter/addBefore if you want to add specific order to readers on the same level of tree
277 // use subtreeAdd if you want to handle multiple nodes in single customizer/subtreeAddAfter/subtreeAddBefore if you also want to add order
278 // be aware that instance identifier passes to subtreeAdd/subtreeAddAfter/subtreeAddBefore should define subtree,
279 // therefore it should be relative from handled node down - InstanceIdentifier.create(HandledNode), not parent.child(HandledNode.class)
280 registry.add(new GenericListReader<>(
281 // What part of subtree this reader handles is identified by an InstanceIdentifier
282 ROOT_STATE_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class),
283 // Customizer (the actual translation code to do the heavy lifting)
284 new VxlanReadCustomizer(jvppCore, vxlanNamingContext)));
289 ==== Changes to ElementCustomizer
291 Rename to VxlanWriteCustomizer. Update the code to:
295 package io.fd.honeycomb.tutorial.write;
297 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
298 import io.fd.honeycomb.translate.v3po.util.NamingContext;
299 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
300 import io.fd.honeycomb.translate.write.WriteContext;
301 import io.fd.honeycomb.translate.write.WriteFailedException;
302 import javax.annotation.Nonnull;
303 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel;
304 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnelKey;
305 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
306 import org.openvpp.jvpp.VppBaseCallException;
307 import org.openvpp.jvpp.core.dto.VxlanAddDelTunnel;
308 import org.openvpp.jvpp.core.dto.VxlanAddDelTunnelReply;
309 import org.openvpp.jvpp.core.future.FutureJVppCore;
312 * Writer for {@link VxlanTunnel} list node from our YANG model.
314 public final class VxlanWriteCustomizer implements ListWriterCustomizer<VxlanTunnel, VxlanTunnelKey> {
319 private final FutureJVppCore jvppCore;
321 * Shared vxlan tunnel naming context
323 private final NamingContext vxlanTunnelNamingContext;
325 public VxlanWriteCustomizer(final FutureJVppCore jvppCore, final NamingContext vxlanTunnelNamingContext) {
326 this.jvppCore = jvppCore;
327 this.vxlanTunnelNamingContext = vxlanTunnelNamingContext;
331 public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
332 @Nonnull final VxlanTunnel dataAfter,
333 @Nonnull final WriteContext writeContext) throws WriteFailedException {
334 // Create and set vxlan tunnel add request
335 final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
336 // 1 for add, 0 for delete
337 vxlanAddDelTunnel.isAdd = 1;
338 // dataAfter is the new vxlanTunnel configuration
339 final boolean isIpv6 = dataAfter.getSrc().getIpv6Address() != null;
340 vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6);
341 vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getSrc());
342 vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getDst());
343 // There are other input parameters that are not exposed by our YANG model, default values will be used
346 final VxlanAddDelTunnelReply replyForWrite = TranslateUtils
347 .getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id);
349 // VPP returns the index of new vxlan tunnel
350 final int newVxlanTunnelIndex = replyForWrite.swIfIndex;
351 // It's important to store it in context so that reader knows to which name a vxlan tunnel is mapped
352 vxlanTunnelNamingContext.addName(newVxlanTunnelIndex, dataAfter.getId(), writeContext.getMappingContext());
353 } catch (VppBaseCallException e) {
354 throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
359 public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
360 @Nonnull final VxlanTunnel dataBefore,
361 @Nonnull final VxlanTunnel dataAfter, @Nonnull final WriteContext writeContext)
362 throws WriteFailedException {
363 // Not supported at VPP API level, throw exception
364 throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
365 new UnsupportedOperationException("Vxlan tunnel update is not supported by VPP"));
369 public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
370 @Nonnull final VxlanTunnel dataBefore,
371 @Nonnull final WriteContext writeContext) throws WriteFailedException {
372 // Create and set vxlan tunnel add request
373 final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
374 // 1 for add, 0 for delete
375 vxlanAddDelTunnel.isAdd = 0;
376 // Vxlan tunnel is identified by its attributes when deleting, not index, so set all attributes
377 // dataBefore is the vxlan tunnel that's being deleted
378 final boolean isIpv6 = dataBefore.getSrc().getIpv6Address() != null;
379 vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6);
380 vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getSrc());
381 vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getDst());
382 // There are other input parameters that are not exposed by our YANG model, default values will be used
385 final VxlanAddDelTunnelReply replyForWrite = TranslateUtils
386 .getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id);
387 // It's important to remove the mapping from context
388 vxlanTunnelNamingContext.removeName(dataBefore.getId(), writeContext.getMappingContext());
389 } catch (VppBaseCallException e) {
390 throw new WriteFailedException.DeleteFailedException(id, e);
396 The '"WriterFactory also needs to be updated:
400 package io.fd.honeycomb.tutorial.write;
402 import com.google.inject.Inject;
403 import io.fd.honeycomb.translate.impl.write.GenericWriter;
404 import io.fd.honeycomb.translate.v3po.util.NamingContext;
405 import io.fd.honeycomb.translate.write.WriterFactory;
406 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
407 import javax.annotation.Nonnull;
408 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePlugin;
409 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.Vxlans;
410 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.vxlans.VxlanTunnel;
411 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
412 import org.openvpp.jvpp.core.future.FutureJVppCore;
415 * Factory producing writers for sample-plugin plugin's data.
417 public final class ModuleWriterFactory implements WriterFactory {
419 private static final InstanceIdentifier<SamplePlugin> ROOT_CONTAINER_ID = InstanceIdentifier.create(SamplePlugin.class);
422 * Injected vxlan naming context shared with writer, provided by this plugin
425 private NamingContext vxlanNamingContext;
427 * Injected jvpp core APIs, provided by Honeycomb's infrastructure
430 private FutureJVppCore jvppCore;
433 public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
434 // Unlike ReaderFactory, there's no need to add structural writers, just the writers that actually do something
436 // register writer for vxlan tunnel
437 registry.add(new GenericWriter<>(
438 // What part of subtree this writer handles is identified by an InstanceIdentifier
439 ROOT_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class),
440 // Customizer (the actual translation code to do the heavy lifting)
441 new VxlanWriteCustomizer(jvppCore, vxlanNamingContext)));
446 ==== Changes to Module
447 The module needs to be updated to:
449 * Include new instance of naming context
450 * Remove crud service
452 and the code needs to look like:
456 package io.fd.honeycomb.tutorial;
458 import com.google.inject.AbstractModule;
459 import com.google.inject.multibindings.Multibinder;
460 import io.fd.honeycomb.data.init.DataTreeInitializer;
461 import io.fd.honeycomb.translate.read.ReaderFactory;
462 import io.fd.honeycomb.translate.v3po.util.NamingContext;
463 import io.fd.honeycomb.translate.write.WriterFactory;
464 import io.fd.honeycomb.tutorial.init.ConfigDataInitializer;
465 import io.fd.honeycomb.tutorial.read.ModuleStateReaderFactory;
466 import io.fd.honeycomb.tutorial.write.ModuleWriterFactory;
467 import net.jmob.guice.conf.core.ConfigurationModule;
470 * Module class instantiating sample-plugin plugin components.
472 public final class Module extends AbstractModule {
475 protected void configure() {
476 // requests injection of properties
477 install(ConfigurationModule.create());
478 requestInjection(ModuleConfiguration.class);
480 // bind naming context instance for reader and writer factories
481 // the first parameter is artificial name prefix in cases a name needs to be reconstructed for a vxlan tunnel
482 // that is present in VPP but not in Honeycomb (could be extracted into configuration)
483 // the second parameter is just the naming context ID (could be extracted into configuration)
484 binder().bind(NamingContext.class).toInstance(new NamingContext("vxlan-tunnel", "vxlan-tunnel-context"));
486 // creates reader factory binding
487 // can hold multiple binding for separate yang modules
488 final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
489 readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class);
491 // create writer factory binding
492 // can hold multiple binding for separate yang modules
493 final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
494 writerFactoryBinder.addBinding().to(ModuleWriterFactory.class);
496 // create initializer binding
497 // can hold multiple binding for separate yang modules
498 final Multibinder<DataTreeInitializer> initializerBinder =
499 Multibinder.newSetBinder(binder(), DataTreeInitializer.class);
500 initializerBinder.addBinding().to(ConfigDataInitializer.class);
502 // Disable notification producer for now
503 // Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding()
504 // .to(SampleNotificationProducer.class);
508 *Now it's time to rebuild the plugin using mvn clean install to make the jars available for integrating them with vpp-integration distribution in next sections*
510 == Integrating with vpp-integration distribution
511 The vxlan tunnel management plugin can now be integrated with any honeycomb distribution. Honeycomb provides a vpp-integration distribution, where all VPP related plugins integrate to create a distribution with all available VPP related features.
513 This distribution comes with honeycomb infrastructure + common components for VPP Honeycomb plugins (e.g. Java APIs for VPP).
515 In order to add this new plugin into vpp-integration:
517 * clone honeycomb codebase (since that's the home of vpp-integration distribution)
518 * add a dependency for this sample plugin in vpp-integration distribution (honeycomb/vpp-integration/minimal-distribution/pom.xml):
520 [source,xml,subs="+attributes"]
523 <groupId>io.fd.honeycomb.tutorial</groupId>
524 <artifactId>sample-plugin-impl</artifactId>
525 <version>{project-version}</version>
529 * modify Main of vpp-integration distribution to include sample-plugin (/home/mmarsale/Projects/honeycomb/vpp-integration/minimal-distribution/src/main/java/io/fd/honeycomb/vpp/integration/distro/Main.java):
532 package io.fd.honeycomb.vpp.integration.distro;
534 import com.google.common.collect.Lists;
535 import com.google.inject.Module;
536 import io.fd.honeycomb.vpp.distro.VppCommonModule;
537 import java.util.List;
541 public static void main(String[] args) {
542 final List<Module> sampleModules = Lists.newArrayList(io.fd.honeycomb.infra.distro.Main.BASE_MODULES);
544 // All the plugins should be listed here
545 sampleModules.add(new VppCommonModule());
546 // Comment out V3po and Lisp module for the time being, since V3po and sample-plugin are in conflict over vxlan tunnel management
547 // a plugin implementing VPP's API that's not yet covered by V3po or LISP plugin would not have to do this
548 // sampleModules.add(new V3poModule());
549 // sampleModules.add(new LispModule());
550 sampleModules.add(new io.fd.honeycomb.tutorial.Module());
552 io.fd.honeycomb.infra.distro.Main.init(sampleModules);
557 Now just rebuild the honeycomb project.
559 == Verifying distribution
560 At this point, the vpp-integration distribution with sample-plugin can now be started. But first, make sure that a compatible version of VPP is installed and running. Next, start honeycomb with:
562 sudo vpp-integration/minimal-distribution/target/vpp-integration-distribution-1.16.9-hc/vpp-integration-distribution-1.16.9/honeycomb
564 === Testing over RESTCONF
565 Reading vxlans operational data (should return empty vxlans container at first):
567 curl -u admin:admin http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state
569 Adding a vxlan tunnel:
571 curl -H 'Content-Type: application/json' -H 'Accept: application/json' -u admin:admin -X PUT -d '{"vxlans":{"vxlan-tunnel": [{"id":"vxlan-test-tunnel", "src":"10.0.0.1", "dst":"10.0.0.2"}]}}' http://localhost:8181/restconf/config/sample-plugin:sample-plugin/vxlans
573 Reading vxlans config data (data that we posted to Honeycomb):
575 curl -u admin:admin http://localhost:8181/restconf/config/sample-plugin:sample-plugin
577 Reading vxlans operational data (data coming from VPP being transformed by ReaderCustomizer on the fly):
579 curl -u admin:admin http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state
581 Verifying vxlan tunnel existence in VPP:
590 Name Idx State Counter Count
595 Deleting a vxlan tunnel:
597 curl -u admin:admin -X DELETE http://localhost:8181/restconf/config/sample-plugin:sample-plugin/vxlans/vxlan-tunnel/vxlan-test-tunnel
599 Disclaimer: The vxlan tunnel will be removed from Honeycomb, and delete command will be executed on VPP, but VPP will just disable that interface and keep it as some sort of placeholder for next vxlan tunnel (that's VPPs behavior, so a vxlan tunnel cant be really deleted). So that's why you would still see the tunnel in VPP's CLI after delete.
601 ==== Testing over NETCONF
602 Netconf testing guide including Notifications, can be found in Honeycomb/Running_Honeycomb.
604 NOTE: Netconf and Restconf are equivalent interfaces to Honeycomb, being capable of providing the same APIs. The only difference is with notifications. Only NETCONF is capable of emitting the notifications.
606 == Full working sample
608 Full working sample on github: https://github.com/marosmars/honeycomb-samples/tree/vpp-plugin
612 just a note on what further work for this plugin might contain:
615 * POSTMAN REST collection with sample requests