summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po
diff options
context:
space:
mode:
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po')
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java282
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java92
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java49
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java97
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java91
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java74
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java61
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java175
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java132
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java89
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java154
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java108
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java100
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java223
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java100
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java197
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java167
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java177
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java176
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java135
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java78
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java133
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java111
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java57
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java150
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java96
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java60
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java87
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java131
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java178
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java286
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java75
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java145
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java103
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java241
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java77
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java121
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java130
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java145
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java148
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java113
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java60
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java73
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java130
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java64
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java120
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java153
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java144
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java141
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java202
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java147
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java147
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java146
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java41
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java154
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java154
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java79
57 files changed, 7299 insertions, 0 deletions
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java
new file mode 100644
index 000000000..1d58bd18d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java
@@ -0,0 +1,282 @@
+/*
+ * 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.translate.v3po.initializers;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.data.init.AbstractDataTreeConverter;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.InterfacesBuilder;
+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.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Initializes ietf-interfaces config data based on operational state
+ */
+public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesState, Interfaces> {
+ private static final Logger LOG = LoggerFactory.getLogger(InterfacesInitializer.class);
+
+ public InterfacesInitializer(@Nonnull final DataBroker bindingDataBroker) {
+ super(bindingDataBroker, InstanceIdentifier.create(InterfacesState.class),
+ InstanceIdentifier.create(Interfaces.class));
+ }
+
+ @Override
+ protected Interfaces convert(final InterfacesState operationalData) {
+ LOG.debug("InterfacesInitializer.convert()");
+ InterfacesBuilder interfacesBuilder = new InterfacesBuilder();
+ interfacesBuilder
+ .setInterface(Lists.transform(operationalData.getInterface(), InterfacesInitializer::initialize));
+ return interfacesBuilder.build();
+ }
+
+ // FIXME https://jira.fd.io/browse/HONEYCOMB-73 this kind of initialization/transformation is bad
+ // There is no relation to readers, it cannot be extended (readers can) and its hard to keep in sync with readers
+
+ // TODO add IP v4/ v6 initializer
+
+ private static Interface initialize(
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input) {
+ InterfaceBuilder builder = new InterfaceBuilder();
+ builder.setKey(new InterfaceKey(input.getKey().getName()));
+ builder.setName(input.getName());
+ builder.setType(input.getType());
+ builder.setEnabled(AdminStatus.Up.equals(input.getAdminStatus()));
+ // builder.setLinkUpDownTrapEnable(); TODO not present in interfaces-state
+
+ initializeVppInterfaceStateAugmentation(input, builder);
+ SubInterfaceInitializationUtils.initializeSubinterfaceStateAugmentation(input, builder);
+ initializeIetfIpAugmentation(input, builder);
+
+ return builder.build();
+ }
+
+ private static void initializeVppInterfaceStateAugmentation(
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input,
+ final InterfaceBuilder builder) {
+ final VppInterfaceStateAugmentation vppIfcAugmentation =
+ input.getAugmentation(VppInterfaceStateAugmentation.class);
+ if (vppIfcAugmentation != null) {
+ final VppInterfaceAugmentationBuilder augmentBuilder = new VppInterfaceAugmentationBuilder();
+ builder.setDescription(vppIfcAugmentation.getDescription());
+
+ final Vxlan vxlan = vppIfcAugmentation.getVxlan();
+ if (vxlan != null) {
+ setVxlan(augmentBuilder, vxlan);
+ }
+
+ final VxlanGpe vxlanGpe = vppIfcAugmentation.getVxlanGpe();
+ if (vxlanGpe != null) {
+ setVxlanGpe(augmentBuilder, vxlanGpe);
+ }
+
+ final Tap tap = vppIfcAugmentation.getTap();
+ if (tap != null) {
+ setTap(input, augmentBuilder, tap);
+ }
+
+ final VhostUser vhostUser = vppIfcAugmentation.getVhostUser();
+ if (vhostUser != null) {
+ setVhostUser(augmentBuilder, vhostUser);
+ }
+
+ final L2 l2 = vppIfcAugmentation.getL2();
+ if (l2 != null) {
+ setL2(augmentBuilder, l2);
+ }
+
+ final Ethernet ethernet = vppIfcAugmentation.getEthernet();
+ if (ethernet != null) {
+ setEthernet(augmentBuilder, ethernet);
+ }
+
+ final Acl acl = vppIfcAugmentation.getAcl();
+ if (acl != null) {
+ setAcl(augmentBuilder, acl);
+ }
+
+ // TODO set routing, not present in interface-state
+
+ builder.addAugmentation(VppInterfaceAugmentation.class, augmentBuilder.build());
+ }
+ }
+
+ private static void initializeIetfIpAugmentation(
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input,
+ final InterfaceBuilder builder) {
+ final Interface2 ietfIpAugmentation = input.getAugmentation(Interface2.class);
+ if (ietfIpAugmentation != null) {
+ final Interface1Builder augmentBuilder = new Interface1Builder();
+
+ final Ipv4 ipv4 = ietfIpAugmentation.getIpv4();
+ if (ipv4 != null) {
+ final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address>
+ collect =
+ ipv4.getAddress().stream()
+ .map(
+ address -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder()
+ .setIp(address.getIp())
+ .setSubnet(getSubnet(address))
+ .build())
+ .collect(Collectors.toList());
+
+ final List<Neighbor> neighbors = ipv4.getNeighbor().stream()
+ .map(neighbor -> new NeighborBuilder().setIp(neighbor.getIp())
+ .setLinkLayerAddress(neighbor.getLinkLayerAddress()).build())
+ .collect(Collectors.toList());
+
+ augmentBuilder.setIpv4(new Ipv4Builder().setAddress(collect).setNeighbor(neighbors).build());
+ }
+
+ // TODO ipv6
+
+ builder.addAugmentation(Interface1.class, augmentBuilder.build());
+ }
+ }
+
+ private static Subnet getSubnet(final Address address) {
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.Subnet
+ subnet = address.getSubnet();
+
+ // TODO only prefix length supported
+ Preconditions.checkArgument(
+ subnet instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength);
+
+ return new PrefixLengthBuilder().setPrefixLength(
+ ((org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength) subnet)
+ .getPrefixLength()).build();
+ }
+
+ private static void setEthernet(final VppInterfaceAugmentationBuilder augmentBuilder, final Ethernet ethernet) {
+ final EthernetBuilder ethernetBuilder = new EthernetBuilder();
+ ethernetBuilder.setMtu(ethernet.getMtu());
+ augmentBuilder.setEthernet(ethernetBuilder.build());
+ }
+
+ private static void setAcl(final VppInterfaceAugmentationBuilder augmentBuilder, final Acl acl) {
+ final AclBuilder aclBuilder = new AclBuilder();
+ aclBuilder.setL2Acl(acl.getL2Acl());
+ aclBuilder.setIp4Acl(acl.getIp4Acl());
+ aclBuilder.setIp6Acl(acl.getIp6Acl());
+ augmentBuilder.setAcl(aclBuilder.build());
+ }
+
+ private static void setL2(final VppInterfaceAugmentationBuilder augmentBuilder, final L2 l2) {
+ final L2Builder l2Builder = new L2Builder();
+
+ final Interconnection interconnection = l2.getInterconnection();
+ if (interconnection != null) {
+ if (interconnection instanceof XconnectBased) {
+ final XconnectBasedBuilder xconnectBasedBuilder = new XconnectBasedBuilder();
+ xconnectBasedBuilder.setXconnectOutgoingInterface(
+ ((XconnectBased) interconnection).getXconnectOutgoingInterface());
+ l2Builder.setInterconnection(xconnectBasedBuilder.build());
+ } else if (interconnection instanceof BridgeBased) {
+ final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder();
+ bridgeBasedBuilder.setBridgeDomain(((BridgeBased) interconnection).getBridgeDomain());
+ bridgeBasedBuilder
+ .setBridgedVirtualInterface(((BridgeBased) interconnection).isBridgedVirtualInterface());
+ bridgeBasedBuilder.setSplitHorizonGroup(((BridgeBased) interconnection).getSplitHorizonGroup());
+ l2Builder.setInterconnection(bridgeBasedBuilder.build());
+ }
+ }
+
+ augmentBuilder.setL2(l2Builder.build());
+ }
+
+ private static void setVhostUser(final VppInterfaceAugmentationBuilder augmentBuilder, final VhostUser vhostUser) {
+ final VhostUserBuilder vhostUserBuilder = new VhostUserBuilder();
+ vhostUserBuilder.setRole(vhostUser.getRole());
+ vhostUserBuilder.setSocket(vhostUser.getSocket());
+ augmentBuilder.setVhostUser(vhostUserBuilder.build());
+ }
+
+ private static void setTap(
+ final @Nonnull org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input,
+ final VppInterfaceAugmentationBuilder augmentBuilder,
+ final Tap tap) {
+ final TapBuilder tapBuilder = new TapBuilder();
+ tapBuilder.setMac(input.getPhysAddress());
+ tapBuilder.setTapName(tap.getTapName());
+// tapBuilder.setDeviceInstance();
+ augmentBuilder.setTap(tapBuilder.build());
+ }
+
+ private static void setVxlan(final VppInterfaceAugmentationBuilder augmentBuilder, final Vxlan vxlan) {
+ final VxlanBuilder vxlanBuilder = new VxlanBuilder();
+ vxlanBuilder.setDst(vxlan.getDst());
+ vxlanBuilder.setSrc(vxlan.getSrc());
+ vxlanBuilder.setEncapVrfId(vxlan.getEncapVrfId());
+ vxlanBuilder.setVni(new VxlanVni(vxlan.getVni()));
+ augmentBuilder.setVxlan(vxlanBuilder.build());
+ }
+
+ private static void setVxlanGpe(final VppInterfaceAugmentationBuilder augmentBuilder, final VxlanGpe vxlanGpe) {
+ final VxlanGpeBuilder vxlanGpeBuilder = new VxlanGpeBuilder();
+ vxlanGpeBuilder.setLocal(vxlanGpe.getLocal());
+ vxlanGpeBuilder.setRemote(vxlanGpe.getRemote());
+ vxlanGpeBuilder.setVni(new VxlanGpeVni(vxlanGpe.getVni()));
+ vxlanGpeBuilder.setNextProtocol(vxlanGpe.getNextProtocol());
+ vxlanGpeBuilder.setEncapVrfId(vxlanGpe.getEncapVrfId());
+ vxlanGpeBuilder.setDecapVrfId(vxlanGpe.getDecapVrfId());
+ augmentBuilder.setVxlanGpe(vxlanGpeBuilder.build());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java
new file mode 100644
index 000000000..7acc75bcd
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java
@@ -0,0 +1,92 @@
+/*
+ * 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.translate.v3po.initializers;
+
+import com.google.common.collect.Lists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder;
+
+/**
+ * Utility class for sub interface initialization
+ */
+final class SubInterfaceInitializationUtils {
+
+ private SubInterfaceInitializationUtils() {
+ throw new UnsupportedOperationException("Utility class cannot be instantiated");
+ }
+
+ static void initializeSubinterfaceStateAugmentation(
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input,
+ final InterfaceBuilder builder) {
+ final SubinterfaceStateAugmentation subIfcAugmentation =
+ input.getAugmentation(SubinterfaceStateAugmentation.class);
+ if (subIfcAugmentation != null) {
+ final SubinterfaceAugmentationBuilder augmentBuilder = new SubinterfaceAugmentationBuilder();
+
+ final SubInterfaces subInterfaces = subIfcAugmentation.getSubInterfaces();
+ if (subInterfaces != null) {
+ setSubInterfaces(augmentBuilder, subInterfaces);
+ }
+
+ builder.addAugmentation(SubinterfaceAugmentation.class, augmentBuilder.build());
+ }
+ }
+
+ private static void setSubInterfaces(final SubinterfaceAugmentationBuilder augmentBuilder,
+ final SubInterfaces operationalData) {
+
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder
+ subInterfacesCfgBuilder =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder();
+ subInterfacesCfgBuilder.setSubInterface(Lists.transform(operationalData.getSubInterface(),
+ SubInterfaceInitializationUtils::convertSubInterface));
+ augmentBuilder.setSubInterfaces(subInterfacesCfgBuilder.build());
+ }
+
+ private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface convertSubInterface(
+ final SubInterface operationalData) {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder subInterfaceCfgBuilder =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder();
+
+ subInterfaceCfgBuilder.setEnabled(SubInterfaceStatus.Up.equals(operationalData.getAdminStatus()));
+ subInterfaceCfgBuilder.setIdentifier(operationalData.getIdentifier());
+ subInterfaceCfgBuilder.setKey(new SubInterfaceKey(operationalData.getIdentifier()));
+ subInterfaceCfgBuilder.setL2(operationalData.getL2());
+ subInterfaceCfgBuilder.setMatch(operationalData.getMatch());
+ subInterfaceCfgBuilder.setTags(operationalData.getTags());
+ subInterfaceCfgBuilder.setVlanType(operationalData.getVlanType());
+ subInterfaceCfgBuilder.setIpv4(operationalData.getIpv4());
+ subInterfaceCfgBuilder.setIpv6(operationalData.getIpv6());
+
+ if (operationalData.getAcl() != null) {
+ final AclBuilder aclBuilder = new AclBuilder();
+ aclBuilder.setL2Acl(operationalData.getAcl().getL2Acl());
+ aclBuilder.setIp4Acl(operationalData.getAcl().getIp4Acl());
+ aclBuilder.setIp6Acl(operationalData.getAcl().getIp6Acl());
+ subInterfaceCfgBuilder.setAcl(aclBuilder.build());
+ }
+
+ return subInterfaceCfgBuilder.build();
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java
new file mode 100644
index 000000000..42d1c59dc
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java
@@ -0,0 +1,49 @@
+/*
+ * 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.translate.v3po.initializers;
+
+import io.fd.honeycomb.data.init.AbstractDataTreeConverter;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Initializes vpp-classfier node in config data tree based on operational state.
+ */
+public class VppClasifierInitializer extends AbstractDataTreeConverter<VppClassifierState, VppClassifier> {
+ private static final InstanceIdentifier<VppClassifierState> OPER_ID =
+ InstanceIdentifier.create(VppClassifierState.class);
+ private static final InstanceIdentifier<VppClassifier> CFG_ID = InstanceIdentifier.create(VppClassifier.class);
+
+ public VppClasifierInitializer(@Nonnull final DataBroker bindingDataBroker) {
+ super(bindingDataBroker, OPER_ID, CFG_ID);
+ }
+
+ @Override
+ protected VppClassifier convert(final VppClassifierState operationalData) {
+ final VppClassifierBuilder builder = new VppClassifierBuilder();
+ builder.setClassifyTable(operationalData.getClassifyTable().stream()
+ .map(oper -> new ClassifyTableBuilder(oper).setName(oper.getName()).build())
+ .collect(Collectors.toList()));
+ return builder.build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java
new file mode 100644
index 000000000..370de347b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java
@@ -0,0 +1,97 @@
+/*
+ * 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.translate.v3po.initializers;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.data.init.AbstractDataTreeConverter;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Initializes vpp node in config data tree based on operational state.
+ */
+public class VppInitializer extends AbstractDataTreeConverter<VppState, Vpp> {
+ private static final Logger LOG = LoggerFactory.getLogger(VppInitializer.class);
+
+ public VppInitializer(@Nonnull final DataBroker bindingDataBroker) {
+ super(bindingDataBroker, InstanceIdentifier.create(VppState.class), InstanceIdentifier.create(Vpp.class));
+ }
+
+ // TODO move to v3po2vpp
+
+ @Override
+ protected Vpp convert(final VppState operationalData) {
+ LOG.debug("VppInitializer.convert()");
+
+ VppBuilder vppBuilder = new VppBuilder();
+ BridgeDomainsBuilder bdsBuilder = new BridgeDomainsBuilder();
+ bdsBuilder.setBridgeDomain(Lists.transform(operationalData.getBridgeDomains().getBridgeDomain(), CONVERT_BD));
+ vppBuilder.setBridgeDomains(bdsBuilder.build());
+ return vppBuilder.build();
+ }
+
+ private static final Function<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain, BridgeDomain>
+ CONVERT_BD =
+ new Function<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain, BridgeDomain>() {
+ @Nullable
+ @Override
+ public BridgeDomain apply(
+ @Nullable final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain input) {
+ final BridgeDomainBuilder builder = new BridgeDomainBuilder();
+ builder.setLearn(input.isLearn());
+ builder.setUnknownUnicastFlood(input.isUnknownUnicastFlood());
+ builder.setArpTermination(input.isArpTermination());
+ builder.setFlood(input.isFlood());
+ builder.setForward(input.isForward());
+ builder.setKey(new BridgeDomainKey(input.getKey().getName()));
+ builder.setName(input.getName());
+ setL2FibTable(builder, input.getL2FibTable());
+ return builder.build();
+ }
+ };
+
+ private static void setL2FibTable(@Nonnull final BridgeDomainBuilder builder,
+ @Nullable final L2FibTable l2FibTable) {
+ if (l2FibTable == null) {
+ return;
+ }
+ final L2FibTableBuilder tableBuilder = new L2FibTableBuilder()
+ .setL2FibEntry(
+ l2FibTable.getL2FibEntry().stream()
+ // Convert operational object to config. VPP does not support setting BVI (see v3po.yang)
+ .map(oper -> new L2FibEntryBuilder(oper).setBridgedVirtualInterface(null).build())
+ .collect(Collectors.toList()));
+ builder.setL2FibTable(tableBuilder.build());
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java
new file mode 100644
index 000000000..c292073e3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java
@@ -0,0 +1,91 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.rev150105.interfaces._interface.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ACLs on given interface.
+ */
+public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Acl>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final NamingContext classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ try {
+ setAcl(true, id, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ try {
+ setAcl(false, id, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, ifIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java
new file mode 100644
index 000000000..1d538ac3f
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java
@@ -0,0 +1,74 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.AclBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.InputAclSetInterface;
+import org.openvpp.jvpp.dto.InputAclSetInterfaceReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+interface AclWriter {
+
+ default void inputAclSetInterface(@Nonnull final FutureJVpp futureJvpp, final boolean isAdd,
+ @Nonnull final InstanceIdentifier<?> id, @Nonnull final AclBaseAttributes acl,
+ @Nonnegative final int ifIndex, @Nonnull final NamingContext classifyTableContext,
+ @Nonnull final MappingContext mappingContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = booleanToByte(isAdd);
+ request.swIfIndex = ifIndex;
+ request.l2TableIndex = ~0; // skip
+ request.ip4TableIndex = ~0; // skip
+ request.ip6TableIndex = ~0; // skip
+
+ final L2Acl l2Acl = acl.getL2Acl();
+ if (l2Acl != null) {
+ final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null");
+ request.l2TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+ }
+ final Ip4Acl ip4Acl = acl.getIp4Acl();
+ if (ip4Acl != null) {
+ final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null");
+ request.ip4TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+ }
+ final Ip6Acl ip6Acl = acl.getIp6Acl();
+ if (ip6Acl != null) {
+ final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null");
+ request.ip6TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+ }
+
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ futureJvpp.inputAclSetInterface(request);
+
+ TranslateUtils.getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java
new file mode 100644
index 000000000..2dd0dbd00
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java
@@ -0,0 +1,61 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EthernetCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Ethernet> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class);
+
+ public EthernetCustomizer(final FutureJVpp vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ // TODO
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ // VPP API does not support setting MTU
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataBefore, @Nonnull final Ethernet dataAfter,
+ @Nonnull final WriteContext writeContext) {
+ // TODO
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) {
+ // TODO
+ LOG.warn("Unsupported, ignoring configuration delete {}", id);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java
new file mode 100644
index 000000000..ecaaa4717
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java
@@ -0,0 +1,175 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceSetL2Bridge;
+import org.openvpp.jvpp.dto.SwInterfaceSetL2BridgeReply;
+import org.openvpp.jvpp.dto.SwInterfaceSetL2Xconnect;
+import org.openvpp.jvpp.dto.SwInterfaceSetL2XconnectReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Interconnection CUD support.
+ */
+final class InterconnectionWriteUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class);
+
+ private final FutureJVpp futureJvpp;
+ private final NamingContext interfaceContext;
+ private final NamingContext bridgeDomainContext;
+
+ InterconnectionWriteUtils(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null");
+ this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null");
+ this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null");
+ }
+
+ void setInterconnection(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final Interconnection ic, final WriteContext writeContext)
+ throws WriteFailedException {
+ try {
+ if (ic == null) { // TODO in case of update we should delete interconnection
+ LOG.trace("Interconnection is not set. Skipping");
+ } else if (ic instanceof XconnectBased) {
+ setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 1 /*enable*/);
+ } else if (ic instanceof BridgeBased) {
+ setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 1 /*enable*/);
+ } else {
+ // FIXME how does choice extensibility work
+ // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject
+ // FIXME we might need a choice customizer
+ // THis choice is already from augment, so its probably not possible to augment augmented choice
+ LOG.error("Unable to handle Interconnection of type {}", ic.getClass());
+ throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass());
+ }
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to update bridge/xconnect based interconnection flags for: {}, interconnection: {}",
+ ifcName, ic);
+ throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass(), e);
+ }
+ }
+
+ void deleteInterconnection(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final Interconnection ic, final WriteContext writeContext)
+ throws WriteFailedException {
+ try {
+ if (ic == null) { // TODO in case of update we should delete interconnection
+ LOG.trace("Interconnection is not set. Skipping");
+ } else if (ic instanceof XconnectBased) {
+ setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 0 /*disable*/);
+ } else if (ic instanceof BridgeBased) {
+ setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 0 /*disable*/);
+ } else {
+ LOG.error("Unable to delete Interconnection of type {}", ic.getClass());
+ throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass());
+ }
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete bridge/xconnect based interconnection flags for: {}, interconnection: {}",
+ ifcName, ic);
+ throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass(), e);
+ }
+ }
+
+ private void setBridgeBasedL2(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final BridgeBased bb,
+ final WriteContext writeContext, final byte enabled)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}", bb.getBridgeDomain(),
+ ifcName);
+
+ String bdName = bb.getBridgeDomain();
+
+ int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext());
+ checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist",
+ ifcName, bdName);
+
+ byte bvi = bb.isBridgedVirtualInterface()
+ ? (byte) 1
+ : (byte) 0;
+ byte shg = 0;
+ if (bb.getSplitHorizonGroup() != null) {
+ shg = bb.getSplitHorizonGroup().byteValue();
+ }
+
+ final CompletionStage<SwInterfaceSetL2BridgeReply> swInterfaceSetL2BridgeReplyCompletionStage = futureJvpp
+ .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bvi, enabled));
+ TranslateUtils.getReplyForWrite(swInterfaceSetL2BridgeReplyCompletionStage.toCompletableFuture(), id);
+
+ LOG.debug("Bridge based interconnection updated successfully for: {}, interconnection: {}", ifcName, bb);
+ }
+
+ private SwInterfaceSetL2Bridge getL2BridgeRequest(final int swIfIndex, final int bdId, final byte shg,
+ final byte bvi, final byte enabled) {
+ final SwInterfaceSetL2Bridge swInterfaceSetL2Bridge = new SwInterfaceSetL2Bridge();
+ swInterfaceSetL2Bridge.rxSwIfIndex = swIfIndex;
+ swInterfaceSetL2Bridge.bdId = bdId;
+ swInterfaceSetL2Bridge.shg = shg;
+ swInterfaceSetL2Bridge.bvi = bvi;
+ swInterfaceSetL2Bridge.enable = enabled;
+ return swInterfaceSetL2Bridge;
+ }
+
+ private void setXconnectBasedL2(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final XconnectBased ic,
+ final WriteContext writeContext, final byte enabled)
+ throws VppBaseCallException, WriteTimeoutException {
+ String outSwIfName = ic.getXconnectOutgoingInterface();
+ LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName, ifcName);
+
+ int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext());
+ checkArgument(outSwIfIndex > 0,
+ "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist",
+ ifcName, outSwIfIndex);
+
+ final CompletionStage<SwInterfaceSetL2XconnectReply> swInterfaceSetL2XconnectReplyCompletionStage =
+ futureJvpp
+ .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled));
+ TranslateUtils.getReplyForWrite(swInterfaceSetL2XconnectReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Xconnect based interconnection updated successfully for: {}, interconnection: {}", ifcName, ic);
+ }
+
+ private SwInterfaceSetL2Xconnect getL2XConnectRequest(final int rxIfc, final int txIfc,
+ final byte enabled) {
+
+ final SwInterfaceSetL2Xconnect swInterfaceSetL2Xconnect = new SwInterfaceSetL2Xconnect();
+ swInterfaceSetL2Xconnect.enable = enabled;
+ swInterfaceSetL2Xconnect.rxSwIfIndex = rxIfc;
+ swInterfaceSetL2Xconnect.txSwIfIndex = txIfc;
+ return swInterfaceSetL2Xconnect;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java
new file mode 100644
index 000000000..1bad2cdca
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java
@@ -0,0 +1,132 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceSetFlags;
+import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Ietf interface write customizer that only caches interface objects for child writers
+ */
+public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Interface, InterfaceKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public InterfaceCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ try {
+ setInterface(id, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Update of VppInterfaceAugment failed", e);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataBefore,
+ @Nonnull final Interface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ try {
+ updateInterface(id, dataBefore, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Update of VppInterfaceAugment failed", e);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataBefore,
+ @Nonnull final WriteContext writeContext) {
+
+ // TODO Handle deletes
+ }
+
+ private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf,
+ final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Setting interface: {} to: {}", id, swIf);
+ setInterfaceAttributes(id, swIf, swIf.getName(), writeContext);
+ }
+
+ private void setInterfaceAttributes(final InstanceIdentifier<Interface> id, final Interface swIf,
+ final String swIfName, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+
+ setInterfaceFlags(id, swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()),
+ swIf.isEnabled() ? (byte) 1 : (byte) 0);
+ }
+
+ private void updateInterface(final InstanceIdentifier<Interface> id,
+ final Interface dataBefore,
+ final Interface dataAfter, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Updating interface:{} to: {}", id, dataAfter);
+ setInterfaceAttributes(id, dataAfter, dataAfter.getName(), writeContext);
+ }
+
+ private void setInterfaceFlags(final InstanceIdentifier<Interface> id, final String swIfName, final int swIfIndex,
+ final byte enabled)
+ throws VppBaseCallException, WriteTimeoutException {
+ final CompletionStage<SwInterfaceSetFlagsReply> swInterfaceSetFlagsReplyFuture = getFutureJVpp().swInterfaceSetFlags(
+ getSwInterfaceSetFlagsInput(swIfIndex, enabled, (byte) 0 /* deleted */));
+
+ LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled);
+
+ TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id);
+ LOG.debug("Interface flags updated successfully for: {}, index: {}, enabled: {}",
+ swIfName, swIfIndex, enabled);
+ }
+
+ private SwInterfaceSetFlags getSwInterfaceSetFlagsInput(final int swIfIndex, final byte enabled, final byte deleted) {
+ final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags();
+ swInterfaceSetFlags.swIfIndex = swIfIndex;
+ swInterfaceSetFlags.adminUpDown = enabled;
+ swInterfaceSetFlags.linkUpDown = enabled;
+ swInterfaceSetFlags.deleted = deleted;
+ return swInterfaceSetFlags;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java
new file mode 100644
index 000000000..881c82b53
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java
@@ -0,0 +1,89 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.rev150105.interfaces._interface.L2;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class L2Customizer extends FutureJVppCustomizer implements WriterCustomizer<L2> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
+ private final NamingContext interfaceContext;
+ private final InterconnectionWriteUtils icWriteUtils;
+
+ public L2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext,
+ final NamingContext bridgeDomainContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ this.icWriteUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ setL2(id, swIfc, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ // TODO handle update properly (if possible)
+ setL2(id, swIfc, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ deleteL2(id, swIfc, ifcName, dataBefore, writeContext);
+ }
+
+ private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Setting L2 for interface: {}", ifcName);
+ // Nothing besides interconnection here
+ icWriteUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext);
+ }
+
+ private void deleteL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2Before,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting L2 for interface: {}", ifcName);
+ // Nothing besides interconnection here
+ icWriteUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java
new file mode 100644
index 000000000..86af47709
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java
@@ -0,0 +1,154 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+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.vpp.vlan.rev150527._802dot1q;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite;
+import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for vlan tag rewrite.<br> Sends {@code l2_interface_vlan_tag_rewrite} message to
+ * VPP.<br> Equivalent of invoking {@code vppctl set interface l2 tag-rewrite} command.
+ */
+public class RewriteCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Rewrite> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(final InstanceIdentifier<Rewrite> id, final Rewrite dataAfter,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+ try {
+ setTagRewrite(id, subifName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to write interface {}(id=): {}", subifName, writeContext, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<Rewrite> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+
+ private void setTagRewrite(final InstanceIdentifier<Rewrite> id, final String ifname, final Rewrite rewrite,
+ final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext());
+ LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, rewrite);
+
+ final CompletionStage<L2InterfaceVlanTagRewriteReply> replyCompletionStage =
+ getFutureJVpp().l2InterfaceVlanTagRewrite(getTagRewriteRequest(swIfIndex, rewrite));
+
+ TranslateUtils.getReplyForWrite(replyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Tag rewrite for interface {}(id=) set successfully: {}", ifname, swIfIndex, rewrite);
+ }
+
+ private L2InterfaceVlanTagRewrite getTagRewriteRequest(final int swIfIndex, final Rewrite rewrite) {
+ final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite();
+ request.swIfIndex = swIfIndex;
+ request.pushDot1Q = booleanToByte(_802dot1q.class == rewrite.getVlanType());
+
+ final List<PushTags> pushTags = rewrite.getPushTags();
+ final Short popTags = rewrite.getPopTags();
+
+ final int numberOfTagsToPop = popTags == null
+ ? 0
+ : popTags.intValue();
+ final int numberOfTagsToPush = pushTags == null
+ ? 0
+ : pushTags.size();
+
+ request.vtrOp = TagRewriteOperation.get(numberOfTagsToPop, numberOfTagsToPush).ordinal();
+
+ if (numberOfTagsToPush > 0) {
+ for (final PushTags tag : pushTags) {
+ if (tag.getIndex() == 0) {
+ request.tag1 = tag.getDot1qTag().getVlanId().getValue();
+ } else {
+ request.tag2 = tag.getDot1qTag().getVlanId().getValue();
+ }
+ }
+ }
+
+ LOG.debug("Generated tag rewrite request: {}", ReflectionToStringBuilder.toString(request));
+ return request;
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final Rewrite dataBefore,
+ @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+ try {
+ setTagRewrite(id, subifName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to update interface {}(id=): {}", subifName, writeContext, dataAfter);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+ try {
+ LOG.debug("Disabling tag rewrite for interface {}", subifName);
+ final Rewrite rewrite = new RewriteBuilder().build(); // rewrite without push and pops will cause delete
+ setTagRewrite(id, subifName, rewrite, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete interface {}(id=): {}", subifName, writeContext, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java
new file mode 100644
index 000000000..fe7b7263e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+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.rev150105.interfaces._interface.Routing;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceSetTable;
+import org.openvpp.jvpp.dto.SwInterfaceSetTableReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoutingCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Routing> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RoutingCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ try {
+ setRouting(id, ifName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataBefore, @Nonnull final Routing dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ try {
+ // TODO handle updates properly
+ setRouting(id, ifName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to update routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext) {
+ // TODO implement delete
+ }
+
+ private void setRouting(final InstanceIdentifier<Routing> id, final String name, final Routing rt,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
+ LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt);
+
+ int vrfId = (rt != null)
+ ? rt.getVrfId().intValue()
+ : 0;
+
+ if (vrfId != 0) {
+ final CompletionStage<SwInterfaceSetTableReply> swInterfaceSetTableReplyCompletionStage =
+ getFutureJVpp().swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, /* isIpv6 */ vrfId));
+ TranslateUtils.getReplyForWrite(swInterfaceSetTableReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt);
+ }
+ }
+
+ private SwInterfaceSetTable getInterfaceSetTableRequest(final int swIfc, final byte isIpv6, final int vrfId) {
+ final SwInterfaceSetTable swInterfaceSetTable = new SwInterfaceSetTable();
+ swInterfaceSetTable.isIpv6 = isIpv6;
+ swInterfaceSetTable.swIfIndex = swIfc;
+ swInterfaceSetTable.vrfId = vrfId;
+ return swInterfaceSetTable;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..45b2a480d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java
@@ -0,0 +1,100 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ACLs on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements WriterCustomizer<Acl>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final NamingContext classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ try {
+ setAcl(true, id, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ try {
+ setAcl(false, id, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ final String subInterfaceName = SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, subInterfaceIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java
new file mode 100644
index 000000000..6af19cb89
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java
@@ -0,0 +1,223 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+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.vpp.vlan.rev150527._802dot1ad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.MatchType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.Default;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTagged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.CreateSubif;
+import org.openvpp.jvpp.dto.CreateSubifReply;
+import org.openvpp.jvpp.dto.SwInterfaceSetFlags;
+import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for sub interface creation.<br> Sends {@code create_subif} message to VPP.<br>
+ * Equivalent of invoking {@code vppclt create subif} command.
+ */
+public class SubInterfaceCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<SubInterface, SubInterfaceKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String superIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createSubInterface(id, superIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to create sub interface for: {}, subInterface: {}", superIfName, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ private void createSubInterface(final InstanceIdentifier<SubInterface> id, @Nonnull final String superIfName,
+ @Nonnull final SubInterface subInterface,
+ final WriteContext writeContext) throws VppBaseCallException,
+ WriteTimeoutException {
+ final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext());
+ final CompletionStage<CreateSubifReply> createSubifReplyCompletionStage =
+ getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex));
+
+ final CreateSubifReply reply =
+ TranslateUtils.getReplyForWrite(createSubifReplyCompletionStage.toCompletableFuture(), id);
+
+ setInterfaceState(id, reply.swIfIndex, booleanToByte(subInterface.isEnabled()));
+ interfaceContext.addName(reply.swIfIndex,
+ getSubInterfaceName(superIfName, Math.toIntExact(subInterface.getIdentifier())),
+ writeContext.getMappingContext());
+ LOG.debug("Sub interface created successfully for: {}, subInterface: {}", superIfName, subInterface);
+ }
+
+ private CreateSubif getCreateSubifRequest(@Nonnull final SubInterface subInterface, final int swIfIndex) {
+ // TODO add validation
+ CreateSubif request = new CreateSubif();
+ request.subId = Math.toIntExact(subInterface.getIdentifier().intValue());
+ request.swIfIndex = swIfIndex;
+
+ final int numberOfTags = getNumberOfTags(subInterface);
+ switch (numberOfTags) {
+ case 0:
+ request.noTags = 1;
+ break;
+ case 1:
+ request.oneTag = 1;
+ break;
+ case 2:
+ request.twoTags = 1;
+ break;
+ }
+ request.dot1Ad = booleanToByte(_802dot1ad.class == subInterface.getVlanType());
+
+ final MatchType matchType = subInterface.getMatch().getMatchType(); // todo match should be mandatory
+ request.exactMatch =
+ booleanToByte(matchType instanceof VlanTagged && ((VlanTagged) matchType).isMatchExactTags());
+ request.defaultSub = booleanToByte(matchType instanceof Default);
+
+ if (numberOfTags > 0) {
+ for (final Tag tag : subInterface.getTags().getTag()) {
+ if (tag.getIndex() == 0) {
+ setOuterTag(request, tag);
+ } else if (tag.getIndex() == 1) {
+ setInnerTag(request, tag);
+ }
+ }
+ }
+ return request;
+ }
+
+ private void setOuterTag(final CreateSubif request, final Tag outerTag) {
+ checkState(SVlan.class == outerTag.getDot1qTag().getTagType(), "Service Tag expected at index 0");
+ final Dot1qTag.VlanId vlanId = outerTag.getDot1qTag().getVlanId();
+
+ request.outerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId());
+ request.outerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration()));
+ }
+
+ private void setInnerTag(final CreateSubif request, final Tag innerTag) {
+ checkState(CVlan.class == innerTag.getDot1qTag().getTagType(), "Customer Tag expected at index 1");
+ final Dot1qTag.VlanId vlanId = innerTag.getDot1qTag().getVlanId();
+
+ request.innerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId());
+ request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration()));
+ }
+
+ private static int getNumberOfTags(@Nonnull final SubInterface subInterface) {
+ final Tags tags = subInterface.getTags();
+ if (tags == null) {
+ return 0;
+ }
+ final List<Tag> tagList = tags.getTag();
+ if (tagList == null) {
+ return 0;
+ }
+ return tagList.size();
+ }
+
+ private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) {
+ if (dot1qVlanId == null) {
+ return 0; // tell VPP that optional argument is missing
+ } else {
+ return dot1qVlanId.getValue().shortValue();
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataBefore, @Nonnull final SubInterface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ if (Objects.equals(dataBefore.isEnabled(), dataAfter.isEnabled())) {
+ LOG.debug("No state update will be performed. Ignoring config");
+ return; // TODO shouldn't we throw exception here (if there will be dedicated L2 customizer)?
+ }
+ final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(dataAfter.getIdentifier()));
+ try {
+ setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()),
+ booleanToByte(dataAfter.isEnabled()));
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to update interface state for: interface if={}, enabled: {}",
+ subIfaceName, booleanToByte(dataAfter.isEnabled()));
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ private void setInterfaceState(final InstanceIdentifier<SubInterface> id, final int swIfIndex, final byte enabled)
+ throws VppBaseCallException, WriteTimeoutException {
+ final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags();
+ swInterfaceSetFlags.swIfIndex = swIfIndex;
+ swInterfaceSetFlags.adminUpDown = enabled;
+
+ final CompletionStage<SwInterfaceSetFlagsReply> swInterfaceSetFlagsReplyFuture =
+ getFutureJVpp().swInterfaceSetFlags(swInterfaceSetFlags);
+
+ LOG.debug("Updating interface state for interface if={}, enabled: {}", swIfIndex, enabled);
+
+ SwInterfaceSetFlagsReply reply =
+ TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id);
+ LOG.debug("Interface state updated successfully for interface index: {}, enabled: {}, ctxId: {}",
+ swIfIndex, enabled, reply.context);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.DeleteFailedException {
+ throw new UnsupportedOperationException("Sub interface delete is not supported");
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java
new file mode 100644
index 000000000..b420e73e3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java
@@ -0,0 +1,100 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for writing vlan sub interface l2 configuration
+ */
+public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements WriterCustomizer<L2> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class);
+ private final NamingContext interfaceContext;
+ private final InterconnectionWriteUtils icWriterUtils;
+
+ public SubInterfaceL2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext,
+ final NamingContext bridgeDomainContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ this.icWriterUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext);
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<L2> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ // TODO handle update properly (if possible)
+ setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ deleteL2(id, subInterfaceIndex, subInterfaceName, dataBefore, writeContext);
+ }
+
+ private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Setting L2 for sub-interface: {}", ifcName);
+ icWriterUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext);
+ }
+
+ private void deleteL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2Before,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting L2 for sub-interface: {}", ifcName);
+ icWriterUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java
new file mode 100644
index 000000000..b90e2c304
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java
@@ -0,0 +1,197 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.TapConnect;
+import org.openvpp.jvpp.dto.TapConnectReply;
+import org.openvpp.jvpp.dto.TapDelete;
+import org.openvpp.jvpp.dto.TapDeleteReply;
+import org.openvpp.jvpp.dto.TapModify;
+import org.openvpp.jvpp.dto.TapModifyReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public TapCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createTap(id, ifcName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataBefore,
+ @Nonnull final Tap dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+
+ try {
+ modifyTap(id, ifcName, index, dataAfter);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+
+ try {
+ deleteTap(id, ifcName, index, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete tap interface: {}, tap: {}", ifcName, dataBefore.getTapName(), e);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void createTap(final InstanceIdentifier<Tap> id, final String swIfName, final Tap tap,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap);
+ final CompletionStage<TapConnectReply> tapConnectFuture =
+ getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance()));
+ final TapConnectReply reply =
+ TranslateUtils.getReplyForWrite(tapConnectFuture.toCompletableFuture(), id);
+ LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private void modifyTap(final InstanceIdentifier<Tap> id, final String swIfName, final int index, final Tap tap)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tap);
+ final CompletionStage<TapModifyReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().tapModify(getTapModifyRequest(tap.getTapName(), index, tap.getMac(), tap.getDeviceInstance()));
+ TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tap);
+ }
+
+ private void deleteTap(final InstanceIdentifier<Tap> id, final String swIfName, final int index,
+ final Tap dataBefore,
+ final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore);
+ final CompletionStage<TapDeleteReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().tapDelete(getTapDeleteRequest(index));
+ TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore);
+ // Remove deleted interface from interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private TapConnect getTapConnectRequest(final String tapName, final PhysAddress mac, final Long deviceInstance) {
+ final TapConnect tapConnect = new TapConnect();
+ tapConnect.tapName = tapName.getBytes();
+
+ if(mac == null) {
+ tapConnect.useRandomMac = 1;
+ tapConnect.macAddress = new byte[6];
+ } else {
+ tapConnect.useRandomMac = 0;
+ tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue());
+ }
+
+ if(deviceInstance == null) {
+ tapConnect.renumber = 0;
+ } else {
+ tapConnect.renumber = 1;
+ tapConnect.customDevInstance = Math.toIntExact(deviceInstance);
+ }
+
+ return tapConnect;
+ }
+
+ private TapModify getTapModifyRequest(final String tapName, final int swIndex, final PhysAddress mac, final Long deviceInstance) {
+ final TapModify tapConnect = new TapModify();
+ tapConnect.tapName = tapName.getBytes();
+ tapConnect.swIfIndex = swIndex;
+
+ if(mac == null) {
+ tapConnect.useRandomMac = 1;
+ tapConnect.macAddress = new byte[6];
+ } else {
+ tapConnect.useRandomMac = 0;
+ tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue());
+ }
+
+ if(deviceInstance == null) {
+ tapConnect.renumber = 0;
+ } else {
+ tapConnect.renumber = 1;
+ tapConnect.customDevInstance = Math.toIntExact(deviceInstance);
+ }
+
+ return tapConnect;
+ }
+
+ private TapDelete getTapDeleteRequest(final int swIndex) {
+ final TapDelete tapConnect = new TapDelete();
+ tapConnect.swIfIndex = swIndex;
+ return tapConnect;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java
new file mode 100644
index 000000000..6f30b41c5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java
@@ -0,0 +1,167 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.rev150105.VhostUserRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.CreateVhostUserIf;
+import org.openvpp.jvpp.dto.CreateVhostUserIfReply;
+import org.openvpp.jvpp.dto.DeleteVhostUserIf;
+import org.openvpp.jvpp.dto.DeleteVhostUserIfReply;
+import org.openvpp.jvpp.dto.ModifyVhostUserIf;
+import org.openvpp.jvpp.dto.ModifyVhostUserIfReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for passing vhost user interface CRD operations to VPP
+ */
+public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUser> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VhostUserCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createVhostUserIf(id, swIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
+ LOG.debug("Failed to create vhost user interface: {}, vhostUser: {}", swIfName, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ private void createVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUser, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
+
+ final CompletionStage<CreateVhostUserIfReply> createVhostUserIfReplyCompletionStage =
+ getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser));
+ final CreateVhostUserIfReply reply =
+ TranslateUtils.getReplyForWrite(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private CreateVhostUserIf getCreateVhostUserIfRequest(final VhostUser vhostUser) {
+ CreateVhostUserIf request = new CreateVhostUserIf();
+ request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole()));
+ request.sockFilename = vhostUser.getSocket().getBytes();
+ request.renumber = 0; // TODO
+ request.customDevInstance = 0; // TODO
+ request.useCustomMac = 0;
+ request.macAddress = new byte[]{};
+ return request;
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataBefore, @Nonnull final VhostUser dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ modifyVhostUserIf(id, swIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to update vhost user interface: {}, vhostUser: {}", swIfName, dataAfter);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ private void modifyVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUser, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
+ final CompletionStage<ModifyVhostUserIfReply> modifyVhostUserIfReplyCompletionStage =
+ getFutureJVpp()
+ .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
+
+ TranslateUtils.getReplyForWrite(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUser);
+ }
+
+ private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) {
+ ModifyVhostUserIf request = new ModifyVhostUserIf();
+ request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole()));
+ request.sockFilename = vhostUser.getSocket().getBytes();
+ request.renumber = 0; // TODO
+ request.customDevInstance = 0; // TODO
+ request.swIfIndex = swIfIndex;
+ return request;
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ deleteVhostUserIf(id, swIfName, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete vhost user interface: {}, vhostUser: {}", swIfName, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void deleteVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUser, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
+ final CompletionStage<DeleteVhostUserIfReply> deleteVhostUserIfReplyCompletionStage =
+ getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
+
+ TranslateUtils.getReplyForWrite(deleteVhostUserIfReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private DeleteVhostUserIf getDeleteVhostUserIfRequest(final int swIfIndex) {
+ DeleteVhostUserIf request = new DeleteVhostUserIf();
+ request.swIfIndex = swIfIndex;
+ return request;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java
new file mode 100644
index 000000000..5b424449d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java
@@ -0,0 +1,177 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.rev150105.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.VxlanAddDelTunnel;
+import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// TODO extract common code from all Interface type specific writer customizers into a superclass
+public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VxlanCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return VxlanTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createVxlanTunnel(id, swIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
+ LOG.debug("Failed to set vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataBefore,
+ @Nonnull final Vxlan dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Vxlan tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ deleteVxlanTunnel(id, swIfName, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.debug("Failed to delete vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void createVxlanTunnel(final InstanceIdentifier<Vxlan> id, final String swIfName, final Vxlan vxlan,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
+
+ int encapVrfId = vxlan.getEncapVrfId().intValue();
+ int vni = vxlan.getVni().getValue().intValue();
+
+ LOG.debug("Setting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan);
+ final CompletionStage<VxlanAddDelTunnelReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6));
+
+ final VxlanAddDelTunnelReply reply =
+ TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan);
+ if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel)
+ // This may cause inconsistencies in mapping context when configuring tunnels like this:
+ // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6
+ // will get into mapping context) 4. Add tunnel (this will add another mapping with the same
+ // reserved ID and context is invalid)
+ // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing
+ // new name for that ID
+ final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceContext.removeName(formerName, writeContext.getMappingContext());
+ }
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final Vxlan vxlan) {
+ if (vxlan.getSrc().getIpv4Address() == null) {
+ checkArgument(vxlan.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(),
+ vxlan.getDst());
+ return true;
+ } else {
+ checkArgument(vxlan.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(),
+ vxlan.getDst());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteVxlanTunnel(final InstanceIdentifier<Vxlan> id, final String swIfName, final Vxlan vxlan,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
+
+ int encapVrfId = vxlan.getEncapVrfId().intValue();
+ int vni = vxlan.getVni().getValue().intValue();
+
+ LOG.debug("Deleting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan);
+ final CompletionStage<VxlanAddDelTunnelReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6));
+
+ TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr,
+ final int encapVrfId,
+ final int decapNextIndex, final int vni, final byte isIpv6) {
+ final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
+ vxlanAddDelTunnel.isAdd = isAdd;
+ vxlanAddDelTunnel.srcAddress = srcAddr;
+ vxlanAddDelTunnel.dstAddress = dstAddr;
+ vxlanAddDelTunnel.encapVrfId = encapVrfId;
+ vxlanAddDelTunnel.vni = vni;
+ vxlanAddDelTunnel.decapNextIndex = decapNextIndex;
+ vxlanAddDelTunnel.isIpv6 = isIpv6;
+ return vxlanAddDelTunnel;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java
new file mode 100644
index 000000000..95ed55570
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java
@@ -0,0 +1,176 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.rev150105.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel;
+import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VxlanGpeCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return VxlanGpeTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
+ LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataBefore,
+ @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("VxlanGpe tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void createVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
+ final VxlanGpe vxlanGpe, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0);
+ final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
+ final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
+
+ int vni = vxlanGpe.getVni().getValue().intValue();
+ byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
+ int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
+ int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
+
+ LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
+ final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(),
+ Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
+
+ final VxlanGpeAddDelTunnelReply reply =
+ TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe);
+ if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceContext.removeName(formerName, writeContext.getMappingContext());
+ }
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final VxlanGpe VxlanGpe) {
+ if (VxlanGpe.getLocal().getIpv4Address() == null) {
+ checkArgument(VxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(),
+ VxlanGpe.getRemote());
+ return true;
+ } else {
+ checkArgument(VxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(),
+ VxlanGpe.getRemote());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
+ final VxlanGpe VxlanGpe, final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(VxlanGpe) ? 1 : 0);
+ final InetAddress local = InetAddresses.forString(getAddressString(VxlanGpe.getLocal()));
+ final InetAddress remote = InetAddresses.forString(getAddressString(VxlanGpe.getRemote()));
+
+ int vni = VxlanGpe.getVni().getValue().intValue();
+ byte protocol = (byte) VxlanGpe.getNextProtocol().getIntValue();
+ int encapVrfId = VxlanGpe.getEncapVrfId().intValue();
+ int decapVrfId = VxlanGpe.getDecapVrfId().intValue();
+
+ LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, VxlanGpe);
+ final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(),
+ remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
+
+ TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("VxlanGpe tunnel deleted successfully for: {}, VxlanGpe: {}", swIfName, VxlanGpe);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local, final byte[] remote,
+ final int vni, final byte protocol, final int encapVrfId, final int decapVrfId,
+ final byte isIpv6) {
+ final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel();
+ VxlanGpeAddDelTunnel.isAdd = isAdd;
+ VxlanGpeAddDelTunnel.local = local;
+ VxlanGpeAddDelTunnel.remote = remote;
+ VxlanGpeAddDelTunnel.vni = vni;
+ VxlanGpeAddDelTunnel.protocol = protocol;
+ VxlanGpeAddDelTunnel.encapVrfId = encapVrfId;
+ VxlanGpeAddDelTunnel.decapVrfId = decapVrfId;
+ VxlanGpeAddDelTunnel.isIpv6 = isIpv6;
+ return VxlanGpeAddDelTunnel;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java
new file mode 100644
index 000000000..74d546d65
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java
@@ -0,0 +1,135 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for writing {@link Address}
+ */
+public class Ipv4AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public Ipv4AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
+ throws WriteFailedException {
+ setAddress(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
+ WriteContext writeContext) throws WriteFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Operation not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
+ throws WriteFailedException {
+ setAddress(false, id, dataBefore, writeContext);
+ }
+
+ private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
+ final WriteContext writeContext) throws WriteFailedException {
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
+
+ Subnet subnet = address.getSubnet();
+
+ if (subnet instanceof PrefixLength) {
+ setPrefixLengthSubnet(add, id, interfaceName, interfaceIndex, address, (PrefixLength) subnet);
+ } else if (subnet instanceof Netmask) {
+ setNetmaskSubnet(add, id, interfaceName, interfaceIndex, address, (Netmask) subnet);
+ } else {
+ // FIXME how does choice extensibility work
+ // FIXME it is not even possible to create a dedicated
+ // customizer for Interconnection, since it's not a DataObject
+ // FIXME we might need a choice customizer
+ // THis choice is already from augment, so its probably not
+ // possible to augment augmented choice
+ LOG.error("Unable to handle subnet of type {}", subnet.getClass());
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
+ }
+ }
+
+ private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+ @Nonnull final String interfaceName, final int interfaceIndex,
+ @Nonnull final Address address, @Nonnull final Netmask subnet)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Setting Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}",
+ interfaceName, interfaceIndex, subnet, address);
+
+ final DottedQuad netmask = subnet.getNetmask();
+ checkNotNull(netmask, "netmask value should not be null");
+
+ final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue());
+ Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), subnetLength);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}",
+ interfaceName, interfaceIndex, subnet, address);
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+ }
+ }
+
+ private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+ @Nonnull final String interfaceName, final int interfaceIndex,
+ @Nonnull final Address address, @Nonnull final PrefixLength subnet)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Setting Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}",
+ interfaceName, interfaceIndex, subnet, address);
+
+ Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(),
+ subnet.getPrefixLength().byteValue());
+
+ LOG.debug("Subnet(prefix-length) set successfully for interface: {}(id={}). Subnet: {}, address: {}",
+ interfaceName, interfaceIndex, subnet, address);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}",
+ interfaceName, interfaceIndex, subnet, address);
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java
new file mode 100644
index 000000000..c956794ac
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java
@@ -0,0 +1,78 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv4Customizer extends FutureJVppCustomizer implements WriterCustomizer<Ipv4> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
+ private final NamingContext interfaceContext;
+
+ public Ipv4Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ setIpv4(id, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ // TODO handle update in a better way
+ setIpv4(id, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) {
+ // TODO implement delete
+ }
+
+ private void setIpv4(final InstanceIdentifier<Ipv4> id, final String name, final Ipv4 ipv4,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
+
+ LOG.warn("Ignoring Ipv4 leaf nodes (create/update is not supported)");
+ // TODO add support for enabled leaf
+ // TODO add support for forwarding leaf
+ // TODO add support for mtu leaf
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java
new file mode 100644
index 000000000..edd49f2f5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java
@@ -0,0 +1,133 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+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.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.IpNeighborAddDel;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Customizer for writing {@link Neighbor} for {@link Ipv4}
+ */
+public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Neighbor, NeighborKey> {
+
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class);
+ final NamingContext interfaceContext;
+
+ public Ipv4NeighbourCustomizer(final FutureJVpp futureJvpp, final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataAfter,
+ @Nonnull WriteContext writeContext)
+ throws WriteFailedException {
+
+ checkNotNull(dataAfter, "Cannot write null neighbour");
+ checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found");
+
+ LOG.debug("Processing request for Neigbour write");
+ String interfaceName = id.firstKeyOf(Interface.class).getName();
+ MappingContext mappingContext = writeContext.getMappingContext();
+
+ checkState(interfaceContext.containsIndex(interfaceName, mappingContext),
+ "Mapping does not contains mapping for provider interface name ".concat(interfaceName));
+
+ LOG.debug("Parent interface index found");
+ try {
+ addDelNeighbourAndReply(id, true,
+ interfaceContext.getIndex(interfaceName, mappingContext), dataAfter);
+ LOG.info("Neighbour successfully written");
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataBefore,
+ @Nonnull Neighbor dataAfter,
+ @Nonnull WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Operation not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataBefore,
+ @Nonnull WriteContext writeContext)
+ throws WriteFailedException {
+
+ checkNotNull(dataBefore, "Cannot delete null neighbour");
+ checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found");
+
+ LOG.debug("Processing request for Neigbour delete");
+ String interfaceName = id.firstKeyOf(Interface.class).getName();
+ MappingContext mappingContext = writeContext.getMappingContext();
+
+ checkState(interfaceContext.containsIndex(interfaceName, mappingContext),
+ "Mapping does not contains mapping for provider interface name %s", interfaceName);
+
+ LOG.debug("Parent interface[{}] index found", interfaceName);
+ try {
+ addDelNeighbourAndReply(id, false,
+ interfaceContext.getIndex(interfaceName, mappingContext), dataBefore);
+ LOG.info("Neighbour {} successfully deleted", id);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void addDelNeighbourAndReply(InstanceIdentifier<Neighbor> id, boolean add, int parentInterfaceIndex,
+ Neighbor data)
+ throws VppBaseCallException, WriteTimeoutException {
+
+ IpNeighborAddDel request = new IpNeighborAddDel();
+
+ request.isAdd = TranslateUtils.booleanToByte(add);
+ request.isIpv6 = 0;
+ request.isStatic = 1;
+ request.dstAddress = TranslateUtils.ipv4AddressNoZoneToArray(data.getIp());
+ request.macAddress = TranslateUtils.parseMac(data.getLinkLayerAddress().getValue());
+ request.swIfIndex = parentInterfaceIndex;
+
+ //TODO if it is necessary for future use ,make adjustments to be able to set vrfid
+ //request.vrfId
+ TranslateUtils.getReplyForWrite(getFutureJVpp().ipNeighborAddDel(request).toCompletableFuture(), id);
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java
new file mode 100644
index 000000000..3aeb2dfaf
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java
@@ -0,0 +1,111 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
+import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+/**
+ * Utility class providing Ipv4 CUD support.
+ */
+// TODO replace with interface with default methods or abstract class
+final class Ipv4WriteUtils {
+
+ private static final int DOTTED_QUAD_MASK_LENGTH = 4;
+ private static final int IPV4_ADDRESS_PART_BITS_COUNT = 8;
+ private static final int NETMASK_PART_LIMIT = 256; // 2 power to 8
+
+ private Ipv4WriteUtils() {
+ throw new UnsupportedOperationException("This utility class cannot be instantiated");
+ }
+
+ static void addDelAddress(@Nonnull final FutureJVpp futureJvpp, final boolean add, final InstanceIdentifier<?> id,
+ @Nonnegative final int ifaceId,
+ @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength)
+ throws VppBaseCallException, WriteTimeoutException {
+ checkArgument(prefixLength > 0, "Invalid prefix length");
+ checkNotNull(address, "address should not be null");
+
+ final byte[] addressBytes = TranslateUtils.ipv4AddressNoZoneToArray(address);
+
+ final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+ futureJvpp.swInterfaceAddDelAddress(
+ getSwInterfaceAddDelAddressRequest(ifaceId, TranslateUtils.booleanToByte(add) /* isAdd */,
+ (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));
+
+ TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ static SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
+ final byte ipv6, final byte deleteAll,
+ final byte length, final byte[] addr) {
+ final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
+ swInterfaceAddDelAddress.swIfIndex = swIfc;
+ swInterfaceAddDelAddress.isAdd = isAdd;
+ swInterfaceAddDelAddress.isIpv6 = ipv6;
+ swInterfaceAddDelAddress.delAll = deleteAll;
+ swInterfaceAddDelAddress.address = addr;
+ swInterfaceAddDelAddress.addressLength = length;
+ return swInterfaceAddDelAddress;
+ }
+
+ /**
+ * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
+ * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
+ * leading ones, IllegalArgumentExpression is thrown
+ *
+ * @param mask the subnet mask in dot notation 255.255.255.255
+ * @return the prefix length as number of bits
+ */
+ static byte getSubnetMaskLength(final String mask) {
+ String[] maskParts = mask.split("\\.");
+
+ checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH,
+ "Network mask %s is not in Quad Dotted Decimal notation!", mask);
+
+ long maskAsNumber = 0;
+ for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) {
+ maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
+ int value = Integer.parseInt(maskParts[i]);
+ checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
+ checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
+ maskAsNumber += value;
+ }
+
+ String bits = Long.toBinaryString(maskAsNumber);
+ checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH,
+ "Incorrect network mask %s", mask);
+ final int leadingOnes = bits.indexOf('0');
+ checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
+ checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
+ "Non-contiguous network mask %s is not allowed!", mask);
+ return (byte) leadingOnes;
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java
new file mode 100644
index 000000000..1e3a3e747
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv6Customizer extends FutureJVppCustomizer implements WriterCustomizer<Ipv6> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv6Customizer.class);
+
+ public Ipv6Customizer(final FutureJVpp vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataAfter, @Nonnull final WriteContext writeContext) {
+ // TODO
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataBefore, @Nonnull final Ipv6 dataAfter,
+ @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataBefore, @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration delete {}", id);
+ // TODO
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644
index 000000000..700139704
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java
@@ -0,0 +1,150 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Write customizer for sub-interface {@link Address}
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Address, AddressKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interface context should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
+ throws WriteFailedException {
+ setAddress(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
+ WriteContext writeContext) throws WriteFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Operation not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
+ throws WriteFailedException {
+ setAddress(false, id, dataBefore, writeContext);
+ }
+
+ private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
+ final WriteContext writeContext) throws WriteFailedException {
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+
+ Subnet subnet = address.getSubnet();
+
+ if (subnet instanceof PrefixLength) {
+ setPrefixLengthSubnet(add, id, interfaceName, subInterfaceIndex, address, (PrefixLength) subnet);
+ } else if (subnet instanceof Netmask) {
+ setNetmaskSubnet(add, id, interfaceName, subInterfaceIndex, address, (Netmask) subnet);
+ } else {
+ // FIXME how does choice extensibility work
+ // FIXME it is not even possible to create a dedicated
+ // customizer for Interconnection, since it's not a DataObject
+ // FIXME we might need a choice customizer
+ // THis choice is already from augment, so its probably not
+ // possible to augment augmented choice
+ LOG.error("Unable to handle subnet of type {}", subnet.getClass());
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
+ }
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+ @Nonnull final String subInterfaceName, final int subInterfaceIndex,
+ @Nonnull final Address address, @Nonnull final Netmask subnet)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Setting Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+ subInterfaceName, subInterfaceIndex, subnet, address);
+
+ final DottedQuad netmask = subnet.getNetmask();
+ checkNotNull(netmask, "netmask value should not be null");
+
+ final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue());
+ Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), subnetLength);
+
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+ subInterfaceName, subInterfaceIndex, subnet, address);
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+ }
+ }
+
+ private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+ @Nonnull final String subInterfaceName, final int subInterfaceIndex,
+ @Nonnull final Address address, @Nonnull final PrefixLength subnet)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Setting Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+ subInterfaceName, subInterfaceIndex, subnet, address);
+
+ Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(),
+ subnet.getPrefixLength().byteValue());
+
+ LOG.debug("Subnet(prefix-length) set successfully for sub-interface: {}(id={}). Subnet: {}, address: {}",
+ subInterfaceName, subInterfaceIndex, subnet, address);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to set Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+ subInterfaceName, subInterfaceIndex, subnet, address);
+ throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java
new file mode 100644
index 000000000..1b76a0382
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java
@@ -0,0 +1,96 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyTableByInterface;
+import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ACLs enabled on given interface.
+ */
+public class AclCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Acl, AclBuilder>, AclReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final NamingContext classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Acl readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setAcl(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public AclBuilder getBuilder(@Nonnull final InstanceIdentifier<Acl> id) {
+ return new AclBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final AclBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface ACL: {}", id);
+ final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class);
+ checkArgument(interfaceKey != null, "No parent interface key found");
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(interfaceKey.getName(), ctx.getMappingContext());
+ try {
+ final ClassifyTableByInterfaceReply reply = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java
new file mode 100644
index 000000000..c64c096a8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java
@@ -0,0 +1,60 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder;
+
+interface AclReader {
+
+ @Nonnull
+ default L2Acl readL2Acl(final int l2TableId, @Nonnull final NamingContext classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (l2TableId == ~0) {
+ return null;
+ }
+ return new L2AclBuilder()
+ .setClassifyTable(classifyTableContext.getName(l2TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final NamingContext classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip4TableId == ~0) {
+ return null;
+ }
+ return new Ip4AclBuilder()
+ .setClassifyTable(classifyTableContext.getName(ip4TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final NamingContext classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip6TableId == ~0) {
+ return null;
+ }
+ return new Ip6AclBuilder()
+ .setClassifyTable(classifyTableContext.getName(ip6TableId, mappingContext)).build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java
new file mode 100644
index 000000000..30d3f6482
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java
@@ -0,0 +1,87 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EthernetCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Ethernet, EthernetBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public EthernetCustomizer(@Nonnull final FutureJVpp jvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+ @Nonnull final Ethernet readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setEthernet(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public EthernetBuilder getBuilder(@Nonnull InstanceIdentifier<Ethernet> id) {
+ return new EthernetBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final EthernetBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, key.getName(),
+ interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache());
+
+ if(iface.linkMtu != 0) {
+ builder.setMtu((int) iface.linkMtu);
+ }
+
+ switch (iface.linkDuplex) {
+ case 1:
+ builder.setDuplex(Ethernet.Duplex.Half);
+ break;
+ case 2:
+ builder.setDuplex(Ethernet.Duplex.Full);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java
new file mode 100644
index 000000000..c01d27a2d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java
@@ -0,0 +1,131 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.BridgeDomainDetails;
+import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
+import org.openvpp.jvpp.dto.BridgeDomainDump;
+import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Interconnection read support.
+ */
+// FIXME this should be customizer, but it is not possible because Interconnection is not a DataObject
+final class InterconnectionReadUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterconnectionReadUtils.class);
+
+ private final FutureJVpp futureJvpp;
+ private final NamingContext interfaceContext;
+ private final NamingContext bridgeDomainContext;
+
+ InterconnectionReadUtils(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null");
+ this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null");
+ this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null");
+ }
+
+ @Nullable
+ Interconnection readInterconnection(@Nonnull final InstanceIdentifier<?> id, @Nonnull final String ifaceName,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final int ifaceId = interfaceContext.getIndex(ifaceName, ctx.getMappingContext());
+
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(futureJvpp, id, ifaceName,
+ ifaceId, ctx.getModificationCache());
+ LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface);
+
+ final BridgeDomainDetailsReplyDump dumpReply = getDumpReply(id);
+ final Optional<BridgeDomainSwIfDetails> bdForInterface = getBridgeDomainForInterface(ifaceId, dumpReply);
+ if (bdForInterface.isPresent()) {
+ final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get();
+ final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
+ bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext()));
+
+ // Set BVI if the bridgeDomainDetails.bviSwIfIndex == current sw if index
+ final Optional<BridgeDomainDetails> bridgeDomainForInterface =
+ getBridgeDomainForInterface(dumpReply, bdForInterface.get().bdId);
+ // Since we already found an interface assigned to a bridge domain, the details for BD must be present
+ checkState(bridgeDomainForInterface.isPresent());
+ if (bridgeDomainForInterface.get().bviSwIfIndex == ifaceId) {
+ bbBuilder.setBridgedVirtualInterface(true);
+ } else {
+ bbBuilder.setBridgedVirtualInterface(false);
+ }
+
+ if (bdSwIfDetails.shg != 0) {
+ bbBuilder.setSplitHorizonGroup((short) bdSwIfDetails.shg);
+ }
+ return bbBuilder.build();
+ }
+ // TODO is there a way to check if interconnection is XconnectBased?
+
+ return null;
+ }
+
+ private Optional<BridgeDomainSwIfDetails> getBridgeDomainForInterface(final int ifaceId,
+ final BridgeDomainDetailsReplyDump reply) {
+ if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) {
+ return Optional.empty();
+ }
+ // interface can be added to only one BD only
+ return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst();
+ }
+
+ private Optional<BridgeDomainDetails> getBridgeDomainForInterface(final BridgeDomainDetailsReplyDump reply,
+ int bdId) {
+ return reply.bridgeDomainDetails.stream().filter(a -> a.bdId == bdId).findFirst();
+ }
+
+ private BridgeDomainDetailsReplyDump getDumpReply(@Nonnull final InstanceIdentifier<?> id)
+ throws ReadFailedException {
+ try {
+ // We need to perform full bd dump, because there is no way
+ // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?)
+ // TODO cache dump result
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = -1;
+
+ final CompletableFuture<BridgeDomainDetailsReplyDump> bdCompletableFuture =
+ futureJvpp.bridgeDomainSwIfDump(request).toCompletableFuture();
+ return TranslateUtils.getReplyForRead(bdCompletableFuture, id);
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java
new file mode 100644
index 000000000..082b68559
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java
@@ -0,0 +1,178 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.InterfacesStateBuilder;
+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.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface.
+ */
+public class InterfaceCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<Interface, InterfaceKey, InterfaceBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class);
+ public static final String DUMPED_IFCS_CONTEXT_KEY =
+ InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds";
+
+ private final NamingContext interfaceContext;
+
+ public InterfaceCustomizer(@Nonnull final FutureJVpp jvpp, final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Nonnull
+ @Override
+ public InterfaceBuilder getBuilder(@Nonnull InstanceIdentifier<Interface> id) {
+ return new InterfaceBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Interface> id, @Nonnull InterfaceBuilder builder,
+ @Nonnull ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface: {}", id);
+ final String ifaceName = id.firstKeyOf(id.getTargetType()).getName();
+
+ // Pass cached details from getAllIds to getDetails to avoid additional dumps
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, ifaceName,
+ interfaceContext.getIndex(ifaceName, ctx.getMappingContext()), ctx.getModificationCache());
+ LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface);
+
+ if (!isRegularInterface(iface)) {
+ LOG.debug("Interface: {} is a sub-interface. Ignoring read request.", ifaceName);
+ return;
+ }
+
+ builder.setName(ifaceName);
+ builder.setType(InterfaceUtils.getInterfaceType(new String(iface.interfaceName).intern()));
+ builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex));
+ builder.setAdminStatus(1 == iface.adminUpDown
+ ? AdminStatus.Up
+ : AdminStatus.Down);
+ builder.setOperStatus(1 == iface.linkUpDown
+ ? OperStatus.Up
+ : OperStatus.Down);
+ if (0 != iface.linkSpeed) {
+ builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed));
+ }
+ if (iface.l2AddressLength == 6) {
+ builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address)));
+ }
+ LOG.trace("Base attributes read for interface: {} as: {}", ifaceName, builder);
+ }
+
+ @Nonnull
+ @SuppressWarnings("unchecked")
+ public static Map<Integer, SwInterfaceDetails> getCachedInterfaceDump(@Nonnull final ModificationCache ctx) {
+ return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null
+ ? new HashMap<>()
+ // allow customizers to update the cache
+ : (Map<Integer, SwInterfaceDetails>) ctx.get(DUMPED_IFCS_CONTEXT_KEY);
+ }
+
+ @Nonnull
+ @Override
+ public List<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ try {
+ final List<InterfaceKey> interfacesKeys;
+ LOG.trace("Dumping all interfaces to get all IDs");
+
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = "".getBytes();
+ request.nameFilterValid = 0;
+
+ final CompletableFuture<SwInterfaceDetailsReplyDump> swInterfaceDetailsReplyDumpCompletableFuture =
+ getFutureJVpp().swInterfaceDump(request).toCompletableFuture();
+ final SwInterfaceDetailsReplyDump ifaces =
+ TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id);
+
+ if (null == ifaces || null == ifaces.swInterfaceDetails) {
+ LOG.debug("No interfaces for :{} found in VPP", id);
+ return Collections.emptyList();
+ }
+
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
+
+ interfacesKeys = ifaces.swInterfaceDetails.stream()
+ .filter(elt -> elt != null)
+ .map((elt) -> {
+ // Store interface name from VPP in context if not yet present
+ if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) {
+ interfaceContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName),
+ context.getMappingContext());
+ }
+ LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
+ interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName,
+ elt.swIfIndex);
+
+ return elt;
+ })
+ .filter(InterfaceCustomizer::isRegularInterface) // filter out sub-interfaces
+ .map((elt) -> new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext())))
+ .collect(Collectors.toList());
+
+ LOG.debug("Interfaces found in VPP: {}", interfacesKeys);
+ return interfacesKeys;
+ } catch (VppBaseCallException e) {
+ LOG.warn("getAllIds for id :{} failed with exception ", id, e);
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ private static boolean isRegularInterface(final SwInterfaceDetails iface) {
+ return iface.subId == 0;
+ }
+
+ @Override
+ public void merge(@Nonnull final org.opendaylight.yangtools.concepts.Builder<? extends DataObject> builder,
+ @Nonnull final List<Interface> readData) {
+ ((InterfacesStateBuilder) builder).setInterface(readData);
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java
new file mode 100644
index 000000000..b7c1e518a
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java
@@ -0,0 +1,286 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.math.BigInteger;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletionStage;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.yang.types.rev130715.Gauge64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class InterfaceUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceUtils.class);
+
+ private static final Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO);
+ private static final Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000));
+ private static final Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000));
+ private static final Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000));
+ private static final Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000));
+ private static final Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000));
+ private static final Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000));
+
+ private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+ private static final int PHYSICAL_ADDRESS_LENGTH = 6;
+
+ private static final Collector<SwInterfaceDetails, ?, SwInterfaceDetails> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ private InterfaceUtils() {
+ throw new UnsupportedOperationException("This utility class cannot be instantiated");
+ }
+
+ /**
+ * Convert VPP's link speed bitmask to Yang type. 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G
+ *
+ * @param vppLinkSpeed Link speed in bitmask format from VPP.
+ * @return Converted value from VPP link speed
+ */
+ public static Gauge64 vppInterfaceSpeedToYang(byte vppLinkSpeed) {
+ switch (vppLinkSpeed) {
+ case 1:
+ return vppLinkSpeed1;
+ case 2:
+ return vppLinkSpeed2;
+ case 4:
+ return vppLinkSpeed4;
+ case 8:
+ return vppLinkSpeed8;
+ case 16:
+ return vppLinkSpeed16;
+ case 32:
+ return vppLinkSpeed32;
+ default:
+ return vppLinkSpeed0;
+ }
+ }
+
+ private static final void appendHexByte(final StringBuilder sb, final byte b) {
+ final int v = b & 0xFF;
+ sb.append(HEX_CHARS[v >>> 4]);
+ sb.append(HEX_CHARS[v & 15]);
+ }
+
+ // TODO rename and move to V3poUtils
+
+ /**
+ * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates <p> Replace later with
+ * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/
+ * java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfYangUtil.java
+ *
+ * @param vppPhysAddress byte array of bytes in big endian order, constructing the network IF physical address.
+ * @return String like "aa:bb:cc:dd:ee:ff"
+ * @throws NullPointerException if vppPhysAddress is null
+ * @throws IllegalArgumentException if vppPhysAddress.length < 6
+ */
+ public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) {
+ return vppPhysAddrToYang(vppPhysAddress, 0);
+ }
+
+ public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) {
+ Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes");
+ final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH;
+ checkArgument(endIndex <= vppPhysAddress.length,
+ "Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length,
+ startIndex, endIndex);
+ return printHexBinary(vppPhysAddress, startIndex, endIndex);
+ }
+
+ public static String printHexBinary(@Nonnull final byte[] bytes) {
+ Objects.requireNonNull(bytes, "bytes array should not be null");
+ return printHexBinary(bytes, 0, bytes.length);
+ }
+
+ private static String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
+ StringBuilder str = new StringBuilder();
+
+ appendHexByte(str, bytes[startIndex]);
+ for (int i = startIndex + 1; i < endIndex; i++) {
+ str.append(":");
+ appendHexByte(str, bytes[i]);
+ }
+
+ return str.toString();
+ }
+
+ /**
+ * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from
+ * VPP's interface index to YANG's interface index.
+ *
+ * @param vppIfIndex the sw interface index VPP reported.
+ * @return VPP's interface index incremented by one
+ */
+ public static int vppIfIndexToYang(int vppIfIndex) {
+ return vppIfIndex + 1;
+ }
+
+ /**
+ * This function does the opposite of what {@link #vppIfIndexToYang(int)} does.
+ *
+ * @param yangIfIndex if-index from ietf-interfaces.
+ * @return VPP's representation of the if-index
+ */
+ public static int yangIfIndexToVpp(int yangIfIndex) {
+ checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
+ return yangIfIndex - 1;
+ }
+
+
+ /**
+ * Queries VPP for interface description given interface key.
+ *
+ * @param futureJvpp VPP Java Future API
+ * @param id InstanceIdentifier, which is passed in ReadFailedException
+ * @param name interface name
+ * @param index VPP index of the interface
+ * @param ctx per-tx scope context containing cached dump with all the interfaces. If the cache is not
+ * available or outdated, another dump will be performed.
+ * @return SwInterfaceDetails DTO or null if interface was not found
+ * @throws IllegalArgumentException If interface cannot be found
+ * @throws ReadFailedException If read operation had failed
+ */
+ @Nonnull
+ public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final String name, final int index,
+ @Nonnull final ModificationCache ctx)
+ throws ReadFailedException {
+ requireNonNull(futureJvpp, "futureJvpp should not be null");
+ requireNonNull(name, "name should not be null");
+ requireNonNull(ctx, "ctx should not be null");
+
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = name.getBytes();
+ request.nameFilterValid = 1;
+
+ final Map<Integer, SwInterfaceDetails> allInterfaces = InterfaceCustomizer.getCachedInterfaceDump(ctx);
+
+ // Returned cached if available
+ if (allInterfaces.containsKey(index)) {
+ return allInterfaces.get(index);
+ }
+
+ SwInterfaceDetailsReplyDump ifaces;
+ try {
+ CompletionStage<SwInterfaceDetailsReplyDump> requestFuture = futureJvpp.swInterfaceDump(request);
+ ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id);
+ if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) {
+ request.nameFilterValid = 0;
+
+ LOG.warn("VPP returned null instead of interface by key {} and its not cached", name);
+ LOG.warn("Iterating through all the interfaces to find interface: {}", name);
+
+ // Or else just perform full dump and do inefficient filtering
+ requestFuture = futureJvpp.swInterfaceDump(request);
+ ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id);
+
+ // Update the cache
+ allInterfaces.clear();
+ allInterfaces
+ .putAll(ifaces.swInterfaceDetails.stream().collect(Collectors.toMap(d -> d.swIfIndex, d -> d)));
+
+ if (allInterfaces.containsKey(index)) {
+ return allInterfaces.get(index);
+ }
+ throw new IllegalArgumentException("Unable to find interface " + name);
+ }
+ } catch (VppBaseCallException e) {
+ LOG.warn("getVppInterfaceDetails for id :{} and name :{} failed with exception :", id, name, e);
+ throw new ReadFailedException(id, e);
+ }
+
+ // SwInterfaceDump's name filter does prefix match, so we need additional filtering:
+ final SwInterfaceDetails iface =
+ ifaces.swInterfaceDetails.stream().filter(d -> d.swIfIndex == index).collect(SINGLE_ITEM_COLLECTOR);
+ allInterfaces.put(index, iface); // update the cache
+ return iface;
+ }
+
+ /**
+ * Determine interface type based on its VPP name (relying on VPP's interface naming conventions)
+ *
+ * @param interfaceName VPP generated interface name
+ * @return Interface type
+ */
+ @Nonnull
+ public static Class<? extends InterfaceType> getInterfaceType(@Nonnull final String interfaceName) {
+ if (interfaceName.startsWith("tap")) {
+ return Tap.class;
+ }
+
+ if (interfaceName.startsWith("vxlan_gpe")) {
+ return VxlanGpeTunnel.class;
+ }
+
+ if (interfaceName.startsWith("vxlan")) {
+ return VxlanTunnel.class;
+ }
+
+ if (interfaceName.startsWith("VirtualEthernet")) {
+ return VhostUser.class;
+ }
+
+ return EthernetCsmacd.class;
+ }
+
+ /**
+ * Check interface type. Uses interface details from VPP to determine. Uses {@link
+ * #getVppInterfaceDetails(FutureJVpp, InstanceIdentifier, String, int, ModificationCache)} internally so tries to
+ * utilize cache before asking VPP.
+ */
+ static boolean isInterfaceOfType(@Nonnull final FutureJVpp jvpp,
+ @Nonnull final ModificationCache cache,
+ @Nonnull final InstanceIdentifier<?> id,
+ final int index,
+ @Nonnull final Class<? extends InterfaceType> ifcType) throws ReadFailedException {
+ final String name = id.firstKeyOf(Interface.class).getName();
+ final SwInterfaceDetails vppInterfaceDetails =
+ getVppInterfaceDetails(jvpp, id, name, index, cache);
+
+ return isInterfaceOfType(ifcType, vppInterfaceDetails);
+ }
+
+ static boolean isInterfaceOfType(final Class<? extends InterfaceType> ifcType,
+ final SwInterfaceDetails cachedDetails) {
+ return ifcType.equals(getInterfaceType(TranslateUtils.toString(cachedDetails.interfaceName)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java
new file mode 100644
index 000000000..4e18c9804
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java
@@ -0,0 +1,75 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+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.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+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.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2
+ */
+public class L2Customizer extends FutureJVppCustomizer implements ReaderCustomizer<L2, L2Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
+ private final InterconnectionReadUtils icReadUtils;
+
+ public L2Customizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ super(futureJvpp);
+ this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
+ return new L2Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ LOG.debug("Reading attributes for L2: {}", id);
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final String ifaceName = key.getName();
+ builder.setInterconnection(icReadUtils.readInterconnection(id, ifaceName, ctx));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java
new file mode 100644
index 000000000..87bd1b25b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java
@@ -0,0 +1,145 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTagBuilder;
+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.vpp.vlan.rev150527._802dot1ad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading vlan tag-rewrite configuration state form the VPP.
+ */
+public class RewriteCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Rewrite, RewriteBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+ @Nonnull final Rewrite readValue) {
+ ((L2Builder) parentBuilder).setRewrite(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public RewriteBuilder getBuilder(@Nonnull final InstanceIdentifier<Rewrite> id) {
+ return new RewriteBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final RewriteBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ LOG.debug("Reading attributes for sub interface: {}", subInterfaceName);
+
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName,
+ interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache());
+ LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface));
+
+ checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface");
+
+ final TagRewriteOperation operation = TagRewriteOperation.get(iface.vtrOp);
+ if (TagRewriteOperation.disabled == operation) {
+ LOG.debug("Tag rewrite operation is disabled for ");
+ return;
+ }
+
+ builder.setVlanType(iface.vtrPushDot1Q == 1
+ ? _802dot1q.class
+ : _802dot1ad.class);
+
+ setPushTags(builder, iface);
+ setPopTags(builder, operation);
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<Rewrite> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+
+ private void setPopTags(final RewriteBuilder builder, final TagRewriteOperation operation) {
+ final byte numberOfTagsToPop = operation.getPopTags();
+ if (numberOfTagsToPop != 0) {
+ builder.setPopTags(Short.valueOf(numberOfTagsToPop));
+ }
+ }
+
+ private void setPushTags(final RewriteBuilder builder, final SwInterfaceDetails iface) {
+ final List<PushTags> tags = new ArrayList<>();
+ if (iface.vtrTag1 != 0) {
+ tags.add(buildTag((short) 0, SVlan.class, iface.vtrTag1));
+ }
+ if (iface.vtrTag2 != 0) {
+ tags.add(buildTag((short) 1, CVlan.class, iface.vtrTag2));
+ }
+ if (tags.size() > 0) {
+ builder.setPushTags(tags);
+ }
+ }
+
+ private PushTags buildTag(final short index, final Class<? extends Dot1qTagVlanType> tagType, final int vlanId) {
+ final PushTagsBuilder tag = new PushTagsBuilder();
+ tag.setIndex(index);
+ tag.setKey(new PushTagsKey(index));
+ final Dot1qTagBuilder dtag = new Dot1qTagBuilder();
+ dtag.setTagType(tagType);
+ dtag.setVlanId(new Dot1qVlanId(vlanId));
+ tag.setDot1qTag(dtag.build());
+ return tag.build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..8c46a6a09
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java
@@ -0,0 +1,103 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyTableByInterface;
+import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ACLs enabled on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Acl, AclBuilder>, AclReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final NamingContext classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Acl readValue) {
+ ((SubInterfaceBuilder) parentBuilder).setAcl(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public AclBuilder getBuilder(@Nonnull final InstanceIdentifier<Acl> id) {
+ return new AclBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final AclBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface ACL: {}", id);
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ checkArgument(parentInterfacekey != null, "No parent interface key found");
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ checkArgument(subInterfacekey != null, "No sub-interface key found");
+ final String subInterfaceName =
+ getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+ try {
+ final ClassifyTableByInterfaceReply reply = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java
new file mode 100644
index 000000000..108a07a2c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java
@@ -0,0 +1,241 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder;
+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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.DefaultBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.UntaggedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading sub interfaces form the VPP.
+ */
+public class SubInterfaceCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<SubInterface, SubInterfaceKey, SubInterfaceBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class);
+ private NamingContext interfaceContext;
+ private static final Dot1qTag.VlanId ANY_VLAN_ID = new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any);
+
+ public SubInterfaceCustomizer(@Nonnull final FutureJVpp jvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Nonnull
+ @Override
+ public List<SubInterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ try {
+ // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
+ // to fill in the context with initial ifc mapping
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final String ifaceName = key.getName();
+ final int ifaceId = interfaceContext.getIndex(ifaceName, context.getMappingContext());
+
+ // TODO if we know that full dump was already performed we could use cache
+ // (checking if getCachedInterfaceDump() returns non empty map is not enough, because
+ // we could be part of particular iface state read
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = "".getBytes();
+ request.nameFilterValid = 0;
+
+ final CompletableFuture<SwInterfaceDetailsReplyDump> swInterfaceDetailsReplyDumpCompletableFuture =
+ getFutureJVpp().swInterfaceDump(request).toCompletableFuture();
+ final SwInterfaceDetailsReplyDump ifaces =
+ TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id);
+
+ if (null == ifaces || null == ifaces.swInterfaceDetails) {
+ LOG.warn("Looking for sub-interfaces, but no interfaces found in VPP");
+ return Collections.emptyList();
+ }
+
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ context.getModificationCache().put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
+
+ final List<SubInterfaceKey> interfacesKeys = ifaces.swInterfaceDetails.stream()
+ .filter(elt -> elt != null)
+ // accept only sub-interfaces for current iface:
+ .filter(elt -> elt.subId != 0 && elt.supSwIfIndex == ifaceId)
+ .map(details -> new SubInterfaceKey(new Long(details.subId)))
+ .collect(Collectors.toList());
+
+ LOG.debug("Sub-interfaces of {} found in VPP: {}", ifaceName, interfacesKeys);
+ return interfacesKeys;
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id,e);
+ }
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<SubInterface> readData) {
+ ((SubInterfacesBuilder) builder).setSubInterface(readData);
+ }
+
+ @Nonnull
+ @Override
+ public SubInterfaceBuilder getBuilder(@Nonnull final InstanceIdentifier<SubInterface> id) {
+ return new SubInterfaceBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterfaceBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ LOG.debug("Reading attributes for sub interface: {}", subInterfaceName);
+
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName,
+ interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache());
+ LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface));
+
+ checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface");
+
+ builder.setIdentifier(Long.valueOf(iface.subId));
+ builder.setKey(new SubInterfaceKey(builder.getIdentifier()));
+
+ // sub-interface-base-attributes:
+ builder.setTags(readTags(iface));
+ builder.setMatch(readMatch(iface));
+
+ // sub-interface-operational-attributes:
+ builder.setAdminStatus(1 == iface.adminUpDown
+ ? SubInterfaceStatus.Up
+ : SubInterfaceStatus.Down);
+ builder.setOperStatus(1 == iface.linkUpDown
+ ? SubInterfaceStatus.Up
+ : SubInterfaceStatus.Down);
+ builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex));
+ if (iface.l2AddressLength == 6) {
+ builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address)));
+ }
+ if (0 != iface.linkSpeed) {
+ builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed));
+ }
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<SubInterface> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(id.getTargetType()).getIdentifier()));
+ }
+
+ private Tags readTags(final SwInterfaceDetails iface) {
+ final TagsBuilder tags = new TagsBuilder();
+ final List<Tag> list = new ArrayList<>();
+ if (iface.subNumberOfTags > 0) {
+ if (iface.subOuterVlanIdAny == 1) {
+ list.add(buildTag((short) 0, SVlan.class, ANY_VLAN_ID));
+ } else {
+ list.add(buildTag((short) 0, SVlan.class, buildVlanId(iface.subOuterVlanId)));
+ }
+ // inner tag (customer tag):
+ if (iface.subNumberOfTags == 2) {
+ if (iface.subInnerVlanIdAny == 1) {
+ list.add(buildTag((short) 1, CVlan.class, ANY_VLAN_ID));
+ } else {
+ list.add(buildTag((short) 1, CVlan.class, buildVlanId(iface.subInnerVlanId)));
+ }
+ }
+ }
+ tags.setTag(list);
+ return tags.build();
+ }
+
+ private static Tag buildTag(final short index, final Class<? extends Dot1qTagVlanType> tagType,
+ final Dot1qTag.VlanId vlanId) {
+ TagBuilder tag = new TagBuilder();
+ tag.setIndex(index);
+ tag.setKey(new TagKey(index));
+ final Dot1qTagBuilder dtag = new Dot1qTagBuilder();
+ dtag.setTagType(tagType);
+ dtag.setVlanId(vlanId);
+ tag.setDot1qTag(dtag.build());
+ return tag.build();
+ }
+
+ private static Dot1qTag.VlanId buildVlanId(final short vlanId) {
+ // treat vlanId as unsigned value:
+ return new Dot1qTag.VlanId(new Dot1qVlanId(0xffff & vlanId));
+ }
+
+ private Match readMatch(final SwInterfaceDetails iface) {
+ final MatchBuilder match = new MatchBuilder();
+ if (iface.subDefault == 1) {
+ match.setMatchType(new DefaultBuilder().build());
+ } else if (iface.subNumberOfTags == 0) {
+ match.setMatchType(new UntaggedBuilder().build());
+ } else {
+ final VlanTaggedBuilder tagged = new VlanTaggedBuilder();
+ tagged.setMatchExactTags(byteToBoolean(iface.subExactMatch));
+ match.setMatchType(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTaggedBuilder()
+ .setVlanTagged(tagged.build()).build());
+ }
+ return match.build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java
new file mode 100644
index 000000000..4855915bb
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java
@@ -0,0 +1,77 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading vlan sub interface L2 operational state
+ */
+public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements ReaderCustomizer<L2, L2Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class);
+ private final InterconnectionReadUtils icReadUtils;
+
+ public SubInterfaceL2Customizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ super(futureJvpp);
+ this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
+ ((SubInterfaceBuilder) parentBuilder).setL2(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
+ return new L2Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface L2: {}", id);
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ final String subInterfaceName = getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+
+ builder.setInterconnection(icReadUtils.readInterconnection(id, subInterfaceName, ctx));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java
new file mode 100644
index 000000000..992912a63
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java
@@ -0,0 +1,121 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
+
+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.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.TapBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceTapDetails;
+import org.openvpp.jvpp.dto.SwInterfaceTapDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceTapDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class TapCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Tap, TapBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class);
+ public static final String DUMPED_TAPS_CONTEXT_KEY = TapCustomizer.class.getName() + "dumpedTapsDuringGetAllIds";
+ private NamingContext interfaceContext;
+
+ public TapCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder, @Nonnull Tap readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setTap(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public TapBuilder getBuilder(@Nonnull InstanceIdentifier<Tap> id) {
+ return new TapBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id,
+ @Nonnull final TapBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ try {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for tap interface: {}", key.getName());
+
+ @SuppressWarnings("unchecked")
+ Map<Integer, SwInterfaceTapDetails> mappedTaps =
+ (Map<Integer, SwInterfaceTapDetails>) ctx.getModificationCache().get(DUMPED_TAPS_CONTEXT_KEY);
+
+ if(mappedTaps == null) {
+ // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it
+ final SwInterfaceTapDump request = new SwInterfaceTapDump();
+ final CompletionStage<SwInterfaceTapDetailsReplyDump> swInterfaceTapDetailsReplyDumpCompletionStage =
+ getFutureJVpp().swInterfaceTapDump(request);
+ final SwInterfaceTapDetailsReplyDump reply =
+ TranslateUtils.getReplyForRead(swInterfaceTapDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ if(null == reply || null == reply.swInterfaceTapDetails) {
+ mappedTaps = Collections.emptyMap();
+ } else {
+ final List<SwInterfaceTapDetails> swInterfaceTapDetails = reply.swInterfaceTapDetails;
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ mappedTaps = swInterfaceTapDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
+ }
+
+ ctx.getModificationCache().put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps);
+ }
+
+ final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index);
+ LOG.trace("Tap interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceTapDetails);
+
+ builder.setTapName(TranslateUtils.toString(swInterfaceTapDetails.devName));
+ LOG.debug("Tap interface: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to readCurrentAttributes for: {}", id, e);
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java
new file mode 100644
index 000000000..a9bf069b2
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java
@@ -0,0 +1,130 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUserBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetails;
+import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceVhostUserDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class VhostUserCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<VhostUser, VhostUserBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class);
+ public static final String DUMPED_VHOST_USERS_CONTEXT_KEY = VhostUserCustomizer.class.getName() + "dumpedVhostUsersDuringGetAllIds";
+ private NamingContext interfaceContext;
+
+ public VhostUserCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder, @Nonnull VhostUser readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVhostUser(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VhostUserBuilder getBuilder(@Nonnull InstanceIdentifier<VhostUser> id) {
+ return new VhostUserBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUserBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ try {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for vhpost user interface: {}", key.getName());
+
+ @SuppressWarnings("unchecked")
+ Map<Integer, SwInterfaceVhostUserDetails> mappedVhostUsers =
+ (Map<Integer, SwInterfaceVhostUserDetails>) ctx.getModificationCache().get(DUMPED_VHOST_USERS_CONTEXT_KEY);
+
+ if(mappedVhostUsers == null) {
+ // Full VhostUser dump has to be performed here, no filter or anything is here to help so at least we cache it
+ final SwInterfaceVhostUserDump request = new SwInterfaceVhostUserDump();
+ final CompletionStage<SwInterfaceVhostUserDetailsReplyDump> swInterfaceVhostUserDetailsReplyDumpCompletionStage =
+ getFutureJVpp().swInterfaceVhostUserDump(request);
+ final SwInterfaceVhostUserDetailsReplyDump reply =
+ TranslateUtils.getReplyForRead(swInterfaceVhostUserDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ if(null == reply || null == reply.swInterfaceVhostUserDetails) {
+ mappedVhostUsers = Collections.emptyMap();
+ } else {
+ final List<SwInterfaceVhostUserDetails> swInterfaceVhostUserDetails = reply.swInterfaceVhostUserDetails;
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ mappedVhostUsers = swInterfaceVhostUserDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
+ }
+
+ ctx.getModificationCache().put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers);
+ }
+
+ // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping
+ final SwInterfaceVhostUserDetails swInterfaceVhostUserDetails = mappedVhostUsers.get(index);
+ LOG.trace("Vhost user interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceVhostUserDetails);
+
+ builder.setRole(swInterfaceVhostUserDetails.isServer == 1 ? VhostUserRole.Server : VhostUserRole.Client);
+ builder.setFeatures(BigInteger.valueOf(swInterfaceVhostUserDetails.features));
+ builder.setNumMemoryRegions((long) swInterfaceVhostUserDetails.numRegions);
+ builder.setSocket(TranslateUtils.toString(swInterfaceVhostUserDetails.sockFilename));
+ builder.setVirtioNetHdrSize((long) swInterfaceVhostUserDetails.virtioNetHdrSz);
+ builder.setConnectError(Integer.toString(swInterfaceVhostUserDetails.sockErrno));
+
+ LOG.debug("Vhost user interface: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to readCurrentAttributes for: {}", id, e);
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java
new file mode 100644
index 000000000..450c75709
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java
@@ -0,0 +1,145 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
+
+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.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+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.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.VxlanTunnelDetails;
+import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump;
+import org.openvpp.jvpp.dto.VxlanTunnelDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Vxlan, VxlanBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VxlanCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull Vxlan readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlan(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VxlanBuilder getBuilder(@Nonnull InstanceIdentifier<Vxlan> id) {
+ return new VxlanBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id,
+ @Nonnull final VxlanBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ try {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanTunnel.class)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for vxlan tunnel: {}", key.getName());
+ // Dump just a single
+ final VxlanTunnelDump request = new VxlanTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<VxlanTunnelDetailsReplyDump> swInterfaceVxlanDetailsReplyDumpCompletionStage =
+ getFutureJVpp().vxlanTunnelDump(request);
+ final VxlanTunnelDetailsReplyDump reply =
+ TranslateUtils.getReplyForRead(swInterfaceVxlanDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ // VPP keeps vxlan tunnel interfaces even after they were deleted (optimization)
+ // However there ar no longer any vxlan tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.vxlanTunnelDetails == null || reply.vxlanTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "Vxlan tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.vxlanTunnelDetails.size() == 1,
+ "Unexpected number of returned vxlan tunnels: {} for tunnel: {}", reply.vxlanTunnelDetails, key.getName());
+ LOG.trace("Vxlan tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final VxlanTunnelDetails swInterfaceVxlanDetails = reply.vxlanTunnelDetails.get(0);
+ if (swInterfaceVxlanDetails.isIpv6 == 1) {
+ final Ipv6Address dstIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanDetails.dstAddress).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv6));
+ final Ipv6Address srcIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanDetails.srcAddress).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.dstAddress, 0, 4);
+ final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.srcAddress, 0, 4);
+ final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv4));
+ }
+ builder.setEncapVrfId((long) swInterfaceVxlanDetails.encapVrfId);
+ builder.setVni( new VxlanVni((long) swInterfaceVxlanDetails.vni));
+ LOG.debug("Vxlan tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to readCurrentAttributes for: {}", id);
+ throw new ReadFailedException( id, e );
+ }
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java
new file mode 100644
index 000000000..6763aaf60
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java
@@ -0,0 +1,148 @@
+/*
+ * 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.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+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.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpeBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails;
+import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump;
+import org.openvpp.jvpp.dto.VxlanGpeTunnelDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanGpeCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<VxlanGpe, VxlanGpeBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public VxlanGpeCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull VxlanGpe readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlanGpe(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VxlanGpeBuilder getBuilder(@Nonnull InstanceIdentifier<VxlanGpe> id) {
+ return new VxlanGpeBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
+ @Nonnull final VxlanGpeBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ try {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanGpeTunnel.class)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for VxlanGpe tunnel: {}", key.getName());
+ // Dump just a single
+ final VxlanGpeTunnelDump request = new VxlanGpeTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<VxlanGpeTunnelDetailsReplyDump> swInterfaceVxlanGpeDetailsReplyDumpCompletionStage =
+ getFutureJVpp().vxlanGpeTunnelDump(request);
+ final VxlanGpeTunnelDetailsReplyDump reply =
+ TranslateUtils.getReplyForRead(swInterfaceVxlanGpeDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ // VPP keeps VxlanGpe tunnel interfaces even after they were deleted (optimization)
+ // However there are no longer any VxlanGpe tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.vxlanGpeTunnelDetails == null || reply.vxlanGpeTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "VxlanGpe tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.vxlanGpeTunnelDetails.size() == 1,
+ "Unexpected number of returned VxlanGpe tunnels: {} for tunnel: {}", reply.vxlanGpeTunnelDetails, key.getName());
+ LOG.trace("VxlanGpe tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final VxlanGpeTunnelDetails swInterfaceVxlanGpeDetails = reply.vxlanGpeTunnelDetails.get(0);
+ if (swInterfaceVxlanGpeDetails.isIpv6 == 1) {
+ final Ipv6Address remote6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.remote).getHostAddress());
+ builder.setRemote(new IpAddress(remote6));
+ final Ipv6Address local6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.local).getHostAddress());
+ builder.setLocal(new IpAddress(local6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.remote, 0, 4);
+ final Ipv4Address remote4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setRemote(new IpAddress(remote4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.local, 0, 4);
+ final Ipv4Address local4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setLocal(new IpAddress(local4));
+ }
+ builder.setVni(new VxlanGpeVni((long) swInterfaceVxlanGpeDetails.vni));
+ builder.setNextProtocol(VxlanGpeNextProtocol.forValue(swInterfaceVxlanGpeDetails.protocol));
+ builder.setEncapVrfId((long) swInterfaceVxlanGpeDetails.encapVrfId);
+ builder.setDecapVrfId((long) swInterfaceVxlanGpeDetails.decapVrfId);
+ LOG.debug("VxlanGpe tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to readCurrentAttributes for: {}", id);
+ throw new ReadFailedException( id, e );
+ }
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
new file mode 100644
index 000000000..b4b656c52
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
@@ -0,0 +1,113 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds;
+
+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.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.List;
+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.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.IpAddressDetails;
+import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read customizer for interface Ipv4 addresses.
+ */
+public class Ipv4AddressCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
+
+ private final NamingContext interfaceContext;
+
+ public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ @Nonnull
+ public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) {
+ return new AddressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder,
+ @Nonnull ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for interface address: {}", id);
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext());
+ final Optional<IpAddressDetailsReplyDump> dumpOptional =
+ dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx);
+
+ final Optional<IpAddressDetails> ipAddressDetails =
+ findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
+
+ if (ipAddressDetails.isPresent()) {
+ final IpAddressDetails detail = ipAddressDetails.get();
+ builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))
+ .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build());
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Attributes for {} interface (id={}) address {} successfully read: {}",
+ interfaceName, interfaceIndex, id, builder.build());
+ }
+ }
+ }
+
+ @Override
+ public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading list of keys for interface addresses: {}", id);
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext());
+ final Optional<IpAddressDetailsReplyDump> dumpOptional =
+ dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx);
+
+ return getAllIpv4AddressIds(dumpOptional, AddressKey::new);
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) {
+ ((Ipv4Builder) builder).setAddress(readData);
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java
new file mode 100644
index 000000000..6b890f343
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+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.v3po.util.FutureJVppCustomizer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv4Customizer extends FutureJVppCustomizer implements ReaderCustomizer<Ipv4, Ipv4Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
+
+ public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp) {
+ super(futureJvpp);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ipv4 readValue) {
+ ((Interface2Builder) parentBuilder).setIpv4(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public Ipv4Builder getBuilder(@Nonnull final InstanceIdentifier<Ipv4> id) {
+ return new Ipv4Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id, @Nonnull final Ipv4Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ //TODO add reading of isForwarding flag when there is dump for it
+ LOG.warn("Operation not supported");
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java
new file mode 100644
index 000000000..3b04c5614
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java
@@ -0,0 +1,73 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Operational data read operation customizer for {@link Neighbor}<br>
+ * Currently not supported in jvpp, so this is only dummy implementation<br>
+ */
+public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<Neighbor, NeighborKey, NeighborBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class);
+
+ public Ipv4NeighbourCustomizer(FutureJVpp futureJvpp) {
+ super(futureJvpp);
+ }
+
+ @Override
+ public NeighborBuilder getBuilder(InstanceIdentifier<Neighbor> id) {
+ return new NeighborBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(InstanceIdentifier<Neighbor> id, NeighborBuilder builder, ReadContext ctx)
+ throws ReadFailedException {
+ //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first
+ LOG.warn("Operation not supported");
+ }
+
+ @Override
+ public List<NeighborKey> getAllIds(InstanceIdentifier<Neighbor> id, ReadContext context)
+ throws ReadFailedException {
+ //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first
+ LOG.warn("Operation not supported,returning empty List");
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void merge(Builder<? extends DataObject> builder, List<Neighbor> readData) {
+ ((Ipv4Builder) builder).setNeighbor(readData);
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java
new file mode 100644
index 000000000..56ad73c9b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java
@@ -0,0 +1,130 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.IpAddressDetails;
+import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
+import org.openvpp.jvpp.dto.IpAddressDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Ipv4 read support.
+ */
+final class Ipv4ReadUtils {
+
+ static final String CACHE_KEY = Ipv4ReadUtils.class.getName();
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4ReadUtils.class);
+
+ private Ipv4ReadUtils() {
+ throw new UnsupportedOperationException("This utility class cannot be instantiated");
+ }
+
+ // Many VPP APIs do not provide get operation for single item. Dump requests for all items are used instead.
+ // To improve HC performance, caching dump requests is a common pattern.
+ // TODO: use more generic caching implementation, once provided
+ static Optional<IpAddressDetailsReplyDump> dumpAddresses(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final String interfaceName,
+ final int interfaceIndex, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+
+ final String cacheKey = CACHE_KEY + interfaceName;
+ Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache());
+
+ if (dumpFromCache.isPresent()) {
+ return dumpFromCache;
+ }
+
+ Optional<IpAddressDetailsReplyDump> dumpFromOperational;
+ try {
+ dumpFromOperational = dumpAddressFromOperationalData(futureJvpp, id, interfaceIndex);
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+
+ if (dumpFromOperational.isPresent()) {
+ ctx.getModificationCache().put(cacheKey, dumpFromOperational.get());
+ }
+
+ return dumpFromOperational;
+ }
+
+ private static Optional<IpAddressDetailsReplyDump> dumpAddressFromCache(@Nonnull final String cacheKey,
+ @Nonnull final ModificationCache cache) {
+ LOG.debug("Retrieving Ipv4 addresses from cache for {}", cacheKey);
+ return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey));
+ }
+
+ private static Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData(
+ @Nonnull final FutureJVpp futureJvpp, @Nonnull final InstanceIdentifier<?> id, final int interfaceIndex)
+ throws VppBaseCallException, ReadTimeoutException {
+ LOG.debug("Dumping Ipv4 addresses for interface id={}", interfaceIndex);
+ final IpAddressDump dumpRequest = new IpAddressDump();
+ dumpRequest.isIpv6 = 0;
+ dumpRequest.swIfIndex = interfaceIndex;
+ return Optional.fromNullable(
+ TranslateUtils.getReplyForRead(futureJvpp.ipAddressDump(dumpRequest).toCompletableFuture(), id));
+ }
+
+ @Nonnull static <T extends Identifier> List<T> getAllIpv4AddressIds(
+ final Optional<IpAddressDetailsReplyDump> dumpOptional,
+ @Nonnull final Function<Ipv4AddressNoZone, T> keyConstructor) {
+ if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
+ return dumpOptional.get().ipAddressDetails.stream()
+ .map(detail -> keyConstructor.apply(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ static Optional<IpAddressDetails> findIpAddressDetailsByIp(
+ final Optional<IpAddressDetailsReplyDump> dump,
+ @Nonnull final Ipv4AddressNoZone ip) {
+ checkNotNull(ip, "ip address should not be null");
+
+ if (dump.isPresent() && dump.get().ipAddressDetails != null) {
+ final List<IpAddressDetails> details = dump.get().ipAddressDetails;
+
+ return Optional.of(details.stream()
+ .filter(singleDetail -> ip.equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip)))
+ .collect(RWUtils.singleItemCollector()));
+ }
+ return Optional.absent();
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java
new file mode 100644
index 000000000..b71cca0bb
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java
@@ -0,0 +1,64 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+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.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public class Ipv6Customizer extends FutureJVppCustomizer implements ReaderCustomizer<Ipv6, Ipv6Builder> {
+
+ private final NamingContext interfaceContext;
+
+ public Ipv6Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ipv6 readValue) {
+ ((Interface2Builder) parentBuilder).setIpv6(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public Ipv6Builder getBuilder(@Nonnull final InstanceIdentifier<Ipv6> id) {
+ return new Ipv6Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id, @Nonnull final Ipv6Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ // TODO implement
+// final IpAddressDump dumpRequest = new IpAddressDump();
+// dumpRequest.isIpv6 = 1;
+// dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), ctx.getMappingContext());
+// final CompletionStage<IpAddressDetailsReplyDump> addressDumpFuture = getFutureJVpp().ipAddressDump(dumpRequest);
+ // TODO consider extracting customizer for address
+// final IpAddressDetailsReplyDump reply = TranslateUtils.getReply(addressDumpFuture.toCompletableFuture());
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644
index 000000000..c5fa6ee8e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java
@@ -0,0 +1,120 @@
+/*
+ * 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.translate.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds;
+
+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.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.List;
+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.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.IpAddressDetails;
+import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read customizer for sub-interface Ipv4 addresses.
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ @Nonnull
+ public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) {
+ return new AddressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder,
+ @Nonnull ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface address: {}", id);
+
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+ final Optional<IpAddressDetailsReplyDump> dumpOptional =
+ dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx);
+
+ final Optional<IpAddressDetails> ipAddressDetails =
+ findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
+
+ if (ipAddressDetails.isPresent()) {
+ final IpAddressDetails detail = ipAddressDetails.get();
+ builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))
+ .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build());
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Attributes for {} sub-interface (id={}) address {} successfully read: {}",
+ subInterfaceName, subInterfaceIndex, id, builder.build());
+ }
+ }
+ }
+
+ @Override
+ public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading list of keys for sub-interface addresses: {}", id);
+
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+ final Optional<IpAddressDetailsReplyDump> dumpOptional =
+ dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx);
+
+ return getAllIpv4AddressIds(dumpOptional, AddressKey::new);
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) {
+ ((Ipv4Builder) builder).setAddress(readData);
+ }
+
+ private static String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java
new file mode 100644
index 000000000..1c60ef609
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java
@@ -0,0 +1,153 @@
+/*
+ * 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.translate.v3po.notification;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.notification.NotificationCollector;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeoutException;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeleted;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeletedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceNameOrIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification;
+import org.openvpp.jvpp.dto.WantInterfaceEvents;
+import org.openvpp.jvpp.dto.WantInterfaceEventsReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Notification producer for interface events. It starts interface notification stream and for every
+ * received notification, it transforms it into its BA equivalent and pushes into HC's notification collector.
+ */
+@NotThreadSafe
+public final class InterfaceChangeNotificationProducer implements ManagedNotificationProducer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeNotificationProducer.class);
+
+ private final FutureJVpp jvpp;
+ private final NamingContext interfaceContext;
+ private final MappingContext mappingContext;
+ @Nullable
+ private AutoCloseable notificationListenerReg;
+
+ public InterfaceChangeNotificationProducer(@Nonnull final FutureJVpp jvpp,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final MappingContext mappingContext) {
+ this.jvpp = jvpp;
+ this.interfaceContext = interfaceContext;
+ this.mappingContext = mappingContext;
+ }
+
+ @Override
+ public void start(final NotificationCollector collector) {
+ LOG.trace("Starting interface notifications");
+ enableDisableIfcNotifications(1);
+ LOG.debug("Interface notifications started successfully");
+ notificationListenerReg = jvpp.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback(
+ swInterfaceSetFlagsNotification -> {
+ LOG.trace("Interface notification received: {}", swInterfaceSetFlagsNotification);
+ // TODO this should be lazy
+ collector.onNotification(transformNotification(swInterfaceSetFlagsNotification));
+ }
+ );
+ }
+
+ private Notification transformNotification(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) {
+ if (swInterfaceSetFlagsNotification.deleted == 1) {
+ return new InterfaceDeletedBuilder().setName(getIfcName(swInterfaceSetFlagsNotification)).build();
+ } else {
+ return new InterfaceStateChangeBuilder()
+ .setName(getIfcName(swInterfaceSetFlagsNotification))
+ .setAdminStatus(swInterfaceSetFlagsNotification.adminUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down)
+ .setOperStatus(swInterfaceSetFlagsNotification.linkUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down)
+ .build();
+ }
+ }
+
+ /**
+ * Get mapped name for the interface. Best effort only! The mapping might not yet be stored in context
+ * data tree (write transaction is still in progress and context changes have not been committed yet, or
+ * VPP sends the notification before it returns create request(that would store mapping)).
+ * <p/>
+ * In case mapping is not available, index is used as name. TODO inconsistent behavior, maybe just use indices ?
+ */
+ private InterfaceNameOrIndex getIfcName(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) {
+ final Optional<String> optionalName =
+ interfaceContext.getNameIfPresent(swInterfaceSetFlagsNotification.swIfIndex, mappingContext);
+ return optionalName.isPresent()
+ ? new InterfaceNameOrIndex(optionalName.get())
+ : new InterfaceNameOrIndex((long) swInterfaceSetFlagsNotification.swIfIndex);
+ }
+
+ @Override
+ public void stop() {
+ LOG.trace("Stopping interface notifications");
+ enableDisableIfcNotifications(0);
+ LOG.debug("Interface notifications stopped successfully");
+ try {
+ if (notificationListenerReg != null) {
+ notificationListenerReg.close();
+ }
+ } catch (Exception e) {
+ LOG.warn("Unable to properly close notification registration: {}", notificationListenerReg, e);
+ }
+ }
+
+ private void enableDisableIfcNotifications(int enableDisable) {
+ final WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents();
+ wantInterfaceEvents.pid = 1;
+ wantInterfaceEvents.enableDisable = enableDisable;
+ final CompletionStage<WantInterfaceEventsReply> wantInterfaceEventsReplyCompletionStage;
+ try {
+ wantInterfaceEventsReplyCompletionStage = jvpp.wantInterfaceEvents(wantInterfaceEvents);
+ TranslateUtils.getReply(wantInterfaceEventsReplyCompletionStage.toCompletableFuture());
+ } catch (VppBaseCallException | TimeoutException e) {
+ LOG.warn("Unable to {} interface notifications", enableDisable == 1 ? "enable" : "disable", e);
+ throw new IllegalStateException("Unable to control interface notifications", e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public Collection<Class<? extends Notification>> getNotificationTypes() {
+ final ArrayList<Class<? extends Notification>> classes = Lists.newArrayList();
+ classes.add(InterfaceStateChange.class);
+ classes.add(InterfaceDeleted.class);
+ return classes;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.trace("Closing interface notifications producer");
+ stop();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java
new file mode 100644
index 000000000..d148bc20c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java
@@ -0,0 +1,144 @@
+/*
+ * 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.translate.v3po.vpp;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.BridgeDomainAddDel;
+import org.openvpp.jvpp.dto.BridgeDomainAddDelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BridgeDomainCustomizer
+ extends FutureJVppCustomizer
+ implements ListWriterCustomizer<BridgeDomain, BridgeDomainKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class);
+
+ private static final byte ADD_OR_UPDATE_BD = (byte) 1;
+ private final NamingContext bdContext;
+
+ public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext) {
+ super(futureJvpp);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ }
+
+ private BridgeDomainAddDelReply addOrUpdateBridgeDomain(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ final int bdId, @Nonnull final BridgeDomain bd)
+ throws VppBaseCallException, WriteTimeoutException {
+ final BridgeDomainAddDelReply reply;
+ final BridgeDomainAddDel request = new BridgeDomainAddDel();
+ request.bdId = bdId;
+ request.flood = booleanToByte(bd.isFlood());
+ request.forward = booleanToByte(bd.isForward());
+ request.learn = booleanToByte(bd.isLearn());
+ request.uuFlood = booleanToByte(bd.isUnknownUnicastFlood());
+ request.arpTerm = booleanToByte(bd.isArpTermination());
+ request.isAdd = ADD_OR_UPDATE_BD;
+
+ reply = TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id);
+ LOG.debug("Bridge domain {} (id={}) add/update successful", bd.getName(), bdId);
+ return reply;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, dataBefore, ctx);
+ final String bdName = dataBefore.getName();
+
+ try {
+ int index;
+ if (bdContext.containsIndex(bdName, ctx.getMappingContext())) {
+ index = bdContext.getIndex(bdName, ctx.getMappingContext());
+ } else {
+ // FIXME we need the bd index to be returned by VPP or we should have a counter field
+ // (maybe in context similar to artificial name)
+ // Here we assign the next available ID from bdContext's perspective
+ index = 1;
+ while (bdContext.containsName(index, ctx.getMappingContext())) {
+ index++;
+ }
+ }
+ addOrUpdateBridgeDomain(id, index, dataBefore);
+ bdContext.addName(index, bdName, ctx.getMappingContext());
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to create bridge domain", e);
+ throw new WriteFailedException.CreateFailedException(id, dataBefore, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx);
+ final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
+ int bdId = bdContext.getIndex(bdName, ctx.getMappingContext());
+ try {
+
+ final BridgeDomainAddDel request = new BridgeDomainAddDel();
+ request.bdId = bdId;
+
+ TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id);
+ LOG.debug("Bridge domain {} (id={}) deleted successfully", bdName, bdId);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Bridge domain {} (id={}) delete failed", bdName, bdId);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter,
+ ctx);
+
+ final String bdName = checkNotNull(dataAfter.getName());
+ checkArgument(bdName.equals(dataBefore.getName()),
+ "BridgeDomain name changed. It should be deleted and then created.");
+
+ try {
+ addOrUpdateBridgeDomain(id, bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to create bridge domain", e);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java
new file mode 100644
index 000000000..0e4b90a56
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java
@@ -0,0 +1,141 @@
+/*
+ * 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.translate.v3po.vpp;
+
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.parseMac;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.L2FibAddDel;
+import org.openvpp.jvpp.dto.L2FibAddDelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for L2 FIB create/delete operations.<br> Sends {@code l2_fib_add_del} message to
+ * VPP.<br> Equivalent of invoking {@code vppctl l2fib add/del} command.
+ */
+public class L2FibEntryCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<L2FibEntry, L2FibEntryKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class);
+
+ private final NamingContext bdContext;
+ private final NamingContext interfaceContext;
+
+ public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJvpp);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Creating L2 FIB entry: {} {}", id, dataAfter);
+ l2FibAddDel(id, dataAfter, writeContext, true);
+ LOG.debug("L2 FIB entry created successfully: {} {}", id, dataAfter);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to create L2 FIB entry: {} {}", id, dataAfter);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataBefore, @Nonnull final L2FibEntry dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException(
+ "L2 FIB entry update is not supported. It has to be deleted and then created.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ try {
+ LOG.debug("Deleting L2 FIB entry: {} {}", id, dataBefore);
+ l2FibAddDel(id, dataBefore, writeContext, false);
+ LOG.debug("L2 FIB entry deleted successfully: {} {}", id, dataBefore);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to delete L2 FIB entry: {} {}", id, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void l2FibAddDel(@Nonnull final InstanceIdentifier<L2FibEntry> id, @Nonnull final L2FibEntry entry,
+ final WriteContext writeContext, boolean isAdd)
+ throws VppBaseCallException, WriteTimeoutException {
+ final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
+ final int bdId = bdContext.getIndex(bdName, writeContext.getMappingContext());
+
+ int swIfIndex = -1;
+ final String swIfName = entry.getOutgoingInterface();
+ if (swIfName != null) {
+ swIfIndex = interfaceContext.getIndex(swIfName, writeContext.getMappingContext());
+ }
+
+ final L2FibAddDel l2FibRequest = createL2FibRequest(entry, bdId, swIfIndex, isAdd);
+ LOG.debug("Sending l2FibAddDel request: {}", ReflectionToStringBuilder.toString(l2FibRequest));
+ final CompletionStage<L2FibAddDelReply> l2FibAddDelReplyCompletionStage =
+ getFutureJVpp().l2FibAddDel(l2FibRequest);
+
+ TranslateUtils.getReplyForWrite(l2FibAddDelReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private L2FibAddDel createL2FibRequest(final L2FibEntry entry, final int bdId, final int swIfIndex, boolean isAdd) {
+ final L2FibAddDel request = new L2FibAddDel();
+ request.mac = macToLong(entry.getPhysAddress().getValue());
+ request.bdId = bdId;
+ request.swIfIndex = swIfIndex;
+ request.isAdd = booleanToByte(isAdd);
+ if (isAdd) {
+ request.staticMac = booleanToByte(entry.isStaticConfig());
+ request.filterMac = booleanToByte(L2FibFilter.class == entry.getAction());
+ }
+ return request;
+ }
+
+ // mac address is string of the form: 11:22:33:44:55:66
+ // but VPP expects long value in the format 11:22:33:44:55:66:XX:XX
+ private static long macToLong(final String macAddress) {
+ final byte[] mac = parseMac(macAddress);
+ return Longs.fromBytes(mac[0], mac[1], mac[2], mac[3],
+ mac[4], mac[5], (byte) 0, (byte) 0);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java
new file mode 100644
index 000000000..8027968f1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java
@@ -0,0 +1,202 @@
+/*
+ * 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.translate.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifySessionDetails;
+import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump;
+import org.openvpp.jvpp.dto.ClassifySessionDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify session read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table verbose} command.
+ */
+public class ClassifySessionReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifySession, ClassifySessionKey, ClassifySessionBuilder>, VppNodeReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
+ static final String CACHE_KEY = ClassifySessionReader.class.getName();
+
+ private final NamingContext classifyTableContext;
+
+ public ClassifySessionReader(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifySession> readData) {
+ ((ClassifyTableBuilder) builder).setClassifySession(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifySession> id) {
+ return new ClassifySessionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify session: {}", id);
+
+ final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class);
+ checkArgument(key != null, "could not find ClassifySession key in {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", ""));
+ final Optional<ClassifySessionDetails> classifySession =
+ findClassifySessionDetailsByMatch(classifySessionDump, match);
+
+ if (classifySession.isPresent()) {
+ final ClassifySessionDetails detail = classifySession.get();
+ builder.setHitNext(readVppNode(detail.hitNextIndex, LOG));
+ if (detail.opaqueIndex != ~0) {
+ // value is specified:
+ builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex));
+ }
+ builder.setAdvance(detail.advance);
+ builder.setMatch(key.getMatch());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build());
+ }
+ }
+ }
+
+ private OpaqueIndex readOpaqueIndex(final int opaqueIndex) {
+ // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
+ // FIXME: the approach might fail if the opaqueIndex contains small value that collides
+ // with some of the adjacent nodes
+ final VppNode node = readVppNode(opaqueIndex, LOG);
+ if (node != null) {
+ return new OpaqueIndex(node);
+ } else {
+ return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
+ }
+ }
+
+ @Nullable
+ private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id);
+
+ final String cacheKey = CACHE_KEY + tableKey;
+
+ ClassifySessionDetailsReplyDump classifySessionDump =
+ (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey);
+ if (classifySessionDump != null) {
+ LOG.debug("Classify sessions is present in cache: {}", cacheKey);
+ return classifySessionDump;
+ }
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsIndex(tableName, ctx.getMappingContext()),
+ "Reading classify sessions for table {}, but table index could not be found in the classify table context",
+ tableName);
+ final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+ LOG.debug("Dumping classify sessions for classify table id={}", tableId);
+
+ try {
+ final ClassifySessionDump dumpRequest = new ClassifySessionDump();
+ dumpRequest.tableId = tableId;
+ classifySessionDump = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id);
+
+ // update the cache:
+ ctx.getModificationCache().put(cacheKey, classifySessionDump);
+ return classifySessionDump;
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ private static Optional<ClassifySessionDetails> findClassifySessionDetailsByMatch(
+ @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) {
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ final List<ClassifySessionDetails> details = classifySessionDump.classifySessionDetails;
+ final List<ClassifySessionDetails> filteredSessions = details.stream()
+ .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList());
+ if (filteredSessions.isEmpty()) {
+ return Optional.absent();
+ } else if (filteredSessions.size() == 1) {
+ return Optional.of(filteredSessions.get(0));
+ } else {
+ throw new IllegalStateException(String.format(
+ "Found %d classify sessions witch given match. Single session expected.",
+ filteredSessions.size()));
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifySessionKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify sessions: {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ return classifySessionDump.classifySessionDetails.stream()
+ .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match))))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java
new file mode 100644
index 000000000..5c00903ae
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java
@@ -0,0 +1,147 @@
+/*
+ * 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.translate.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelSession;
+import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify session create/delete.<br> Sends {@code classify_add_del_session} message
+ * to VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifySessionWriter extends FutureJVppCustomizer
+ implements ListWriterCustomizer<ClassifySession, ClassifySessionKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifySessionWriter(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter);
+ try {
+ classifyAddDelSession(true, id, dataAfter, writeContext);
+ LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify session update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore);
+ try {
+ classifyAddDelSession(false, id, dataBefore, writeContext);
+ LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession classifySession,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteTimeoutException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find classify table key in {}", id);
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+ "Could not find classify table index for {} in the classify table context", tableName);
+ final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+
+ final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
+ .classifyAddDelSession(
+ getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession));
+
+ TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifySession classifySession) {
+ ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory:
+ // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ request.hitNextIndex = classifySession.getHitNext().getPacketHandlingAction().getIntValue();
+
+ if (classifySession.getOpaqueIndex() != null) {
+ request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex());
+ } else {
+ request.opaqueIndex = ~0; // value not specified
+ }
+
+ // default 0:
+ request.advance = classifySession.getAdvance();
+
+ request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", ""));
+ return request;
+ }
+
+ private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) {
+ if (opaqueIndex.getUint32() != null) {
+ return opaqueIndex.getUint32().intValue();
+ } else {
+ // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue();
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java
new file mode 100644
index 000000000..6ad7b2151
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java
@@ -0,0 +1,147 @@
+/*
+ * 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.translate.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
+
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Arrays;
+import java.util.Collections;
+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.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyTableIds;
+import org.openvpp.jvpp.dto.ClassifyTableIdsReply;
+import org.openvpp.jvpp.dto.ClassifyTableInfo;
+import org.openvpp.jvpp.dto.ClassifyTableInfoReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify table read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table} command.
+ */
+public class ClassifyTableReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifyTableReader(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifyTable> readData) {
+ ((VppClassifierStateBuilder) builder).setClassifyTable(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifyTable> id) {
+ return new ClassifyTableBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify table: {}", id);
+
+ final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(key != null, "could not find ClassifyTable key in {}", id);
+ final ClassifyTableInfo request = new ClassifyTableInfo();
+
+ final String tableName = key.getName();
+ if (!classifyTableContext.containsIndex(tableName, ctx.getMappingContext())) {
+ LOG.debug("Could not find classify table {} in the naming context", tableName);
+ return;
+ }
+ request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+
+ try {
+ final ClassifyTableInfoReply reply =
+ TranslateUtils.getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id);
+
+ // mandatory values:
+ builder.setName(tableName);
+ builder.setKey(key);
+ builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets));
+ builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors));
+
+
+ builder.setMissNext(readVppNode(reply.missNextIndex, LOG));
+ builder.setMask(new HexString(printHexBinary(reply.mask)));
+ builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions));
+
+ if (reply.nextTableIndex != ~0) {
+ // next table index is present:
+ builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext()));
+ }
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build());
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifyTableKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify tables: {}", id);
+ try {
+ final ClassifyTableIdsReply classifyTableIdsReply = TranslateUtils
+ .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id);
+ if (classifyTableIdsReply.ids != null) {
+ return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> {
+ final String tableName = classifyTableContext.getName(i, context.getMappingContext());
+ LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i);
+ return new ClassifyTableKey(tableName);
+ }).collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java
new file mode 100644
index 000000000..12680b9cf
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java
@@ -0,0 +1,146 @@
+/*
+ * 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.translate.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ClassifyAddDelTable;
+import org.openvpp.jvpp.dto.ClassifyAddDelTableReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
+ * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifyTableWriter extends FutureJVppCustomizer
+ implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
+ private final NamingContext classifyTableContext;
+
+ public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp,
+ @Nonnull final NamingContext classifyTableContext) {
+ super(futureJvpp);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter);
+ try {
+ final int newTableIndex =
+ classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext());
+
+ // Add classify table name <-> vpp index mapping to the naming context:
+ classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify table update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
+ final String tableName = dataBefore.getName();
+ checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+ "Removing classify table {}, but index could not be found in the classify table context", tableName);
+
+ final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+ try {
+ classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
+
+ // Remove deleted interface from interface context:
+ classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
+ throws VppBaseCallException, WriteTimeoutException {
+ final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
+ getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx));
+
+ final ClassifyAddDelTableReply reply =
+ TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ return reply.newTableIndex;
+
+ }
+
+ private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifyTable table,
+ @Nonnull final MappingContext ctx) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory, all u32 values are permitted:
+ request.nbuckets = table.getNbuckets().intValue();
+ request.memorySize = table.getMemorySize().intValue();
+ request.skipNVectors = table.getSkipNVectors().intValue();
+
+ // mandatory
+ // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ request.missNextIndex = table.getMissNext().getPacketHandlingAction().getIntValue();
+
+ final String nextTable = table.getNextTable();
+ if (isAdd && nextTable != null) {
+ request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx);
+ } else {
+ request.nextTableIndex = ~0; // value not specified
+ }
+ request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", ""));
+ checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16.");
+ request.matchNVectors = request.mask.length / 16;
+
+ return request;
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java
new file mode 100644
index 000000000..6061b8672
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java
@@ -0,0 +1,41 @@
+/*
+ * 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.translate.v3po.vppclassifier;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.slf4j.Logger;
+
+interface VppNodeReader {
+
+ /**
+ * Converts vpp node index to YANG representation of vpp node.
+ *
+ * @param nodeIndex index of vpp node treated as signed integer.
+ * @return vpp node representation
+ */
+ default VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) {
+ final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex);
+ if (action == null) {
+ // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed
+ log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex);
+ return null;
+ }
+ return new VppNode(action);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java
new file mode 100644
index 000000000..e8cfe3978
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java
@@ -0,0 +1,154 @@
+/*
+ * 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.translate.v3po.vppstate;
+
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.BridgeDomainDetails;
+import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
+import org.openvpp.jvpp.dto.BridgeDomainDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class BridgeDomainCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class);
+ private final NamingContext bdContext;
+
+ public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext) {
+ super(futureJVpp);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomainBuilder builder, @Nonnull final ReadContext context)
+ throws ReadFailedException {
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: id={}, builderbuilder={}, context={}",
+ id, builder, context);
+
+ final BridgeDomainKey key = id.firstKeyOf(id.getTargetType());
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: key={}", key);
+
+ final int bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: bdId={}", bdId);
+
+ BridgeDomainDetailsReplyDump reply;
+ BridgeDomainDetails bridgeDomainDetails;
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
+ try {
+ reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get();
+ bridgeDomainDetails = Iterables.getOnlyElement(reply.bridgeDomainDetails);
+ } catch (Exception e) {
+ LOG.debug("Unable to read bridge domain: {}", key.getName(), e);
+ return;
+ }
+
+ logBridgeDomainDetails(bridgeDomainDetails);
+
+ builder.setName(key.getName());
+ builder.setArpTermination(byteToBoolean(bridgeDomainDetails.arpTerm));
+ builder.setFlood(byteToBoolean(bridgeDomainDetails.flood));
+ builder.setForward(byteToBoolean(bridgeDomainDetails.forward));
+ builder.setLearn(byteToBoolean(bridgeDomainDetails.learn));
+ builder.setUnknownUnicastFlood(byteToBoolean(bridgeDomainDetails.uuFlood));
+ }
+
+ private void logBridgeDomainDetails(final BridgeDomainDetails bridgeDomainDetails) {
+ LOG.debug("bridgeDomainDetails={}", bridgeDomainDetails);
+ if (bridgeDomainDetails != null) {
+ LOG.debug("bridgeDomainDetails.arpTerm={}", bridgeDomainDetails.arpTerm);
+ LOG.debug("bridgeDomainDetails.bdId={}", bridgeDomainDetails.bdId);
+ LOG.debug("bridgeDomainDetails.bviSwIfIndex={}", bridgeDomainDetails.bviSwIfIndex);
+ LOG.debug("bridgeDomainDetails.flood={}", bridgeDomainDetails.flood);
+ LOG.debug("bridgeDomainDetails.forward={}", bridgeDomainDetails.forward);
+ LOG.debug("bridgeDomainDetails.learn={}", bridgeDomainDetails.learn);
+ LOG.debug("bridgeDomainDetails.nSwIfs={}", bridgeDomainDetails.nSwIfs);
+ LOG.debug("bridgeDomainDetails.uuFlood={}", bridgeDomainDetails.uuFlood);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier<BridgeDomain> id) {
+ return new BridgeDomainBuilder();
+ }
+
+ @Nonnull
+ @Override
+ public List<BridgeDomainKey> getAllIds(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final ReadContext context) {
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = -1; // dump call
+
+ BridgeDomainDetailsReplyDump reply;
+ try {
+ reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get();
+ } catch (Exception e) {
+ throw new IllegalStateException("Bridge domain dump failed", e); // TODO ReadFailedException?
+ }
+
+ if (reply == null || reply.bridgeDomainDetails == null) {
+ return Collections.emptyList();
+ }
+
+ final int bIdsLength = reply.bridgeDomainDetails.size();
+ LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bIds.length={}", bIdsLength);
+ if (bIdsLength == 0) {
+ // No bridge domains
+ return Collections.emptyList();
+ }
+
+ final List<BridgeDomainKey> allIds = new ArrayList<>(bIdsLength);
+ for (BridgeDomainDetails detail : reply.bridgeDomainDetails) {
+ logBridgeDomainDetails(detail);
+
+ final String bName = bdContext.getName(detail.bdId, context.getMappingContext());
+ LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bName={}", bName);
+ allIds.add(new BridgeDomainKey(bName));
+ }
+
+ return allIds;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<BridgeDomain> readData) {
+ ((BridgeDomainsBuilder) builder).setBridgeDomain(readData);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java
new file mode 100644
index 000000000..a6ecafd72
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java
@@ -0,0 +1,154 @@
+/*
+ * 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.translate.v3po.vppstate;
+
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.vppPhysAddrToYang;
+import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.L2FibTableDump;
+import org.openvpp.jvpp.dto.L2FibTableEntry;
+import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class L2FibEntryCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<L2FibEntry, L2FibEntryKey, L2FibEntryBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class);
+
+ private static final Collector<L2FibTableEntry, ?, L2FibTableEntry> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ private final NamingContext bdContext;
+ private final NamingContext interfaceContext;
+
+ public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVpp);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntryBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+
+ final L2FibEntryKey key = id.firstKeyOf(id.getTargetType());
+ final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class);
+ final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext());
+ LOG.debug("Reading L2 FIB entry: key={}. bridgeDomainKey={}, bdId={}", key, bridgeDomainKey, bdId);
+
+ try {
+ // TODO use cached l2FibTable
+ final L2FibTableEntry entry = dumpL2Fibs(id, bdId).stream().filter(e -> key.getPhysAddress()
+ .equals(new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(e.mac), 2))))
+ .collect(SINGLE_ITEM_COLLECTOR);
+
+ builder.setAction(byteToBoolean(entry.filterMac)
+ ? L2FibFilter.class
+ : L2FibForward.class);
+ builder.setBridgedVirtualInterface(byteToBoolean(entry.bviMac));
+
+ if (entry.swIfIndex != -1) {
+ builder.setOutgoingInterface(interfaceContext.getName(entry.swIfIndex, ctx.getMappingContext()));
+ }
+ builder.setStaticConfig(byteToBoolean(entry.staticMac));
+ builder.setPhysAddress(key.getPhysAddress());
+ builder.setKey(key);
+ } catch (Exception e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ @Nonnull
+ private List<L2FibTableEntry> dumpL2Fibs(final InstanceIdentifier<L2FibEntry> id, final int bdId)
+ throws VppBaseCallException, ReadTimeoutException {
+ final L2FibTableDump l2FibRequest = new L2FibTableDump();
+ l2FibRequest.bdId = bdId;
+
+ final CompletableFuture<L2FibTableEntryReplyDump> l2FibTableDumpCompletableFuture =
+ getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture();
+
+ final L2FibTableEntryReplyDump dump = TranslateUtils.getReplyForRead(l2FibTableDumpCompletableFuture, id);
+
+ if (null == dump || null == dump.l2FibTableEntry) {
+ return Collections.emptyList();
+ } else {
+ return dump.l2FibTableEntry;
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<L2FibEntryKey> getAllIds(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class);
+ final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext());
+
+ LOG.debug("Reading L2 FIB for bridge domain {} (bdId={})", bridgeDomainKey, bdId);
+ try {
+ return dumpL2Fibs(id, bdId).stream()
+ .map(entry -> new L2FibEntryKey(
+ new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(entry.mac), 2))))
+ .collect(Collectors.toList());
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<L2FibEntry> readData) {
+ ((L2FibTableBuilder) builder).setL2FibEntry(readData);
+ }
+
+ @Nonnull
+ @Override
+ public L2FibEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<L2FibEntry> id) {
+ return new L2FibEntryBuilder();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java
new file mode 100644
index 000000000..7eaf2ec80
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.translate.v3po.vppstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.ShowVersion;
+import org.openvpp.jvpp.dto.ShowVersionReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public final class VersionCustomizer
+ extends FutureJVppCustomizer
+ implements ReaderCustomizer<Version, VersionBuilder> {
+
+ /**
+ * Default timeout for executing version read
+ */
+ private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
+
+ public VersionCustomizer(@Nonnull final FutureJVpp futureJVpp) {
+ super(futureJVpp);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Version readValue) {
+ ((VppStateBuilder) parentBuilder).setVersion(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VersionBuilder getBuilder(@Nonnull InstanceIdentifier<Version> id) {
+ return new VersionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Version> id, @Nonnull final VersionBuilder builder,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ try {
+ // Execute with timeout
+ final CompletionStage<ShowVersionReply> showVersionFuture = getFutureJVpp().showVersion(new ShowVersion());
+ final ShowVersionReply reply = TranslateUtils.getReplyForRead(showVersionFuture.toCompletableFuture(), id,
+ DEFAULT_TIMEOUT_IN_SECONDS);
+
+ builder.setBranch(TranslateUtils.toString(reply.version));
+ builder.setName(TranslateUtils.toString(reply.program));
+ builder.setBuildDate(TranslateUtils.toString(reply.buildDate));
+ builder.setBuildDirectory(TranslateUtils.toString(reply.buildDirectory));
+ } catch (VppBaseCallException e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+}