summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces
diff options
context:
space:
mode:
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces')
-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
21 files changed, 2688 insertions, 0 deletions
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);
+ }
+ }
+}