From 4787db493bbf3fca8437ce219766a24c62f24c37 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Mon, 24 Oct 2016 16:14:37 +0200 Subject: HONEYCOMB-248 Enable in/out NAT feature read Change-Id: I6fe57b955437d0b0024323bcbac268f0ed4799f6 Signed-off-by: Maros Marsalek --- .../read/ifc/AbstractInterfaceNatCustomizer.java | 72 +++++++++++++ .../nat/read/ifc/IfcNatReaderFactory.java | 51 +++++++++- .../read/ifc/InterfaceInboundNatCustomizer.java | 112 ++++++++++++++++++--- .../read/ifc/InterfaceOutboundNatCustomizer.java | 111 ++++++++++++++++++-- 4 files changed, 318 insertions(+), 28 deletions(-) create mode 100644 nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/AbstractInterfaceNatCustomizer.java (limited to 'nat/nat2vpp/src/main') 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> + implements InitializingReaderCustomizer { + + private final DumpCacheManager dumpMgr; + private final NamingContext ifcContext; + + AbstractInterfaceNatCustomizer(@Nonnull final DumpCacheManager dumpMgr, + @Nonnull final NamingContext ifcContext) { + this.dumpMgr = dumpMgr; + this.ifcContext = ifcContext; + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier 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 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_AUG_CONTAINER_ID = NAT_AUG_ID.child(Nat.class); + private final DumpCacheManager snatIfcDumpMgr; + private final NamingContext ifcContext; + + @Inject + public IfcNatReaderFactory(final FutureJVppSnatFacade jvppSnat, + @Named("interface-context") final NamingContext ifcContext) { + this.snatIfcDumpMgr = new DumpCacheManager.DumpCacheManagerBuilder() + .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, + 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 { +final class InterfaceInboundNatCustomizer extends AbstractInterfaceNatCustomizer { private static final Logger LOG = LoggerFactory.getLogger(InterfaceInboundNatCustomizer.class); - @Nonnull + InterfaceInboundNatCustomizer( + @Nonnull final DumpCacheManager dumpMgr, + @Nonnull final NamingContext ifcContext) { + super(dumpMgr, ifcContext); + } + @Override - public InboundBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new InboundBuilder(); + protected Logger getLog() { + return LOG; } @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier 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 id) { + // Return not present value by default + return new PresenceInboundBuilder(false); } @Override public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Inbound readValue) { ((NatBuilder) parentBuilder).setInbound(readValue); } + + @Nonnull + @Override + public Initialized init(@Nonnull final InstanceIdentifier id, + @Nonnull final Inbound readValue, + @Nonnull final ReadContext ctx) { + final InstanceIdentifier 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 getAugmentation(final Class augmentationType) { + throw new UnsupportedOperationException(); + } + + @Override + public Class 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 { +final class InterfaceOutboundNatCustomizer extends AbstractInterfaceNatCustomizer { private static final Logger LOG = LoggerFactory.getLogger(InterfaceOutboundNatCustomizer.class); - @Nonnull + InterfaceOutboundNatCustomizer( + @Nonnull final DumpCacheManager dumpMgr, + @Nonnull final NamingContext ifcContext) { + super(dumpMgr, ifcContext); + } + @Override - public OutboundBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new OutboundBuilder(); + protected Logger getLog() { + return LOG; } @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier 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 id) { + return new PresenceOutboundBuilder(false); } @Override public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Outbound readValue) { ((NatBuilder) parentBuilder).setOutbound(readValue); } + + @Nonnull + @Override + public Initialized init(@Nonnull final InstanceIdentifier id, + @Nonnull final Outbound readValue, + @Nonnull final ReadContext ctx) { + final InstanceIdentifier 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 getAugmentation(final Class augmentationType) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getImplementedInterface() { + return Outbound.class; + } + + @Override + public boolean equals(final Object obj) { + // This is necessary to fake this.equals(something) + return obj == NOT_PRESENT_OUTBOUND; + } + } } -- cgit 1.2.3-korg