diff options
author | Hongjun Ni <hongjun.ni@intel.com> | 2016-09-02 22:18:43 +0800 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-09-12 07:39:41 +0000 |
commit | f1a1a73f83f0652a3038de96cb8121f7ddc80e87 (patch) | |
tree | f5891e616d6518f9ffbfb5d46fdea0ebacb1e0bc /nsh/impl | |
parent | 4c80caaa0a39b52b693fda5165ca4ac3d96e2b2a (diff) |
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 <hongjun.ni@intel.com>
Diffstat (limited to 'nsh/impl')
13 files changed, 1265 insertions, 31 deletions
diff --git a/nsh/impl/pom.xml b/nsh/impl/pom.xml index 4fa591f1d..58730cf90 100644 --- a/nsh/impl/pom.xml +++ b/nsh/impl/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2015 Cisco and/or its affiliates. + Copyright (c) 2015 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: @@ -13,37 +13,92 @@ See the License for the specific language governing permissions and limitations under the License. --> -<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>impl-parent</artifactId> - <version>1.16.9-SNAPSHOT</version> - <relativePath>../../common/impl-parent</relativePath> - </parent> - - <modelVersion>4.0.0</modelVersion> - <groupId>io.fd.honeycomb.v3po</groupId> - <artifactId>nsh-impl</artifactId> +<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>impl-parent</artifactId> <version>1.16.9-SNAPSHOT</version> - <packaging>bundle</packaging> + <relativePath>../../common/impl-parent</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>io.fd.honeycomb.vppnsh</groupId> + <artifactId>vppnsh-impl</artifactId> + <version>1.16.9-SNAPSHOT</version> + <packaging>bundle</packaging> + + <properties> + <guice.version>4.1.0</guice.version> + <guice.config.version>1.2.0</guice.config.version> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>vppnsh-api</artifactId> + <version>${project.version}</version> + </dependency> - <dependencies> - <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>nsh-api</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-all</artifactId> - <scope>test</scope> - </dependency> - </dependencies> + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + <version>${guice.version}</version> + </dependency> + <dependency> + <groupId>net.jmob</groupId> + <artifactId>guice.conf</artifactId> + <version>${guice.config.version}</version> + </dependency> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + <version>${guice.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-impl</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>notification-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>cfg-init</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.vpp</groupId> + <artifactId>jvpp-registry</artifactId> + <version>16.09-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>io.fd.nsh_sfc</groupId> + <artifactId>nsh-sfc</artifactId> + <version>16.09-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb.vpp</groupId> + <artifactId>vpp-translate-utils</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>minimal-distribution</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb.v3po</groupId> + <artifactId>v3po2vpp</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> </project> 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<NshEntry, NshEntryKey> { + + 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<NshEntry> 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<NshEntry> 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<NshEntry> 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<NshEntry> id, + @Nonnull final NshEntry entry, final int entryId, final MappingContext ctx) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage<NshAddDelEntryReply> 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<NshMap, NshMapKey> { + + 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<NshMap> 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<NshMap> 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<NshMap> 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<NshMap> id, + @Nonnull final NshMap map, final int mapId, final MappingContext ctx) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage<NshAddDelMapReply> 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<NshEntries> nshEntriesId = InstanceIdentifier.create(VppNsh.class).child(NshEntries.class); + final InstanceIdentifier<NshEntry> 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<NshMap> 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<VppNshState, VppNsh> { + + private static final Logger LOG = LoggerFactory.getLogger(VppNshInitializer.class); + private static final InstanceIdentifier<VppNshState> OPER_ID = InstanceIdentifier.create(VppNshState.class); + private static final InstanceIdentifier<VppNsh> 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.<br> to VPP. + */ +public class NshEntryReaderCustomizer extends FutureJVppNshCustomizer + implements ListReaderCustomizer<NshEntry, NshEntryKey, NshEntryBuilder> { + + 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<? extends DataObject> builder, + @Nonnull final List<NshEntry> readData) { + ((NshEntriesBuilder) builder).setNshEntry(readData); + } + + @Nonnull + @Override + public NshEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<NshEntry> 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<NshEntry> 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<NshEntryDetailsReplyDump> 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<NshEntryKey> getAllIds(@Nonnull final InstanceIdentifier<NshEntry> 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<NshEntryKey> 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.<br> to VPP. + */ +public class NshMapReaderCustomizer extends FutureJVppNshCustomizer + implements ListReaderCustomizer<NshMap, NshMapKey, NshMapBuilder> { + + 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<? extends DataObject> builder, + @Nonnull final List<NshMap> readData) { + ((NshMapsBuilder) builder).setNshMap(readData); + } + + @Nonnull + @Override + public NshMapBuilder getBuilder(@Nonnull final InstanceIdentifier<NshMap> id) { + return new NshMapBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<NshMap> 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<NshMapDetailsReplyDump> 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<NshMapKey> getAllIds(@Nonnull final InstanceIdentifier<NshMap> 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<NshMapKey> 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<VppNshState> vppNshStateId = InstanceIdentifier.create(VppNshState.class); + registry.addStructuralReader(vppNshStateId, VppNshStateBuilder.class); + + // NshENtries(Structural) + final InstanceIdentifier<NshEntries> nshEntriesId = vppNshStateId.child(NshEntries.class); + registry.addStructuralReader(nshEntriesId, NshEntriesBuilder.class); + // NshENtry + final InstanceIdentifier<NshEntry> nshEntryId = nshEntriesId.child(NshEntry.class); + registry.add(new GenericListReader<>(nshEntryId, new NshEntryReaderCustomizer(jvppNsh, nshEntryContext))); + + // NshMaps(Structural) + final InstanceIdentifier<NshMaps> nshMapsId = vppNshStateId.child(NshMaps.class); + registry.addStructuralReader(nshMapsId, NshMapsBuilder.class); + // NshMap + final InstanceIdentifier<NshMap> 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<FutureJVppNsh> { + + 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); + } + } +} + |