From f1a1a73f83f0652a3038de96cb8121f7ddc80e87 Mon Sep 17 00:00:00 2001 From: Hongjun Ni Date: Fri, 2 Sep 2016 22:18:43 +0800 Subject: HONEYCOMB-46: Add NSH_SFC Feature in Honeycomb PatchSet 9: Remove unused imports PatchSet 8: Fix interface DI broken PatchSet 7: Move VppNshModule to distribution PatchSet 2: Augment with encap-if-name for nsh-map Change-Id: Ia12afb72edfe804f26b84021b997d55db3129933 Signed-off-by: Hongjun Ni --- nsh/api/pom.xml | 8 +- nsh/api/src/main/yang/vpp-nsh.yang | 48 +++-- nsh/impl/pom.xml | 117 ++++++++--- .../io/fd/honeycomb/vppnsh/impl/VppNshModule.java | 67 +++++++ .../vppnsh/impl/cfgattrs/VppNshConfiguration.java | 41 ++++ .../fd/honeycomb/vppnsh/impl/cfgattrs/vppnsh.json | 3 + .../impl/config/NshEntryWriterCustomizer.java | 168 ++++++++++++++++ .../vppnsh/impl/config/NshMapWriterCustomizer.java | 141 ++++++++++++++ .../vppnsh/impl/config/VppNshWriterFactory.java | 82 ++++++++ .../vppnsh/impl/init/VppNshInitializer.java | 87 +++++++++ .../vppnsh/impl/oper/NshEntryReaderCustomizer.java | 215 +++++++++++++++++++++ .../vppnsh/impl/oper/NshMapReaderCustomizer.java | 185 ++++++++++++++++++ .../vppnsh/impl/oper/VppNshReaderFactory.java | 85 ++++++++ .../vppnsh/impl/util/FutureJVppNshCustomizer.java | 44 +++++ .../vppnsh/impl/util/JVppNshProvider.java | 61 ++++++ nsh/pom.xml | 8 +- vpp-integration/minimal-distribution/pom.xml | 6 + .../fd/honeycomb/vpp/integration/distro/Main.java | 2 + 18 files changed, 1308 insertions(+), 60 deletions(-) create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/VppNshConfiguration.java create mode 100644 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/vppnsh.json create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshEntryWriterCustomizer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshMapWriterCustomizer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/VppNshWriterFactory.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/init/VppNshInitializer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshEntryReaderCustomizer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshMapReaderCustomizer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/VppNshReaderFactory.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/FutureJVppNshCustomizer.java create mode 100755 nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/JVppNshProvider.java diff --git a/nsh/api/pom.xml b/nsh/api/pom.xml index 86e76669f..abab758f1 100644 --- a/nsh/api/pom.xml +++ b/nsh/api/pom.xml @@ -1,6 +1,6 @@ - - - io.fd.honeycomb.common - impl-parent - 1.16.9-SNAPSHOT - ../../common/impl-parent - - - 4.0.0 - io.fd.honeycomb.v3po - nsh-impl + + + io.fd.honeycomb.common + impl-parent 1.16.9-SNAPSHOT - bundle + ../../common/impl-parent + + + 4.0.0 + io.fd.honeycomb.vppnsh + vppnsh-impl + 1.16.9-SNAPSHOT + bundle + + + 4.1.0 + 1.2.0 + + + + + ${project.groupId} + vppnsh-api + ${project.version} + - - - ${project.groupId} - nsh-api - ${project.version} - - - junit - junit - test - - - org.mockito - mockito-all - test - - + + com.google.inject + guice + ${guice.version} + + + net.jmob + guice.conf + ${guice.config.version} + + + com.google.inject.extensions + guice-multibindings + ${guice.version} + + + io.fd.honeycomb + translate-impl + ${project.version} + + + io.fd.honeycomb + translate-api + ${project.version} + + + io.fd.honeycomb + notification-api + ${project.version} + + + io.fd.honeycomb + cfg-init + ${project.version} + + + io.fd.vpp + jvpp-registry + 16.09-SNAPSHOT + + + io.fd.nsh_sfc + nsh-sfc + 16.09-SNAPSHOT + + + io.fd.honeycomb.vpp + vpp-translate-utils + ${project.version} + + + io.fd.honeycomb + minimal-distribution + ${project.version} + + + io.fd.honeycomb.v3po + v3po2vpp + ${project.version} + + diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java new file mode 100755 index 000000000..48f323394 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.vppnsh.impl.cfgattrs.VppNshConfiguration; +import io.fd.honeycomb.vppnsh.impl.config.VppNshWriterFactory; +import io.fd.honeycomb.vppnsh.impl.oper.VppNshReaderFactory; +import io.fd.honeycomb.vppnsh.impl.init.VppNshInitializer; +import io.fd.honeycomb.vppnsh.impl.util.JVppNshProvider; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; + +/** + * This is some glue code necessary for Honeycomb distribution to pick up the plugin classes + */ +public final class VppNshModule extends AbstractModule { + + @Override + protected void configure() { + // These are plugin specific config attributes + install(ConfigurationModule.create()); + requestInjection(VppNshConfiguration.class); + + // Naming contexts + bind(NamingContext.class) + .annotatedWith(Names.named("nsh-entry-context")) + .toInstance(new NamingContext("nsh-entry-", "nsh-entry-context")); + + bind(NamingContext.class) + .annotatedWith(Names.named("nsh-map-context")) + .toInstance(new NamingContext("nsh-map-", "nsh-map-context")); + + // Bind to Plugin's JVPP. + bind(FutureJVppNsh.class).toProvider(JVppNshProvider.class).in(Singleton.class); + + // Below are classes picked up by HC framework + Multibinder.newSetBinder(binder(), WriterFactory.class).addBinding().to(VppNshWriterFactory.class); + Multibinder.newSetBinder(binder(), ReaderFactory.class).addBinding().to(VppNshReaderFactory.class); + Multibinder.newSetBinder(binder(), DataTreeInitializer.class).addBinding().to(VppNshInitializer.class); + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/VppNshConfiguration.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/VppNshConfiguration.java new file mode 100755 index 000000000..e6491509d --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/VppNshConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.cfgattrs; + +import com.google.common.base.MoreObjects; + +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +@BindConfig(value = "vppnsh", syntax = Syntax.JSON) +public class VppNshConfiguration { + + public boolean isNshEnabled() { + return Boolean.valueOf(nshEnable); + } + + @InjectConfig("nsh-enabled") + public String nshEnable; + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("nshEnable", nshEnable) + .toString(); + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/vppnsh.json b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/vppnsh.json new file mode 100644 index 000000000..f2fe985b9 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/cfgattrs/vppnsh.json @@ -0,0 +1,3 @@ +{ + "nsh-enabled" : "false" +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshEntryWriterCustomizer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshEntryWriterCustomizer.java new file mode 100755 index 000000000..d3c15ae88 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshEntryWriterCustomizer.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.config; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NextProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType1Augment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType1AugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.entries.NshEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.entries.NshEntryKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.nsh.dto.*; +import org.openvpp.jvpp.nsh.callback.*; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import io.fd.honeycomb.vppnsh.impl.util.FutureJVppNshCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer customizer responsible for NshEntry create/delete. + */ +public class NshEntryWriterCustomizer extends FutureJVppNshCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(NshEntryWriterCustomizer.class); + private final NamingContext nshEntryContext; + + public NshEntryWriterCustomizer(@Nonnull final FutureJVppNsh futureJVppNsh, + @Nonnull final NamingContext nshEntryContext) { + super(futureJVppNsh); + this.nshEntryContext = checkNotNull(nshEntryContext, "nshEntryContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshEntry dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Creating nsh entry: iid={} dataAfter={}", id, dataAfter); + try { + final int newEntryIndex = + nshAddDelEntry(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext()); + + // Add nsh entry name <-> vpp index mapping to the naming context: + nshEntryContext.addName(newEntryIndex, dataAfter.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully created nsh entry(id={]): iid={} dataAfter={}", newEntryIndex, id, dataAfter); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshEntry dataBefore, @Nonnull final NshEntry dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException("Nsh entry update is not supported"); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshEntry dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Removing nsh entry: iid={} dataBefore={}", id, dataBefore); + final String entryName = dataBefore.getName(); + checkState(nshEntryContext.containsIndex(entryName, writeContext.getMappingContext()), + "Removing nsh entry {}, but index could not be found in the nsh entry context", entryName); + + final int entryIndex = nshEntryContext.getIndex(entryName, writeContext.getMappingContext()); + try { + nshAddDelEntry(false, id, dataBefore, entryIndex, writeContext.getMappingContext()); + + // Remove deleted interface from interface context: + nshEntryContext.removeName(dataBefore.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully removed nsh entry(id={]): iid={} dataAfter={}", entryIndex, id, dataBefore); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private int nshAddDelEntry(final boolean isAdd, @Nonnull final InstanceIdentifier id, + @Nonnull final NshEntry entry, final int entryId, final MappingContext ctx) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage createNshEntryReplyCompletionStage = + getFutureJVppNsh().nshAddDelEntry(getNshAddDelEntryRequest(isAdd, entryId, entry, ctx)); + + final NshAddDelEntryReply reply = + TranslateUtils.getReplyForWrite(createNshEntryReplyCompletionStage.toCompletableFuture(), id); + return reply.entryIndex; + + } + + private void getNshEntryMdType1Request(@Nonnull final NshEntry entry, + @Nonnull NshAddDelEntry request) { + final NshMdType1Augment nshMdType1Augment = entry.getAugmentation(NshMdType1Augment.class); + if (nshMdType1Augment != null) { + request.c1 = (int) nshMdType1Augment.getC1().longValue(); + request.c2 = (int) nshMdType1Augment.getC2().longValue(); + request.c3 = (int) nshMdType1Augment.getC3().longValue(); + request.c4 = (int) nshMdType1Augment.getC4().longValue(); + } + } + + private NshAddDelEntry getNshAddDelEntryRequest(final boolean isAdd, final int entryIndex, + @Nonnull final NshEntry entry, + @Nonnull final MappingContext ctx) { + final NshAddDelEntry request = new NshAddDelEntry(); + request.isAdd = booleanToByte(isAdd); + + request.verOC = (byte) entry.getVersion().shortValue(); + request.length = (byte) entry.getLength().intValue(); + if (entry.getNextProtocol() == Ipv4.class) + request.nextProtocol = 1; + else if (entry.getNextProtocol() == Ipv6.class) + request.nextProtocol = 2; + else if (entry.getNextProtocol() == Ethernet.class) + request.nextProtocol = 3; + else + request.nextProtocol = 0; + + if (entry.getMdType() == MdType1.class) + { + request.mdType = 1; + getNshEntryMdType1Request(entry, request); + } + else if (entry.getMdType() == MdType1.class) + request.mdType = 2; + else + request.mdType = 0; + + request.nspNsi = (entry.getNsp().intValue()<<8) | entry.getNsi(); + + return request; + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshMapWriterCustomizer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshMapWriterCustomizer.java new file mode 100755 index 000000000..f2757bd64 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/NshMapWriterCustomizer.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.config; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.EncapType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.maps.NshMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.maps.NshMapKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.nsh.dto.*; +import org.openvpp.jvpp.nsh.callback.*; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import io.fd.honeycomb.vppnsh.impl.util.FutureJVppNshCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer customizer responsible for NshMap create/delete. + */ +public class NshMapWriterCustomizer extends FutureJVppNshCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(NshMapWriterCustomizer.class); + private final NamingContext nshMapContext; + private final NamingContext interfaceContext; + + public NshMapWriterCustomizer(@Nonnull final FutureJVppNsh futureJVppNsh, + @Nonnull final NamingContext nshMapContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppNsh); + this.nshMapContext = checkNotNull(nshMapContext, "nshMapContext should not be null"); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshMap dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Creating nsh map: iid={} dataAfter={}", id, dataAfter); + try { + final int newMapIndex = + nshAddDelMap(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext()); + + // Add nsh map name <-> vpp index mapping to the naming context: + nshMapContext.addName(newMapIndex, dataAfter.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully created nsh map(id={]): iid={} dataAfter={}", newMapIndex, id, dataAfter); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshMap dataBefore, @Nonnull final NshMap dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException("Nsh map update is not supported"); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshMap dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Removing nsh map: iid={} dataBefore={}", id, dataBefore); + final String mapName = dataBefore.getName(); + checkState(nshMapContext.containsIndex(mapName, writeContext.getMappingContext()), + "Removing nsh map {}, but index could not be found in the nsh map context", mapName); + + final int mapIndex = nshMapContext.getIndex(mapName, writeContext.getMappingContext()); + try { + nshAddDelMap(false, id, dataBefore, mapIndex, writeContext.getMappingContext()); + + // Remove deleted interface from interface context: + nshMapContext.removeName(dataBefore.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully removed nsh map(id={]): iid={} dataAfter={}", mapIndex, id, dataBefore); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private int nshAddDelMap(final boolean isAdd, @Nonnull final InstanceIdentifier id, + @Nonnull final NshMap map, final int mapId, final MappingContext ctx) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage createNshMapReplyCompletionStage = + getFutureJVppNsh().nshAddDelMap(getNshAddDelMapRequest(isAdd, mapId, map, ctx)); + + final NshAddDelMapReply reply = + TranslateUtils.getReplyForWrite(createNshMapReplyCompletionStage.toCompletableFuture(), id); + return reply.mapIndex; + + } + + private NshAddDelMap getNshAddDelMapRequest(final boolean isAdd, final int mapIndex, + @Nonnull final NshMap map, + @Nonnull final MappingContext ctx) { + final NshAddDelMap request = new NshAddDelMap(); + request.isAdd = booleanToByte(isAdd); + + request.nspNsi = (map.getNsp().intValue()<<8) | map.getNsi(); + request.mappedNspNsi = (map.getMappedNsp().intValue()<<8) | map.getMappedNsi(); + + if (map.getEncapType() == VxlanGpe.class) { + request.nextNode = 2; + } + + checkState(interfaceContext.containsIndex(map.getEncapIfName(), ctx), + "Mapping does not contains mapping for provider interface Name ".concat(map.getEncapIfName())); + request.swIfIndex = interfaceContext.getIndex(map.getEncapIfName(), ctx); + + return request; + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/VppNshWriterFactory.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/VppNshWriterFactory.java new file mode 100755 index 000000000..fbf37c368 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/config/VppNshWriterFactory.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.config; + +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNsh; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType1Augment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType2Augment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.entries.NshEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshMaps; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.maps.NshMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; + +public class VppNshWriterFactory implements WriterFactory { + + @Nonnull + private final FutureJVppNsh jvppNsh; + private final NamingContext nshEntryContext; + private final NamingContext nshMapContext; + private final NamingContext interfaceContext; + + @Inject + public VppNshWriterFactory(@Nonnull final FutureJVppNsh jvppNsh, + @Named("nsh-entry-context") @Nonnull final NamingContext nshEntryContext, + @Named("nsh-map-context") @Nonnull final NamingContext nshMapContext, + @Named("interface-context") @Nonnull final NamingContext interfaceContext) { + this.jvppNsh = jvppNsh; + this.nshEntryContext = nshEntryContext; + this.nshMapContext = nshMapContext; + this.interfaceContext = interfaceContext; + } + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + // WriterFactory is intended for registering Writers into HC framework + // Writers handle ONLY config (config "true") data coming from upper layers and propagate them into lower layer/device + // they are triggered when RESTCONF PUT/POST on config is invoked or when NETCONF edit-config + commit operation is executed + + // VppNsh has no handlers + // NshEntries has no handlers + // NshEntry = + final InstanceIdentifier nshEntriesId = InstanceIdentifier.create(VppNsh.class).child(NshEntries.class); + final InstanceIdentifier nshEntryId = nshEntriesId.child(NshEntry.class); + registry.subtreeAdd( + Sets.newHashSet( + InstanceIdentifier.create(NshEntry.class).augmentation(NshMdType1Augment.class), + InstanceIdentifier.create(NshEntry.class).augmentation(NshMdType2Augment.class)), + new GenericListWriter<>(nshEntryId, new NshEntryWriterCustomizer(jvppNsh, nshEntryContext))); + + // VppNsh has no handlers + // NshMaps has no handlers + // NshMap = + final InstanceIdentifier nshMapId = + InstanceIdentifier.create(VppNsh.class).child(NshMaps.class).child(NshMap.class); + registry.add(new GenericListWriter<>(nshMapId, new NshMapWriterCustomizer(jvppNsh, nshMapContext, interfaceContext))); + + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/init/VppNshInitializer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/init/VppNshInitializer.java new file mode 100755 index 000000000..ca13d8a19 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/init/VppNshInitializer.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.init; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNsh; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshMaps; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.NshMapsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.entries.NshEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.entries.NshEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.maps.NshMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.nsh.maps.NshMapBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is an initializer for VppNsh plugin. Its main goal is to revers-engineer configuration data (config "true") + * for Nsh model from operational data. In this case, we are trying to recreate Nsh container from NshsState + * container. Thanks to symmetrical nature of the model, it's pretty straightforward. + * + * This is very useful when the lower layer already contains some data that should be revers-engineer to config data + * in honeycomb in order to get HC and lower layer to sync... It makes life of upper layers much easier + * + * However it's not always possible to perform this task so the initializers are optional for plugins + */ +public class VppNshInitializer extends AbstractDataTreeConverter { + + private static final Logger LOG = LoggerFactory.getLogger(VppNshInitializer.class); + private static final InstanceIdentifier OPER_ID = InstanceIdentifier.create(VppNshState.class); + private static final InstanceIdentifier CFG_ID = InstanceIdentifier.create(VppNsh.class); + + @Inject + public VppNshInitializer(@Named("honeycomb-initializer") final DataBroker bindingDataBroker) { + super(bindingDataBroker, OPER_ID, CFG_ID); + } + + @Override + protected VppNsh convert(final VppNshState operationalData) { + // Just convert operational data into config data + // The operational data are queried from lower layer using readerCustomizers from this plugin + + LOG.info("Initializing VppNsh config data from: {}", operationalData); + + VppNshBuilder vppNshBuilder = new VppNshBuilder(); + + NshEntriesBuilder nshEntriesBuilder = new NshEntriesBuilder() + .setNshEntry(operationalData.getNshEntries().getNshEntry().stream() + .map(oper -> new NshEntryBuilder(oper).setName(oper.getName()).build()) + .collect(Collectors.toList())); + vppNshBuilder.setNshEntries(nshEntriesBuilder.build()); + + NshMapsBuilder nshMapsBuilder = new NshMapsBuilder() + .setNshMap(operationalData.getNshMaps().getNshMap().stream() + .map(oper -> new NshMapBuilder(oper).setName(oper.getName()).build()) + .collect(Collectors.toList())); + vppNshBuilder.setNshMaps(nshMapsBuilder.build()); + + return vppNshBuilder.build(); + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshEntryReaderCustomizer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshEntryReaderCustomizer.java new file mode 100755 index 000000000..53dff0b64 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshEntryReaderCustomizer.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.oper; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NextProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType1StateAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.NshMdType1StateAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.MdType2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.entries.NshEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.entries.NshEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.entries.NshEntryKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.nsh.dto.NshEntryDump; +import org.openvpp.jvpp.nsh.dto.NshAddDelEntry; +import org.openvpp.jvpp.nsh.dto.NshEntryDetails; +import org.openvpp.jvpp.nsh.dto.NshEntryDetailsReplyDump; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import io.fd.honeycomb.vppnsh.impl.util.FutureJVppNshCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Reader customizer responsible for nsh entry read.
to VPP. + */ +public class NshEntryReaderCustomizer extends FutureJVppNshCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(NshEntryReaderCustomizer.class); + private final NamingContext nshEntryContext; + + public NshEntryReaderCustomizer(@Nonnull final FutureJVppNsh futureJVppNsh, + @Nonnull final NamingContext nshEntryContext) { + super(futureJVppNsh); + this.nshEntryContext = checkNotNull(nshEntryContext, "nshEntryContext should not be null"); + } + + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((NshEntriesBuilder) builder).setNshEntry(readData); + } + + @Nonnull + @Override + public NshEntryBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new NshEntryBuilder(); + } + + private void setNshEntryMdType1Augment(@Nonnull final NshEntryBuilder builder, + @Nonnull NshEntryDetails nshEntryDetails) { + final NshMdType1StateAugmentBuilder augmentBuilder = new NshMdType1StateAugmentBuilder(); + augmentBuilder.setC1((long)nshEntryDetails.c1); + augmentBuilder.setC2((long)nshEntryDetails.c2); + augmentBuilder.setC3((long)nshEntryDetails.c3); + augmentBuilder.setC4((long)nshEntryDetails.c4); + + builder.addAugmentation(NshMdType1StateAugment.class, augmentBuilder.build()); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshEntryBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for nsh entry: {}", id); + try { + final NshEntryKey key = id.firstKeyOf(NshEntry.class); + checkArgument(key != null, "could not find NshEntry key in {}", id); + final NshEntryDump request = new NshEntryDump(); + + final String entryName = key.getName(); + if (!nshEntryContext.containsIndex(entryName, ctx.getMappingContext())) { + LOG.debug("Could not find nsh entry {} in the naming context", entryName); + return; + } + request.entryIndex = nshEntryContext.getIndex(entryName, ctx.getMappingContext()); + + final CompletionStage nshEntryDetailsReplyDumpCompletionStage = + getFutureJVppNsh().nshEntryDump(request); + final NshEntryDetailsReplyDump reply = + TranslateUtils.getReplyForRead(nshEntryDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + if (reply == null || reply.nshEntryDetails == null || reply.nshEntryDetails.isEmpty()) { + LOG.debug("Has no Nsh Entry {} in VPP. ", key.getName()); + return; + } + + LOG.trace("Nsh Entry : {} attributes returned from VPP: {}", key.getName(), reply); + + final NshEntryDetails nshEntryDetails = reply.nshEntryDetails.get(0); + builder.setName(entryName); + builder.setKey(key); + builder.setVersion( (short) nshEntryDetails.verOC ); + builder.setLength( (short) nshEntryDetails.length ); + + switch(nshEntryDetails.nextProtocol) { + case 1: + builder.setNextProtocol(Ipv4.class); + break; + case 2: + builder.setNextProtocol(Ipv6.class); + break; + case 3: + builder.setNextProtocol(Ethernet.class); + break; + default: + LOG.trace("Unsupported next protocol for nsh entry: {}", nshEntryDetails.nextProtocol); + return; + } + + switch(nshEntryDetails.mdType) { + case 1: + { + builder.setMdType(MdType1.class); + setNshEntryMdType1Augment(builder, nshEntryDetails); + break; + } + case 2: + { + builder.setMdType(MdType1.class); + break; + } + default: + LOG.trace("Unsupported Mdtype for nsh entry: {}", nshEntryDetails.mdType); + return; + } + + builder.setNsp( (long)((nshEntryDetails.nspNsi>>8) & 0xFFFFFF)); + builder.setNsi( (short)(nshEntryDetails.nspNsi & 0xFF )); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for nsh entry {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + LOG.debug("Reading list of keys for nsh entry: {}", id); + + final NshEntryDump request = new NshEntryDump(); + request.entryIndex = -1; // dump call + + NshEntryDetailsReplyDump reply; + try { + reply = getFutureJVppNsh().nshEntryDump(request).toCompletableFuture().get(); + } catch (Exception e) { + throw new IllegalStateException("Nsh Entry dump failed", e); + } + + if (reply == null || reply.nshEntryDetails == null) { + return Collections.emptyList(); + } + + final int nIdsLength = reply.nshEntryDetails.size(); + LOG.debug("vppstate.NshEntryCustomizer.getAllIds: nIds.length={}", nIdsLength); + if (nIdsLength == 0) { + return Collections.emptyList(); + } + + final List allIds = new ArrayList<>(nIdsLength); + for (NshEntryDetails detail : reply.nshEntryDetails) { + final String nshName = nshEntryContext.getName(detail.entryIndex, context.getMappingContext()); + LOG.debug("vppstate.NshEntryCustomizer.getAllIds: nName={}", nshName); + allIds.add(new NshEntryKey(nshName)); + } + + return allIds; + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshMapReaderCustomizer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshMapReaderCustomizer.java new file mode 100755 index 000000000..7d6c64baf --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/NshMapReaderCustomizer.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.oper; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.Ipv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.EncapType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshMapsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.maps.NshMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.maps.NshMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.maps.NshMapKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.nsh.dto.NshMapDump; +import org.openvpp.jvpp.nsh.dto.NshMapDetails; +import org.openvpp.jvpp.nsh.dto.NshMapDetailsReplyDump; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import io.fd.honeycomb.vppnsh.impl.util.FutureJVppNshCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Reader customizer responsible for nsh map read.
to VPP. + */ +public class NshMapReaderCustomizer extends FutureJVppNshCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(NshMapReaderCustomizer.class); + private final NamingContext nshMapContext; + private final NamingContext interfaceContext; + + public NshMapReaderCustomizer(@Nonnull final FutureJVppNsh futureJVppNsh, + @Nonnull final NamingContext nshMapContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppNsh); + this.nshMapContext = checkNotNull(nshMapContext, "nshMapContext should not be null"); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((NshMapsBuilder) builder).setNshMap(readData); + } + + @Nonnull + @Override + public NshMapBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new NshMapBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final NshMapBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for nsh map: {}", id); + try { + final NshMapKey key = id.firstKeyOf(NshMap.class); + checkArgument(key != null, "could not find NshMap key in {}", id); + final NshMapDump request = new NshMapDump(); + + final String mapName = key.getName(); + if (!nshMapContext.containsIndex(mapName, ctx.getMappingContext())) { + LOG.debug("Could not find nsh map {} in the naming context", mapName); + return; + } + request.mapIndex = nshMapContext.getIndex(mapName, ctx.getMappingContext()); + + final CompletionStage nshMapDetailsReplyDumpCompletionStage = + getFutureJVppNsh().nshMapDump(request); + final NshMapDetailsReplyDump reply = + TranslateUtils.getReplyForRead(nshMapDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + if (reply == null || reply.nshMapDetails == null || reply.nshMapDetails.isEmpty()) { + LOG.debug("Has no Nsh Map {} in VPP. ", key.getName()); + return; + } + + LOG.trace("Nsh Map : {} attributes returned from VPP: {}", key.getName(), reply); + + final NshMapDetails nshMapDetails = reply.nshMapDetails.get(0); + builder.setName(mapName); + builder.setKey(key); + + builder.setNsp( (long)((nshMapDetails.nspNsi>>8) & 0xFFFFFF)); + builder.setNsi( (short)(nshMapDetails.nspNsi & 0xFF )); + + builder.setMappedNsp( (long)((nshMapDetails.mappedNspNsi>>8) & 0xFFFFFF)); + builder.setMappedNsi( (short)(nshMapDetails.mappedNspNsi & 0xFF )); + + switch(nshMapDetails.nextNode) { + case 2: + builder.setEncapType(VxlanGpe.class); + break; + default: + LOG.trace("Unsupported encap type for nsh map: {}", nshMapDetails.nextNode); + return; + } + + checkState(interfaceContext.containsName(nshMapDetails.swIfIndex, ctx.getMappingContext()), + "Mapping does not contains mapping for provider interface Index "); + final String interfaceName = interfaceContext.getName(nshMapDetails.swIfIndex, ctx.getMappingContext()); + builder.setEncapIfName(interfaceName); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for nsh map {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + LOG.debug("Reading list of keys for nsh map: {}", id); + + final NshMapDump request = new NshMapDump(); + request.mapIndex = -1; // dump call + + NshMapDetailsReplyDump reply; + try { + reply = getFutureJVppNsh().nshMapDump(request).toCompletableFuture().get(); + } catch (Exception e) { + throw new IllegalStateException("Nsh Map dump failed", e); + } + + if (reply == null || reply.nshMapDetails == null) { + return Collections.emptyList(); + } + + final int nIdsLength = reply.nshMapDetails.size(); + LOG.debug("vppstate.NshMapCustomizer.getAllIds: nIds.length={}", nIdsLength); + if (nIdsLength == 0) { + return Collections.emptyList(); + } + + final List allIds = new ArrayList<>(nIdsLength); + for (NshMapDetails detail : reply.nshMapDetails) { + final String nshName = nshMapContext.getName(detail.mapIndex, context.getMappingContext()); + LOG.debug("vppstate.NshMapCustomizer.getAllIds: nName={}", nshName); + allIds.add(new NshMapKey(nshName)); + } + + return allIds; + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/VppNshReaderFactory.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/VppNshReaderFactory.java new file mode 100755 index 000000000..a7467c800 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/oper/VppNshReaderFactory.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.oper; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNsh; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.VppNshStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.entries.NshEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.entries.NshEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshMaps; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.NshMapsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.maps.NshMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nsh.rev160624.vpp.nsh.state.nsh.maps.NshMapBuilder; + +import io.fd.honeycomb.vppnsh.impl.oper.NshEntryReaderCustomizer; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppNshReaderFactory implements ReaderFactory { + + private final FutureJVppNsh jvppNsh; + private final NamingContext nshEntryContext; + private final NamingContext nshMapContext; + private final NamingContext interfaceContext; + + @Inject + public VppNshReaderFactory(final FutureJVppNsh jvppNsh, + @Named("nsh-entry-context") final NamingContext nshEntryContext, + @Named("nsh-map-context") final NamingContext nshMapContext, + @Named("interface-context") @Nonnull final NamingContext interfaceContext) { + this.jvppNsh = jvppNsh; + this.nshEntryContext = nshEntryContext; + this.nshMapContext = nshMapContext; + this.interfaceContext = interfaceContext; + } + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + // ReaderFactory is intended for registering Readers into HC framework + // Readers provide ONLY operational (config "false") data straight from underlying device/layer + // they are triggered when RESTCONF GET on operational is invoked or when NETCONF get operation is executed + + // VppNshState(Structural) + final InstanceIdentifier vppNshStateId = InstanceIdentifier.create(VppNshState.class); + registry.addStructuralReader(vppNshStateId, VppNshStateBuilder.class); + + // NshENtries(Structural) + final InstanceIdentifier nshEntriesId = vppNshStateId.child(NshEntries.class); + registry.addStructuralReader(nshEntriesId, NshEntriesBuilder.class); + // NshENtry + final InstanceIdentifier nshEntryId = nshEntriesId.child(NshEntry.class); + registry.add(new GenericListReader<>(nshEntryId, new NshEntryReaderCustomizer(jvppNsh, nshEntryContext))); + + // NshMaps(Structural) + final InstanceIdentifier nshMapsId = vppNshStateId.child(NshMaps.class); + registry.addStructuralReader(nshMapsId, NshMapsBuilder.class); + // NshMap + final InstanceIdentifier nshMapId = nshMapsId.child(NshMap.class); + registry.add(new GenericListReader<>(nshMapId, new NshMapReaderCustomizer(jvppNsh, nshMapContext, interfaceContext))); + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/FutureJVppNshCustomizer.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/FutureJVppNshCustomizer.java new file mode 100755 index 000000000..f25e33cc5 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/FutureJVppNshCustomizer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Intel 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.honeycomb.vppnsh.impl.util; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import javax.annotation.Nonnull; + +/** + * Abstract utility to hold the NshApi reference. + */ +@Beta +public abstract class FutureJVppNshCustomizer { + + private final FutureJVppNsh futureJVppNsh; + + public FutureJVppNshCustomizer(@Nonnull final FutureJVppNsh futureJVppNsh) { + this.futureJVppNsh = Preconditions.checkNotNull(futureJVppNsh, "futureJVppNsh should not be null"); + } + + /** + * Get NshApi reference + * + * @return NshApi reference + */ + public FutureJVppNsh getFutureJVppNsh() { + return futureJVppNsh; + } +} diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/JVppNshProvider.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/JVppNshProvider.java new file mode 100755 index 000000000..130b499a6 --- /dev/null +++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/util/JVppNshProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Intel and 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.honeycomb.vppnsh.impl.util; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import java.io.IOException; +import org.openvpp.jvpp.JVppRegistry; +import org.openvpp.jvpp.nsh.future.FutureJVppNsh; +import org.openvpp.jvpp.nsh.future.FutureJVppNshFacade; +import org.openvpp.jvpp.nsh.JVppNshImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides future API for jvpp-nsh plugin. Must be a singleton due to shutdown hook usage. + * Registers shutdown hook to free plugin's resources on shutdown. + */ +public final class JVppNshProvider extends ProviderTrait { + + private static final Logger LOG = LoggerFactory.getLogger(JVppNshProvider.class); + + @Inject + private JVppRegistry registry; + + @Override + protected FutureJVppNshFacade create() { + try { + final JVppNshImpl jVppNsh = new JVppNshImpl(); + // Free jvpp-nsh plugin's resources on shutdown + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + LOG.info("Unloading jvpp-nsh plugin"); + jVppNsh.close(); + LOG.info("Successfully unloaded jvpp-nsh plugin"); + } + }); + + LOG.info("Successfully loaded jvpp-nsh plugin"); + return new FutureJVppNshFacade(registry, jVppNsh); + } catch (IOException e) { + throw new IllegalStateException("Unable to open VPP management connection", e); + } + } +} + diff --git a/nsh/pom.xml b/nsh/pom.xml index 11a00b910..2c51641d2 100644 --- a/nsh/pom.xml +++ b/nsh/pom.xml @@ -1,6 +1,6 @@