From 7731d1b1e94617d676a9118497d99677d5dd915a Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Mon, 21 Nov 2016 14:28:41 +0100 Subject: HONEYCOMB-278 Expose basic CRUD for port mirroring Change-Id: I9ed339fd8c7daf1433709dcd862e64b690c5d3da Signed-off-by: Maros Marsalek --- .../hc2vpp/v3po/InterfacesStateReaderFactory.java | 27 +++-- .../io/fd/hc2vpp/v3po/InterfacesWriterFactory.java | 28 +++-- .../span/MirroredInterfacesCustomizer.java | 126 +++++++++++++++++++++ .../span/MirroredInterfacesCustomizer.java | 117 +++++++++++++++++++ 4 files changed, 281 insertions(+), 17 deletions(-) create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/span/MirroredInterfacesCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/span/MirroredInterfacesCustomizer.java (limited to 'v3po/v3po2vpp/src/main/java/io') diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java index f01cd9e99..8a5f09202 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java @@ -19,13 +19,7 @@ package io.fd.hc2vpp.v3po; import com.google.common.collect.Sets; import com.google.inject.Inject; import com.google.inject.name.Named; -import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4AddressCustomizer; -import io.fd.honeycomb.translate.impl.read.GenericInitListReader; -import io.fd.honeycomb.translate.impl.read.GenericInitReader; -import io.fd.honeycomb.translate.impl.read.GenericListReader; -import io.fd.honeycomb.translate.impl.read.GenericReader; -import io.fd.honeycomb.translate.read.ReaderFactory; -import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.hc2vpp.common.translate.util.NamingContext; import io.fd.hc2vpp.v3po.interfacesstate.EthernetCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.GreCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer; @@ -36,12 +30,19 @@ import io.fd.hc2vpp.v3po.interfacesstate.VhostUserCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.VxlanCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.VxlanGpeCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.acl.ingress.AclCustomizer; +import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4AddressCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4Customizer; import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4NeighbourCustomizer; import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv6Customizer; import io.fd.hc2vpp.v3po.interfacesstate.pbb.PbbRewriteStateCustomizer; +import io.fd.hc2vpp.v3po.interfacesstate.span.MirroredInterfacesCustomizer; import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; -import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.impl.read.GenericInitListReader; +import io.fd.honeycomb.translate.impl.read.GenericInitReader; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; import io.fd.vpp.jvpp.core.future.FutureJVppCore; 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.InterfacesStateBuilder; @@ -60,11 +61,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Gre; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.L2; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Span; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.SpanBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Tap; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VhostUser; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Vxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VxlanGpe; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.span.attributes.MirroredInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl; @@ -173,6 +177,13 @@ public final class InterfacesStateReaderFactory implements ReaderFactory { // Proxy ARP registry.add(new GenericReader<>(vppIfcAugId.child(ProxyArp.class), new ProxyArpCustomizer(jvpp, ifcNamingCtx))); + + // Span + final InstanceIdentifier spanId = vppIfcAugId.child(Span.class); + registry.addStructuralReader(spanId, SpanBuilder.class); + // MirroredInterfaces + registry.add(new GenericInitReader<>(spanId.child(MirroredInterfaces.class), + new MirroredInterfacesCustomizer(jvpp, ifcNamingCtx))); } private void initPbbRewriteAugmentation(final ModifiableReaderRegistryBuilder registry, diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java index eb68b6fbf..382e036d7 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java @@ -22,29 +22,30 @@ import static io.fd.hc2vpp.v3po.VppClassifierHoneycombWriterFactory.CLASSIFY_TAB import com.google.common.collect.Sets; import com.google.inject.Inject; import com.google.inject.name.Named; +import io.fd.hc2vpp.common.translate.util.NamingContext; import io.fd.hc2vpp.v3po.interfaces.EthernetCustomizer; import io.fd.hc2vpp.v3po.interfaces.GreCustomizer; +import io.fd.hc2vpp.v3po.interfaces.InterfaceCustomizer; import io.fd.hc2vpp.v3po.interfaces.L2Customizer; import io.fd.hc2vpp.v3po.interfaces.LoopbackCustomizer; +import io.fd.hc2vpp.v3po.interfaces.ProxyArpCustomizer; +import io.fd.hc2vpp.v3po.interfaces.RoutingCustomizer; import io.fd.hc2vpp.v3po.interfaces.TapCustomizer; +import io.fd.hc2vpp.v3po.interfaces.VhostUserCustomizer; import io.fd.hc2vpp.v3po.interfaces.VxlanCustomizer; import io.fd.hc2vpp.v3po.interfaces.VxlanGpeCustomizer; import io.fd.hc2vpp.v3po.interfaces.acl.egress.EgressIetfAclWriter; import io.fd.hc2vpp.v3po.interfaces.acl.ingress.AclCustomizer; -import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4NeighbourCustomizer; -import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; -import io.fd.honeycomb.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.translate.impl.write.GenericWriter; -import io.fd.hc2vpp.v3po.interfaces.InterfaceCustomizer; -import io.fd.hc2vpp.v3po.interfaces.ProxyArpCustomizer; -import io.fd.hc2vpp.v3po.interfaces.RoutingCustomizer; -import io.fd.hc2vpp.v3po.interfaces.VhostUserCustomizer; import io.fd.hc2vpp.v3po.interfaces.acl.ingress.IngressIetfAclWriter; import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4AddressCustomizer; import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4Customizer; +import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4NeighbourCustomizer; import io.fd.hc2vpp.v3po.interfaces.ip.Ipv6Customizer; import io.fd.hc2vpp.v3po.interfaces.pbb.PbbRewriteCustomizer; -import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.interfaces.span.MirroredInterfacesCustomizer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.impl.write.GenericWriter; import io.fd.honeycomb.translate.write.WriterFactory; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; import io.fd.vpp.jvpp.core.future.FutureJVppCore; @@ -65,11 +66,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Loopback; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ProxyArp; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Routing; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Span; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.span.attributes.MirroredInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl; @@ -232,6 +235,13 @@ public final class InterfacesWriterFactory implements WriterFactory { new GenericWriter<>(EGRESS_IETF_ACL_ID, new io.fd.hc2vpp.v3po.interfaces.acl.egress.IetfAclCustomizer(egressAclWriter, ifcNamingContext))); + // Span writers + // Mirrored interfaces + final InstanceIdentifier mirroredIfcsId = VPP_IFC_AUG_ID + .child(Span.class) + .child(MirroredInterfaces.class); + registry.addAfter(new GenericWriter<>(mirroredIfcsId, new MirroredInterfacesCustomizer(jvpp, ifcNamingContext)), + ifcId); } private void addPbbAugmentationWriters(final InstanceIdentifier ifcId, diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/span/MirroredInterfacesCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/span/MirroredInterfacesCustomizer.java new file mode 100644 index 000000000..c45bc6aa8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/span/MirroredInterfacesCustomizer.java @@ -0,0 +1,126 @@ +/* + * 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.hc2vpp.v3po.interfaces.span; + +import com.google.common.base.Preconditions; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSpanEnableDisable; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSpanEnableDisableReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.span.attributes.MirroredInterfaces; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class MirroredInterfacesCustomizer + extends FutureJVppCustomizer + implements WriterCustomizer, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MirroredInterfacesCustomizer.class); + + private final NamingContext ifcContext; + + public MirroredInterfacesCustomizer(@Nonnull final FutureJVppCore futureJVppCore, final NamingContext ifcContext) { + super(futureJVppCore); + this.ifcContext = ifcContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterfaces dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.trace("Writing mirrored interfaces for: {} as: {}", id, dataAfter); + + final int dstId = + ifcContext.getIndex(id.firstKeyOf(Interface.class).getName(), writeContext.getMappingContext()); + + // Collect source IDs + final List srcIds = dataAfter.getMirroredInterface().stream() + .map(ifcName -> ifcContext.getIndex(ifcName, writeContext.getMappingContext())) + // Collecting before executing to verify we have all the IDs first, failing fast... + .collect(Collectors.toList()); + + Preconditions.checkArgument(!srcIds.contains(dstId), + "Source and Destination interface for port mirroring detected: %s at %s", dstId, id); + + // Invoke addition for each source ID + final List> futures = srcIds.stream() + .map(srcId -> getSpanAddDelRequest(dstId, srcId, true)) + .map(request -> getFutureJVpp().swInterfaceSpanEnableDisable(request).toCompletableFuture()) + .collect(Collectors.toList()); + + // Wait for success/exception + for (final CompletableFuture future : futures) { + getReplyForWrite(future, id); + } + + LOG.trace("Mirrored interfaces for: {} written successfully", id); + } + + private SwInterfaceSpanEnableDisable getSpanAddDelRequest(final int dstId, final Integer srcId, final boolean isAdd) { + final SwInterfaceSpanEnableDisable spanAddDel = new SwInterfaceSpanEnableDisable(); + spanAddDel.enable = (byte) (isAdd ? 1 : 0); + spanAddDel.swIfIndexFrom = srcId; + spanAddDel.swIfIndexTo = dstId; + return spanAddDel; + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterfaces dataBefore, + @Nonnull final MirroredInterfaces dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + deleteCurrentAttributes(id, dataBefore, writeContext); + writeCurrentAttributes(id, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterfaces dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.trace("Removing mirrored interfaces for: {} as: {}", id, dataBefore); + + final int dstId = + ifcContext.getIndex(id.firstKeyOf(Interface.class).getName(), writeContext.getMappingContext()); + + final List srcIds = dataBefore.getMirroredInterface().stream() + .map(ifcName -> ifcContext.getIndex(ifcName, writeContext.getMappingContext())) + // Collecting before executing to verify we have all the IDs first, failing fast... + .collect(Collectors.toList()); + + final List> futures = srcIds.stream() + .map(srcId -> getSpanAddDelRequest(dstId, srcId, false)) + .map(request -> getFutureJVpp().swInterfaceSpanEnableDisable(request).toCompletableFuture()) + .collect(Collectors.toList()); + + for (final CompletableFuture future : futures) { + getReplyForWrite(future, id); + } + + LOG.trace("Mirrored interfaces for: {} removed successfully", id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/span/MirroredInterfacesCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/span/MirroredInterfacesCustomizer.java new file mode 100644 index 000000000..2396bcfb7 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/span/MirroredInterfacesCustomizer.java @@ -0,0 +1,117 @@ +/* + * 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.hc2vpp.v3po.interfacesstate.span; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.Initialized; +import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSpanDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.SwInterfaceSpanDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.stream.Collectors; +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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Span; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.SpanBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.span.attributes.MirroredInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.span.attributes.MirroredInterfacesBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class MirroredInterfacesCustomizer + extends FutureJVppCustomizer + implements InitializingReaderCustomizer, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MirroredInterfacesCustomizer.class); + + private final NamingContext ifcContext; + + public MirroredInterfacesCustomizer(@Nonnull final FutureJVppCore futureJVppCore, final NamingContext ifcContext) { + super(futureJVppCore); + this.ifcContext = ifcContext; + } + + @Nonnull + @Override + public MirroredInterfacesBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new MirroredInterfacesBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterfacesBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.trace("Reading mirrored interfaces under: {}", id); + final int dstId = + ifcContext.getIndex(id.firstKeyOf(Interface.class).getName(), ctx.getMappingContext()); + + final SwInterfaceSpanDetailsReplyDump replyForRead; + if (ctx.getModificationCache().containsKey(getCacheKey())) { + replyForRead = (SwInterfaceSpanDetailsReplyDump) ctx.getModificationCache().get(getCacheKey()); + } else { + replyForRead = getReplyForRead(getFutureJVpp().swInterfaceSpanDump( + new SwInterfaceSpanDump()).toCompletableFuture(), id); + ctx.getModificationCache().put(getCacheKey(), replyForRead); + } + + final List mirroredInterfaces = + replyForRead.swInterfaceSpanDetails.stream() + .filter(detail -> detail.swIfIndexTo == dstId) + .map(detail -> ifcContext.getName(detail.swIfIndexFrom, ctx.getMappingContext())) + .collect(Collectors.toList()); + + LOG.debug("Mirrored interfaces for: {} read as: {}", id, mirroredInterfaces); + + if (!mirroredInterfaces.isEmpty()) { + builder.setMirroredInterface(mirroredInterfaces); + } + } + + private String getCacheKey() { + return getClass().getName(); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, + @Nonnull final MirroredInterfaces readValue) { + ((SpanBuilder) parentBuilder).setMirroredInterfaces(readValue); + } + + @Nonnull + @Override + public Initialized init(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterfaces readValue, + @Nonnull final ReadContext ctx) { + final InstanceIdentifier cfgId = + InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class)) + .augmentation(VppInterfaceAugmentation.class) + .child(Span.class) + .child(MirroredInterfaces.class); + return Initialized.create(cfgId, readValue); + } +} -- cgit 1.2.3-korg