diff options
6 files changed, 372 insertions, 18 deletions
diff --git a/v3po/api/src/main/yang/v3po.yang b/v3po/api/src/main/yang/v3po.yang index 18b68620e..bc464646e 100644 --- a/v3po/api/src/main/yang/v3po.yang +++ b/v3po/api/src/main/yang/v3po.yang @@ -10,7 +10,8 @@ module v3po { - moved ACL definitions to vpp-acl module - updated l2 container constraint (permit IP address on BVI interface) - added PID of vpp process to vpp-state - - added support for Loopback interfaces"; + - added support for Loopback interfaces + - added support for port mirroring"; } revision "2015-01-05" { @@ -435,6 +436,16 @@ module v3po { } } + grouping span-attributes { + description "Parameters of the SPAN feature"; + + container mirrored-interfaces { + leaf-list mirrored-interface { + type if:interface-ref; // todo use interface-state-ref for operational data? + } + } + } + augment /if:interfaces/if:interface { ext:augment-identifier "vpp-interface-augmentation"; @@ -522,6 +533,10 @@ module v3po { uses vpp-acl:ietf-acl-base-attributes; } } + + container span { + uses span-attributes; + } } container vpp { @@ -613,6 +628,10 @@ module v3po { uses vpp-acl:ietf-acl-base-attributes; } } + + container span { + uses span-attributes; + } } augment /if:interfaces-state/if:interface/if:statistics { diff --git a/v3po/postman_rest_collection.json b/v3po/postman_rest_collection.json index 79c7d41b4..e0dda472a 100644 --- a/v3po/postman_rest_collection.json +++ b/v3po/postman_rest_collection.json @@ -151,6 +151,17 @@ "owner": "45557" }, { + "id": "df84e568-dac6-7014-f798-57dc87869aed", + "name": "SPAN", + "description": "", + "order": [ + "cdf8e109-9af6-9000-4bb4-2261ad0c3c83", + "3fda19c4-0afe-f738-e4a5-5d4f99e4f588", + "70a990d6-8786-95a1-cab0-adf8e14a879f" + ], + "owner": "45557" + }, + { "id": "ebed4cf3-96db-7ea3-1216-a0802c8f47d3", "name": "TAP", "description": "", @@ -823,6 +834,26 @@ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, { + "id": "3fda19c4-0afe-f738-e4a5-5d4f99e4f588", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8183/restconf/operational/ietf-interfaces:interfaces-state/interface/GigabitEthernet0%2F8%2F0/span", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1477908227905, + "name": "Read port mirroring", + "description": "show span", + "collectionId": "5bad4634-e5cf-900e-9733-0976aa9bea64", + "responses": [], + "rawModeData": "" + }, + { "id": "44df5e99-524f-ae01-0d60-54257fd16ad5", "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", "url": "http://localhost:8183/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff", @@ -1183,6 +1214,26 @@ "folder": "015dc7da-a47b-fcdf-3dee-2760fb5de9fd" }, { + "id": "70a990d6-8786-95a1-cab0-adf8e14a879f", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/span", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1477907954064, + "name": "Delete port mirroring local0 -> GigabiteEthernet0/8/0", + "description": "", + "collectionId": "5bad4634-e5cf-900e-9733-0976aa9bea64", + "responses": [], + "rawModeData": "" + }, + { "id": "7b592c36-12a3-2867-ed71-80ec74695dec", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/local0", @@ -1579,6 +1630,26 @@ "folder": "e742a44e-2e82-fe0c-d7c1-2f6b6bc1f0e9" }, { + "id": "cdf8e109-9af6-9000-4bb4-2261ad0c3c83", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/span", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1477905258870, + "name": "Set port mirroring local0 -> GigabiteEthernet0/8/0", + "description": "set span src local0 dst GigabiteEthernet0/8/0", + "collectionId": "5bad4634-e5cf-900e-9733-0976aa9bea64", + "responses": [], + "rawModeData": "{\r\n \r\n \"span\": {\r\n \t\"mirrored-interfaces\": {\r\n \t\t\"mirrored-interface\": [\"local0\"]\r\n \t}\r\n }\r\n \r\n}" + }, + { "id": "ea9e0f3b-ede6-2104-892b-bb8fd72e3d5d", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", "url": "http://localhost:8183/restconf/config/ietf-access-control-list:access-lists/acl/ietf-access-control-list:eth-acl/acl1", 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<Span> 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<MirroredInterfaces> 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<Interface> 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<MirroredInterfaces>, 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<MirroredInterfaces> 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<Integer> 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<CompletableFuture<SwInterfaceSpanEnableDisableReply>> 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<SwInterfaceSpanEnableDisableReply> 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<MirroredInterfaces> 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<MirroredInterfaces> 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<Integer> 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<CompletableFuture<SwInterfaceSpanEnableDisableReply>> futures = srcIds.stream() + .map(srcId -> getSpanAddDelRequest(dstId, srcId, false)) + .map(request -> getFutureJVpp().swInterfaceSpanEnableDisable(request).toCompletableFuture()) + .collect(Collectors.toList()); + + for (final CompletableFuture<SwInterfaceSpanEnableDisableReply> 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<MirroredInterfaces, MirroredInterfacesBuilder>, 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<MirroredInterfaces> id) { + return new MirroredInterfacesBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<MirroredInterfaces> 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<String> 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<? extends DataObject> parentBuilder, + @Nonnull final MirroredInterfaces readValue) { + ((SpanBuilder) parentBuilder).setMirroredInterfaces(readValue); + } + + @Nonnull + @Override + public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<MirroredInterfaces> id, + @Nonnull final MirroredInterfaces readValue, + @Nonnull final ReadContext ctx) { + final InstanceIdentifier<MirroredInterfaces> cfgId = + InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class)) + .augmentation(VppInterfaceAugmentation.class) + .child(Span.class) + .child(MirroredInterfaces.class); + return Initialized.create(cfgId, readValue); + } +} |