summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-10-24 16:14:37 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-11-02 09:22:39 +0000
commit4787db493bbf3fca8437ce219766a24c62f24c37 (patch)
tree4be5f2b01321c9e5d9832d0e67142d0ccb1566ea
parentf335d213be6acd95835003bb7f5e591018fc06c2 (diff)
HONEYCOMB-248 Enable in/out NAT feature read
Change-Id: I6fe57b955437d0b0024323bcbac268f0ed4799f6 Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
-rw-r--r--nat/nat2vpp/pom.xml7
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/AbstractInterfaceNatCustomizer.java72
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java51
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java112
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java111
-rw-r--r--nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizerTest.java107
-rw-r--r--nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizerTest.java94
7 files changed, 526 insertions, 28 deletions
diff --git a/nat/nat2vpp/pom.xml b/nat/nat2vpp/pom.xml
index ba8204d6c..ad81e0662 100644
--- a/nat/nat2vpp/pom.xml
+++ b/nat/nat2vpp/pom.xml
@@ -30,6 +30,7 @@
<properties>
<honeycomb.infra.version>1.16.12-SNAPSHOT</honeycomb.infra.version>
+ <honeycomb.vpp.common.version>1.16.12-SNAPSHOT</honeycomb.vpp.common.version>
</properties>
<dependencies>
@@ -101,6 +102,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>io.fd.honeycomb.vpp</groupId>
+ <artifactId>vpp-translate-test</artifactId>
+ <version>${honeycomb.vpp.common.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/AbstractInterfaceNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/AbstractInterfaceNatCustomizer.java
new file mode 100644
index 000000000..441218a3f
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/AbstractInterfaceNatCustomizer.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.nat.read.ifc;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+
+abstract class AbstractInterfaceNatCustomizer<C extends DataObject, B extends Builder<C>>
+ implements InitializingReaderCustomizer<C, B> {
+
+ private final DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr;
+ private final NamingContext ifcContext;
+
+ AbstractInterfaceNatCustomizer(@Nonnull final DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr,
+ @Nonnull final NamingContext ifcContext) {
+ this.dumpMgr = dumpMgr;
+ this.ifcContext = ifcContext;
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id,
+ @Nonnull final B builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ getLog().debug("Reading NAT features on interface: {}", ifcName);
+ final int index = ifcContext.getIndex(ifcName, ctx.getMappingContext());
+
+ // Cache dump for each interface under the same key since this is all ifc dump
+ final Optional<SnatInterfaceDetailsReplyDump> dump =
+ dumpMgr.getDump(id, getClass().getName(), ctx.getModificationCache(), null);
+
+ // Find entries for current ifc and if is marked as inside set the builder to return presence container
+ dump.or(new SnatInterfaceDetailsReplyDump()).snatInterfaceDetails.stream()
+ .filter(snatIfcDetail -> snatIfcDetail.swIfIndex == index)
+ .filter(this::isExpectedNatType)
+ .findFirst()
+ .ifPresent(snatIfcDetail -> setBuilderPresence(builder));
+ // Not setting data, just marking the builder to propagate empty container to indicate presence
+ }
+
+ protected abstract Logger getLog();
+
+ abstract void setBuilderPresence(@Nonnull final B builder);
+
+ abstract boolean isExpectedNatType(final SnatInterfaceDetails snatInterfaceDetails);
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java
index 293a3dfd9..761986fc1 100644
--- a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java
@@ -17,9 +17,19 @@
package io.fd.honeycomb.nat.read.ifc;
-import io.fd.honeycomb.translate.impl.read.GenericReader;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.translate.impl.read.GenericInitReader;
+import io.fd.honeycomb.translate.read.ReadFailedException;
import io.fd.honeycomb.translate.read.ReaderFactory;
import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDump;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -42,14 +52,45 @@ public final class IfcNatReaderFactory implements ReaderFactory {
IFC_ID.augmentation(NatInterfaceStateAugmentation.class);
private static final InstanceIdentifier<Nat> NAT_AUG_CONTAINER_ID = NAT_AUG_ID.child(Nat.class);
+ private final DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> snatIfcDumpMgr;
+ private final NamingContext ifcContext;
+
+ @Inject
+ public IfcNatReaderFactory(final FutureJVppSnatFacade jvppSnat,
+ @Named("interface-context") final NamingContext ifcContext) {
+ this.snatIfcDumpMgr = new DumpCacheManager.DumpCacheManagerBuilder<SnatInterfaceDetailsReplyDump, Void>()
+ .withExecutor(new SnatInterfaceExecutor(jvppSnat))
+ .build();
+ this.ifcContext = ifcContext;
+ }
+
@Override
public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
registry.addStructuralReader(NAT_AUG_ID, NatInterfaceStateAugmentationBuilder.class);
registry.addStructuralReader(NAT_AUG_CONTAINER_ID, NatBuilder.class);
- registry.addAfter(
- new GenericReader<>(NAT_AUG_CONTAINER_ID.child(Inbound.class), new InterfaceInboundNatCustomizer()), IFC_ID);
- registry.addAfter(
- new GenericReader<>(NAT_AUG_CONTAINER_ID.child(Outbound.class), new InterfaceOutboundNatCustomizer()), IFC_ID);
+ registry.addAfter(new GenericInitReader<>(NAT_AUG_CONTAINER_ID.child(Inbound.class),
+ new InterfaceInboundNatCustomizer(snatIfcDumpMgr, ifcContext)), IFC_ID);
+ registry.addAfter(new GenericInitReader<>(NAT_AUG_CONTAINER_ID.child(Outbound.class),
+ new InterfaceOutboundNatCustomizer(snatIfcDumpMgr, ifcContext)), IFC_ID);
+ }
+
+ private static final class SnatInterfaceExecutor implements
+ EntityDumpExecutor<SnatInterfaceDetailsReplyDump, Void>,
+ JvppReplyConsumer {
+
+ private final FutureJVppSnatFacade jvppSnat;
+
+ SnatInterfaceExecutor(final FutureJVppSnatFacade jvppSnat) {
+ this.jvppSnat = jvppSnat;
+ }
+
+ @Nonnull
+ @Override
+ public SnatInterfaceDetailsReplyDump executeDump(final InstanceIdentifier<?> identifier, final Void params)
+ throws ReadFailedException {
+ return getReplyForRead(
+ jvppSnat.snatInterfaceDump(new SnatInterfaceDump()).toCompletableFuture(), identifier);
+ }
}
}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java
index 5be35ce16..52467a19a 100644
--- a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java
@@ -17,39 +17,127 @@
package io.fd.honeycomb.nat.read.ifc;
import io.fd.honeycomb.translate.read.ReadContext;
-import io.fd.honeycomb.translate.read.ReadFailedException;
-import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.InboundBuilder;
import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class InterfaceInboundNatCustomizer implements ReaderCustomizer<Inbound, InboundBuilder> {
+final class InterfaceInboundNatCustomizer extends AbstractInterfaceNatCustomizer<Inbound, InboundBuilder> {
private static final Logger LOG = LoggerFactory.getLogger(InterfaceInboundNatCustomizer.class);
- @Nonnull
+ InterfaceInboundNatCustomizer(
+ @Nonnull final DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr,
+ @Nonnull final NamingContext ifcContext) {
+ super(dumpMgr, ifcContext);
+ }
+
@Override
- public InboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Inbound> id) {
- return new InboundBuilder();
+ protected Logger getLog() {
+ return LOG;
}
@Override
- public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Inbound> id,
- @Nonnull final InboundBuilder builder,
- @Nonnull final ReadContext ctx)
- throws ReadFailedException {
- // FIXME HONEYCOMB-248 VPP-459 Implement when read is available in VPP/Snat
- LOG.debug("Unable to read Inbound NAT feature state for an interface");
+ void setBuilderPresence(@Nonnull final InboundBuilder builder) {
+ ((PresenceInboundBuilder) builder).setPresent(true);
+ }
+
+ @Override
+ boolean isExpectedNatType(final SnatInterfaceDetails snatInterfaceDetails) {
+ return snatInterfaceDetails.isInside == 1;
+ }
+
+ @Nonnull
+ @Override
+ public InboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Inbound> id) {
+ // Return not present value by default
+ return new PresenceInboundBuilder(false);
}
@Override
public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Inbound readValue) {
((NatBuilder) parentBuilder).setInbound(readValue);
}
+
+ @Nonnull
+ @Override
+ public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<Inbound> id,
+ @Nonnull final Inbound readValue,
+ @Nonnull final ReadContext ctx) {
+ final InstanceIdentifier<Inbound> cfgId =
+ InstanceIdentifier.create(Interfaces.class)
+ .child(Interface.class,
+ new InterfaceKey(id.firstKeyOf(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class).getName()))
+ .augmentation(NatInterfaceAugmentation.class)
+ .child(Nat.class)
+ .child(Inbound.class);
+ return Initialized.create(cfgId, readValue);
+ }
+
+ // TODO HONEYCOMB-270, make this better, having to fake a builder + value is just exploitation.
+
+ /**
+ * Special Builder to also propagate empty container into the resulting data.
+ */
+ private static final class PresenceInboundBuilder extends InboundBuilder {
+
+ private volatile boolean isPresent = false;
+
+ PresenceInboundBuilder(final boolean isPresent) {
+ this.isPresent = isPresent;
+ }
+
+ void setPresent(final boolean present) {
+ this.isPresent = present;
+ }
+
+ @Override
+ public Inbound build() {
+ return isPresent
+ ? super.build()
+ : NotPresentInbound.NOT_PRESENT_INBOUND;
+ }
+ }
+
+ /**
+ * Fake container that returns false on equals.
+ */
+ private static final class NotPresentInbound implements Inbound {
+
+ private static final NotPresentInbound NOT_PRESENT_INBOUND = new NotPresentInbound();
+
+ @Override
+ public <E extends Augmentation<Inbound>> E getAugmentation(final Class<E> augmentationType) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Class<? extends DataContainer> getImplementedInterface() {
+ return Inbound.class;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ // This is necessary to fake this.equals(something)
+ return obj == NOT_PRESENT_INBOUND;
+ }
+ }
}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java
index cb0103111..b08a636ca 100644
--- a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java
@@ -17,38 +17,127 @@
package io.fd.honeycomb.nat.read.ifc;
import io.fd.honeycomb.translate.read.ReadContext;
-import io.fd.honeycomb.translate.read.ReadFailedException;
-import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.OutboundBuilder;
import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class InterfaceOutboundNatCustomizer implements ReaderCustomizer<Outbound, OutboundBuilder> {
+final class InterfaceOutboundNatCustomizer extends AbstractInterfaceNatCustomizer<Outbound, OutboundBuilder> {
private static final Logger LOG = LoggerFactory.getLogger(InterfaceOutboundNatCustomizer.class);
- @Nonnull
+ InterfaceOutboundNatCustomizer(
+ @Nonnull final DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr,
+ @Nonnull final NamingContext ifcContext) {
+ super(dumpMgr, ifcContext);
+ }
+
@Override
- public OutboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Outbound> id) {
- return new OutboundBuilder();
+ protected Logger getLog() {
+ return LOG;
}
@Override
- public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Outbound> id,
- @Nonnull final OutboundBuilder builder, @Nonnull final ReadContext ctx)
- throws ReadFailedException {
- // FIXME HONEYCOMB-248 VPP-459 Implement when read is available in VPP/Snat
- LOG.debug("Unable to read Outbound NAT feature state for an interface");
+ void setBuilderPresence(@Nonnull final OutboundBuilder builder) {
+ ((PresenceOutboundBuilder) builder).setPresent(true);
+ }
+
+ @Override
+ boolean isExpectedNatType(final SnatInterfaceDetails snatInterfaceDetails) {
+ return snatInterfaceDetails.isInside == 0;
+ }
+
+ @Nonnull
+ @Override
+ public OutboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Outbound> id) {
+ return new PresenceOutboundBuilder(false);
}
@Override
public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Outbound readValue) {
((NatBuilder) parentBuilder).setOutbound(readValue);
}
+
+ @Nonnull
+ @Override
+ public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<Outbound> id,
+ @Nonnull final Outbound readValue,
+ @Nonnull final ReadContext ctx) {
+ final InstanceIdentifier<Outbound> cfgId =
+ InstanceIdentifier.create(Interfaces.class)
+ .child(Interface.class,
+ new InterfaceKey(id.firstKeyOf(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class).getName()))
+ .augmentation(NatInterfaceAugmentation.class)
+ .child(Nat.class)
+ .child(Outbound.class);
+ return Initialized.create(cfgId, readValue);
+ }
+
+ // TODO HONEYCOMB-270, make this better, having to fake a builder + value is just exploitation.
+
+ /**
+ * Special Builder to also propagate empty container into the resulting data.
+ */
+ private static final class PresenceOutboundBuilder extends OutboundBuilder {
+
+ private volatile boolean isPresent = false;
+
+ PresenceOutboundBuilder(final boolean isPresent) {
+ this.isPresent = isPresent;
+ }
+
+ void setPresent(final boolean present) {
+ this.isPresent = present;
+ }
+
+ @Override
+ public Outbound build() {
+ final Outbound build = super.build();
+ return isPresent
+ ? build
+ : NotPresentOutbound.NOT_PRESENT_OUTBOUND;
+ }
+ }
+
+ /**
+ * Fake container that returns false on equals.
+ */
+ private static final class NotPresentOutbound implements Outbound {
+
+ private static final NotPresentOutbound NOT_PRESENT_OUTBOUND = new NotPresentOutbound();
+
+ @Override
+ public <E extends Augmentation<Outbound>> E getAugmentation(final Class<E> augmentationType) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Class<? extends DataContainer> getImplementedInterface() {
+ return Outbound.class;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ // This is necessary to fake this.equals(something)
+ return obj == NOT_PRESENT_OUTBOUND;
+ }
+ }
}
diff --git a/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizerTest.java b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizerTest.java
new file mode 100644
index 000000000..140d35fec
--- /dev/null
+++ b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.nat.read.ifc;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.honeycomb.vpp.test.read.ReaderCustomizerTest;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.InboundBuilder;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceInboundNatCustomizerTest
+ extends ReaderCustomizerTest<Inbound, InboundBuilder> {
+
+ private static final String IFC_NAME = "a";
+ private static final int IFC_IDX = 0;
+ private static final String CTX_NAME = "ifc";
+
+ @Mock
+ private EntityDumpExecutor<SnatInterfaceDetailsReplyDump, Void> abc;
+ private DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr;
+ private NamingContext ifcContext = new NamingContext(CTX_NAME, CTX_NAME);
+ private InstanceIdentifier<Inbound> id;
+
+ public InterfaceInboundNatCustomizerTest() {
+ super(Inbound.class, NatBuilder.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ id = getId(Inbound.class);
+ defineMapping(mappingContext, IFC_NAME, IFC_IDX, CTX_NAME);
+ // empty dump
+ Mockito.doReturn(new SnatInterfaceDetailsReplyDump()).when(abc).executeDump(id, null);
+ dumpMgr = new DumpCacheManager.DumpCacheManagerBuilder<SnatInterfaceDetailsReplyDump, Void>()
+ .withExecutor(abc)
+ .build();
+ }
+
+ static <T extends ChildOf<Nat>> InstanceIdentifier<T> getId(Class<T> boundType) {
+ return InstanceIdentifier.create(InterfacesState.class)
+ .child(Interface.class, new InterfaceKey(IFC_NAME))
+ .augmentation(NatInterfaceStateAugmentation.class)
+ .child(Nat.class)
+ .child(boundType);
+ }
+
+ @Test
+ public void testNoPresence() throws Exception {
+ assertFalse(getReader().read(id, ctx).isPresent());
+ }
+
+ private GenericReader<Inbound, InboundBuilder> getReader() {
+ return new GenericReader<>(RWUtils.makeIidWildcarded(id), customizer);
+ }
+
+ @Test
+ public void testPresence() throws Exception {
+ final SnatInterfaceDetailsReplyDump details = new SnatInterfaceDetailsReplyDump();
+ final SnatInterfaceDetails detail = new SnatInterfaceDetails();
+ detail.isInside = 1;
+ detail.swIfIndex = IFC_IDX;
+ details.snatInterfaceDetails = Lists.newArrayList(detail);
+ Mockito.doReturn(details).when(abc).executeDump(id, null);
+
+ assertTrue(getReader().read(id, ctx).isPresent());
+ }
+
+ @Override
+ protected ReaderCustomizer<Inbound, InboundBuilder> initCustomizer() {
+ return new InterfaceInboundNatCustomizer(dumpMgr, ifcContext);
+ }
+} \ No newline at end of file
diff --git a/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizerTest.java b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizerTest.java
new file mode 100644
index 000000000..c33e040bb
--- /dev/null
+++ b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.nat.read.ifc;
+
+import static io.fd.honeycomb.nat.read.ifc.InterfaceInboundNatCustomizerTest.getId;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.honeycomb.vpp.test.read.ReaderCustomizerTest;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceDetailsReplyDump;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.OutboundBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class InterfaceOutboundNatCustomizerTest
+ extends ReaderCustomizerTest<Outbound, OutboundBuilder> {
+
+ private static final String IFC_NAME = "a";
+ private static final int IFC_IDX = 0;
+ private static final String CTX_NAME = "ifc";
+
+ @Mock
+ private EntityDumpExecutor<SnatInterfaceDetailsReplyDump, Void> abc;
+ private DumpCacheManager<SnatInterfaceDetailsReplyDump, Void> dumpMgr;
+ private NamingContext ifcContext = new NamingContext(CTX_NAME, CTX_NAME);
+ private InstanceIdentifier<Outbound> id;
+
+ public InterfaceOutboundNatCustomizerTest() {
+ super(Outbound.class, NatBuilder.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ id = getId(Outbound.class);
+ defineMapping(mappingContext, IFC_NAME, IFC_IDX, CTX_NAME);
+ // empty dump
+ Mockito.doReturn(new SnatInterfaceDetailsReplyDump()).when(abc).executeDump(id, null);
+ dumpMgr = new DumpCacheManager.DumpCacheManagerBuilder<SnatInterfaceDetailsReplyDump, Void>()
+ .withExecutor(abc)
+ .build();
+ }
+
+ @Test
+ public void testNoPresence() throws Exception {
+ assertFalse(getReader().read(id, ctx).isPresent());
+ }
+
+ private GenericReader<Outbound, OutboundBuilder> getReader() {
+ return new GenericReader<>(RWUtils.makeIidWildcarded(id), customizer);
+ }
+
+ @Test
+ public void testPresence() throws Exception {
+ final SnatInterfaceDetailsReplyDump details = new SnatInterfaceDetailsReplyDump();
+ final SnatInterfaceDetails detail = new SnatInterfaceDetails();
+ detail.isInside = 0;
+ detail.swIfIndex = IFC_IDX;
+ details.snatInterfaceDetails = Lists.newArrayList(detail);
+ Mockito.doReturn(details).when(abc).executeDump(id, null);
+
+ assertTrue(getReader().read(id, ctx).isPresent());
+ }
+
+ @Override
+ protected ReaderCustomizer<Outbound, OutboundBuilder> initCustomizer() {
+ return new InterfaceOutboundNatCustomizer(dumpMgr, ifcContext);
+ }
+} \ No newline at end of file