summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp/src/main/java/io/fd/honeycomb
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-05-06 09:41:51 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-05-11 09:21:01 +0200
commit44348596ff0c675bf3b799f88288111d92d771e6 (patch)
tree17edea7566a34efe7dedb5ee3d7833616e24f121 /v3po/v3po2vpp/src/main/java/io/fd/honeycomb
parent557acf16589e03bf17d255af7438614e63c2d2d3 (diff)
HONEYCOMG-47: Tap interface CRUD support
Tap interface specific configuration and state was added to V3po yang model. TapCustomizer added. Fixed customizers for Interfaces state. Fixed bug in Bridge domain customizers. Change-Id: I9dd47b8ada5153df8732c02cb59d331ab1adc71e Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb')
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java8
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java213
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java (renamed from v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VppInterfaceStateCustomizer.java)47
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java82
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java67
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java113
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtils.java55
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java22
8 files changed, 505 insertions, 102 deletions
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java
index 5d5a6c08b..b6d8748b9 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java
@@ -97,15 +97,12 @@ public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWri
private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf)
throws VppApiInvocationException, WriteFailedException {
- LOG.info("Setting interface {}, type: {}", swIf.getName(), swIf.getType().getSimpleName());
- LOG.debug("Setting interface {}", swIf);
-
+ LOG.debug("Setting interface: {} to: {}", id, swIf);
setInterfaceAttributes(swIf, swIf.getName());
}
private void setInterfaceAttributes(final Interface swIf, final String swIfName)
throws VppApiInvocationException {
- LOG.debug("Creating {} interface {}", swIf.getType().getSimpleName(), swIf.getName());
setInterfaceFlags(swIfName, interfaceContext.getIndex(swIfName),
swIf.isEnabled() ? (byte) 1 : (byte) 0);
@@ -114,8 +111,7 @@ public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWri
private void updateInterface(final InstanceIdentifier<Interface> id,
final Interface dataBefore,
final Interface dataAfter) throws VppApiInvocationException {
- LOG.info("Updating interface {}, type: {}", dataAfter.getName(), dataAfter.getType().getSimpleName());
- LOG.debug("Updating interface {}", dataAfter);
+ LOG.debug("Updating interface:{} to: {}", id, dataAfter);
setInterfaceAttributes(dataAfter, dataAfter.getName());
}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java
new file mode 100644
index 000000000..f05238dda
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java
@@ -0,0 +1,213 @@
+/*
+ * 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.v3po.translate.v3po.interfaces;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.spi.write.ChildWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
+import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
+import io.fd.honeycomb.v3po.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.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.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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 FutureJVppCustomizer implements ChildWriterCustomizer<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;
+ }
+
+ @Nonnull
+ @Override
+ public Optional<Tap> extract(@Nonnull final InstanceIdentifier<Tap> currentId,
+ @Nonnull final DataObject parentData) {
+ return Optional.fromNullable(((VppInterfaceAugmentation) parentData).getTap());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataAfter,
+ @Nonnull final Context writeContext)
+ throws WriteFailedException.CreateFailedException {
+ try {
+ createTap(id.firstKeyOf(Interface.class).getName(), dataAfter);
+ } catch (VppApiInvocationException e) {
+ LOG.warn("Write of Tap failed", 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 Context writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName);
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+
+ try {
+ modifyTap(ifcName, index, dataAfter);
+ } catch (VppApiInvocationException e) {
+ LOG.warn("Write of Tap failed", e);
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataBefore,
+ @Nonnull final Context writeContext)
+ throws WriteFailedException.DeleteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName);
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+
+ try {
+ deleteTap(ifcName, index, dataBefore);
+ } catch (VppApiInvocationException e) {
+ LOG.warn("Delete of Tap failed", e);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void createTap(final String swIfName, final Tap tap) throws VppApiInvocationException {
+ LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap);
+ final CompletionStage<TapConnectReply> tapConnectFuture =
+ getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance()));
+ final TapConnectReply reply =
+ V3poUtils.getReply(tapConnectFuture.toCompletableFuture());
+ if (reply.retval < 0) {
+ LOG.warn("Failed to set tap interface: {}, tap: {}", swIfName, tap);
+ throw new VppApiInvocationException("tap_connect", reply.context, reply.retval);
+ } else {
+ LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName);
+ }
+ }
+
+ private void modifyTap(final String swIfName, final int index, final Tap tap) throws VppApiInvocationException {
+ LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tap);
+ final CompletionStage<TapModifyReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().tapModify(getTapModifyRequest(tap.getTapName(), index, tap.getMac(), tap.getDeviceInstance()));
+ final TapModifyReply reply =
+ V3poUtils.getReply(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture());
+ if (reply.retval < 0) {
+ LOG.warn("Failed to modify tap interface: {}, tap: {}", swIfName, tap);
+ throw new VppApiInvocationException("tap_modify", reply.context, reply.retval);
+ } else {
+ LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tap);
+ }
+ }
+
+ private void deleteTap(final String swIfName, final int index, final Tap dataBefore)
+ throws VppApiInvocationException {
+ LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore);
+ final CompletionStage<TapDeleteReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().tapDelete(getTapDeleteRequest(index));
+ final TapDeleteReply reply =
+ V3poUtils.getReply(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture());
+ if (reply.retval < 0) {
+ LOG.warn("Failed to delete tap interface: {}, tap: {}", swIfName, dataBefore);
+ throw new VppApiInvocationException("tap_modify", reply.context, reply.retval);
+ } else {
+ LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore);
+ // Remove deleted interface from interface context
+ interfaceContext.removeName(swIfName);
+ }
+ }
+
+ 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 = V3poUtils.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 = V3poUtils.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/v3po/translate/v3po/interfacesstate/VppInterfaceStateCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java
index 2bc8beaaa..eca13c1c9 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VppInterfaceStateCustomizer.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java
@@ -16,15 +16,16 @@
package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.getCachedInterfaceDump;
+
import io.fd.honeycomb.v3po.translate.Context;
import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder;
@@ -37,54 +38,50 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class VppInterfaceStateCustomizer extends FutureJVppCustomizer
- implements ChildReaderCustomizer<VppInterfaceStateAugmentation, VppInterfaceStateAugmentationBuilder> {
+public class EthernetCustomizer extends FutureJVppCustomizer
+ implements ChildReaderCustomizer<Ethernet, EthernetBuilder> {
- private static final Logger LOG = LoggerFactory.getLogger(VppInterfaceStateCustomizer.class);
+ private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class);
+ private NamingContext interfaceContext;
- public VppInterfaceStateCustomizer(@Nonnull final FutureJVpp jvpp) {
+ public EthernetCustomizer(@Nonnull final FutureJVpp jvpp,
+ final NamingContext interfaceContext) {
super(jvpp);
+ this.interfaceContext = interfaceContext;
}
@Override
public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
- @Nonnull VppInterfaceStateAugmentation readValue) {
- ((InterfaceBuilder) parentBuilder).addAugmentation(VppInterfaceStateAugmentation.class, readValue);
+ @Nonnull Ethernet readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setEthernet(readValue);
}
@Nonnull
@Override
- public VppInterfaceStateAugmentationBuilder getBuilder(
- @Nonnull InstanceIdentifier<VppInterfaceStateAugmentation> id) {
- return new VppInterfaceStateAugmentationBuilder();
+ public EthernetBuilder getBuilder(
+ @Nonnull InstanceIdentifier<Ethernet> id) {
+ return new EthernetBuilder();
}
@Override
- public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VppInterfaceStateAugmentation> id,
- @Nonnull final VppInterfaceStateAugmentationBuilder builder,
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final EthernetBuilder builder,
@Nonnull final Context ctx) throws ReadFailedException {
final InterfaceKey key = id.firstKeyOf(Interface.class);
- final SwInterfaceDetails iface;
- try {
- iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key);
- } catch (Exception e) {
- throw new ReadFailedException(id, e);
- }
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
+ interfaceContext.getIndex(key.getName()), getCachedInterfaceDump(ctx));
- final EthernetBuilder ethernet = new EthernetBuilder();
- ethernet.setMtu((int) iface.linkMtu);
+ builder.setMtu((int) iface.linkMtu);
switch (iface.linkDuplex) {
case 1:
- ethernet.setDuplex(Ethernet.Duplex.Half);
+ builder.setDuplex(Ethernet.Duplex.Half);
break;
case 2:
- ethernet.setDuplex(Ethernet.Duplex.Full);
+ builder.setDuplex(Ethernet.Duplex.Full);
break;
default:
break;
}
-
- builder.setEthernet(ethernet.build());
}
}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java
index f7d473f73..82e114603 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java
@@ -24,10 +24,10 @@ import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
@@ -44,11 +44,15 @@ import org.openvpp.jvpp.future.FutureJVpp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface
+ */
public class InterfaceCustomizer extends FutureJVppCustomizer
implements ListReaderCustomizer<Interface, InterfaceKey, InterfaceBuilder> {
private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class);
+ public static final String DUMPED_IFCS_CONTEXT_KEY = InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds";
+
private final NamingContext interfaceContext;
public InterfaceCustomizer(@Nonnull final FutureJVpp jvpp, final NamingContext interfaceContext) {
@@ -56,47 +60,53 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
this.interfaceContext = interfaceContext;
}
+ @Nonnull
@Override
- public InterfaceBuilder getBuilder(InstanceIdentifier<Interface> id) {
+ public InterfaceBuilder getBuilder(@Nonnull InstanceIdentifier<Interface> id) {
return new InterfaceBuilder();
}
@Override
- public void readCurrentAttributes(InstanceIdentifier<Interface> id, InterfaceBuilder builder, Context ctx)
- throws ReadFailedException {
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Interface> id, @Nonnull InterfaceBuilder builder,
+ @Nonnull Context ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface: {}", id);
final InterfaceKey key = id.firstKeyOf(id.getTargetType());
- final SwInterfaceDetails iface;
- try {
- iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key);
- } catch (Exception e) {
- throw new ReadFailedException(id, e);
- }
+ final Map<Integer, SwInterfaceDetails> cachedDump = getCachedInterfaceDump(ctx);
+ // Pass cached details from getAllIds to getDetails to avoid additional dumps
+ final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
+ interfaceContext.getIndex(key.getName()), cachedDump);
+ LOG.debug("Interface details for interface: {}, details: {}", key.getName(), iface);
builder.setName(key.getName());
- // FIXME: report interface type based on name
- //Tunnel.class l2vlan(802.1q) bridge (transparent bridge?)
- builder.setType(EthernetCsmacd.class);
+ builder.setType(InterfaceUtils.getInterfaceType(new String(iface.interfaceName).intern()));
builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex));
- builder.setAdminStatus(iface.adminUpDown == 1
- ? AdminStatus.Up
- : AdminStatus.Down);
- builder.setOperStatus(1 == iface.linkUpDown
- ? OperStatus.Up
- : OperStatus.Down);
+ builder.setAdminStatus(1 == iface.adminUpDown ? AdminStatus.Up : AdminStatus.Down);
+ builder.setOperStatus(1 == iface.linkUpDown ? OperStatus.Up : OperStatus.Down);
if (0 != iface.linkSpeed) {
builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed));
}
if (iface.l2AddressLength == 6) {
builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address)));
}
+ LOG.trace("Base attributes read for interface: {} as: {}", key.getName(), builder);
+ }
+
+ @Nonnull
+ @SuppressWarnings("unchecked")
+ public static Map<Integer, SwInterfaceDetails> getCachedInterfaceDump(final @Nonnull Context ctx) {
+ return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null
+ ? Collections.emptyMap()
+ : (Map<Integer, SwInterfaceDetails>) ctx.get(DUMPED_IFCS_CONTEXT_KEY);
}
@Nonnull
@Override
public List<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> id,
@Nonnull final Context context) throws ReadFailedException {
+ LOG.trace("Dumping all interfaces to get all IDs");
+
final SwInterfaceDump request = new SwInterfaceDump();
request.nameFilter = "".getBytes();
request.nameFilterValid = 0;
@@ -105,21 +115,31 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
getFutureJVpp().swInterfaceDump(request).toCompletableFuture();
final SwInterfaceDetailsReplyDump ifaces = V3poUtils.getReply(swInterfaceDetailsReplyDumpCompletableFuture);
- // TODO can we get null here?
if (null == ifaces || null == ifaces.swInterfaceDetails) {
+ LOG.debug("No interfaces found in VPP");
return Collections.emptyList();
}
- return ifaces.swInterfaceDetails.stream()
- .filter(elt -> elt != null)
- .map((elt) -> {
- // Store interface name from VPP in context if not yet present
- if(!interfaceContext.containsName(elt.swIfIndex)){
- interfaceContext.addName(elt.swIfIndex, V3poUtils.toString(elt.interfaceName));
- }
- return new InterfaceKey(interfaceContext.getName(elt.swIfIndex));
- })
- .collect(Collectors.toList());
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ context.put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
+
+ final List<InterfaceKey> interfacesKeys = ifaces.swInterfaceDetails.stream()
+ .filter(elt -> elt != null)
+ .map((elt) -> {
+ // Store interface name from VPP in context if not yet present
+ if (!interfaceContext.containsName(elt.swIfIndex)) {
+ interfaceContext.addName(elt.swIfIndex, V3poUtils.toString(elt.interfaceName));
+ }
+ LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
+ interfaceContext.getName(elt.swIfIndex), elt.interfaceName, elt.swIfIndex);
+
+ return new InterfaceKey(interfaceContext.getName(elt.swIfIndex));
+ })
+ .collect(Collectors.toList());
+
+ LOG.debug("Interfaces found in VPP: {}", interfacesKeys);
+ return interfacesKeys;
}
@Override
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
index 691b95f98..62cac3550 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
@@ -18,13 +18,18 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
+import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
import java.math.BigInteger;
+import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.CompletionStage;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
import org.openvpp.jvpp.dto.SwInterfaceDetails;
import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
import org.openvpp.jvpp.dto.SwInterfaceDump;
@@ -82,6 +87,7 @@ public final class InterfaceUtils {
sb.append(HEX_CHARS[v & 15]);
}
+ // TODO rename and move to V3poUtils
/**
* Reads first 6 bytes of supplied byte array and converts to string as Yang dictates
* <p> Replace later with
@@ -125,7 +131,7 @@ public final class InterfaceUtils {
* @param yangIfIndex if-index from ietf-interfaces.
* @return VPP's representation of the if-index
*/
- public static int YangIfIndexToVpp(int yangIfIndex) {
+ public static int yangIfIndexToVpp(int yangIfIndex) {
Preconditions.checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
return yangIfIndex - 1;
}
@@ -136,27 +142,60 @@ public final class InterfaceUtils {
*
* @param futureJvpp VPP Java Future API
* @param key interface key
+ * @param index VPP index of the interface
+ * @param allInterfaces cached interfaces dump with all the interfaces. If interface not present, another dump all
+ * will be performed
+ *
* @return SwInterfaceDetails DTO or null if interface was not found
- * @throws ExecutionException if exception has been thrown while executing VPP query
- * @throws InterruptedException if the current thread was interrupted
+ *
+ * @throws IllegalArgumentException If interface cannot be found
*/
- @Nullable
+ @Nonnull
public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp,
- @Nonnull InterfaceKey key)
- throws ExecutionException, InterruptedException {
+ @Nonnull InterfaceKey key, final int index,
+ @Nonnull final Map<Integer, SwInterfaceDetails> allInterfaces) {
final SwInterfaceDump request = new SwInterfaceDump();
request.nameFilter = key.getName().getBytes();
request.nameFilterValid = 1;
- // TODO should we use timeout?
- SwInterfaceDetailsReplyDump ifaces = futureJvpp.swInterfaceDump(request).toCompletableFuture().get();
- if (null == ifaces) { // TODO can we get null here?
- LOG.warn("VPP returned null instead of interface by key {}", key.getName().getBytes());
- return null;
- }
+ CompletionStage<SwInterfaceDetailsReplyDump> requestFuture = futureJvpp.swInterfaceDump(request);
+ SwInterfaceDetailsReplyDump ifaces = V3poUtils.getReply(requestFuture.toCompletableFuture());
+ if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) {
+ LOG.warn("VPP returned null instead of interface by key {}", key.getName());
+ LOG.warn("Iterating through all the interfaces to find interface: {}", key.getName());
+ request.nameFilterValid = 0;
+
+ // Returned cached if available
+ if(allInterfaces.containsKey(index)) {
+ return allInterfaces.get(index);
+ }
+ // Or else just perform full dump and do inefficient filtering
+ requestFuture = futureJvpp.swInterfaceDump(request);
+ ifaces = V3poUtils.getReply(requestFuture.toCompletableFuture());
+
+ return ifaces.swInterfaceDetails.stream().filter((swIfc) -> swIfc.swIfIndex == index)
+ .findFirst().orElseThrow(() -> new IllegalArgumentException("Unable to find interface " + key.getName()));
+ }
return Iterables.getOnlyElement(ifaces.swInterfaceDetails);
}
+ /**
+ * Determine interface type based on its VPP name (relying on VPP's interface naming conventions)
+ *
+ * @param interfaceName VPP generated interface name
+ * @return Interface type
+ */
+ @Nonnull
+ public static Class<? extends InterfaceType> getInterfaceType(@Nonnull final String interfaceName) {
+ if(interfaceName.startsWith("tap")) {
+ return Tap.class;
+ }
+ if(interfaceName.startsWith("vxlan")) {
+ return VxlanTunnel.class;
+ }
+
+ return EthernetCsmacd.class;
+ }
}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java
new file mode 100644
index 000000000..a505436c3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
+
+import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.TapBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.SwInterfaceTapDetails;
+import org.openvpp.jvpp.dto.SwInterfaceTapDetailsReplyDump;
+import org.openvpp.jvpp.dto.SwInterfaceTapDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class TapCustomizer extends FutureJVppCustomizer
+ implements ChildReaderCustomizer<Tap, TapBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class);
+ public static final String DUMPED_TAPS_CONTEXT_KEY = TapCustomizer.class.getName() + "dumpedTapsDuringGetAllIds";
+ private NamingContext interfaceContext;
+
+ public TapCustomizer(@Nonnull final FutureJVpp jvpp,
+ final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull Tap readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setTap(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public TapBuilder getBuilder(
+ @Nonnull InstanceIdentifier<Tap> id) {
+ return new TapBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id,
+ @Nonnull final TapBuilder builder,
+ @Nonnull final Context ctx) throws ReadFailedException {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+
+ @SuppressWarnings("unchecked")
+ Map<Integer, SwInterfaceTapDetails> mappedTaps =
+ (Map<Integer, SwInterfaceTapDetails>) ctx.get(DUMPED_TAPS_CONTEXT_KEY);
+
+ if(mappedTaps == null) {
+ // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it
+ final SwInterfaceTapDump request = new SwInterfaceTapDump();
+ final CompletionStage<SwInterfaceTapDetailsReplyDump> swInterfaceTapDetailsReplyDumpCompletionStage =
+ getFutureJVpp().swInterfaceTapDump(request);
+ final SwInterfaceTapDetailsReplyDump reply =
+ V3poUtils.getReply(swInterfaceTapDetailsReplyDumpCompletionStage.toCompletableFuture());
+
+ if(null == reply || null == reply.swInterfaceTapDetails) {
+ mappedTaps = Collections.emptyMap();
+ } else {
+ final List<SwInterfaceTapDetails> swInterfaceTapDetails = reply.swInterfaceTapDetails;
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ mappedTaps = swInterfaceTapDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
+ }
+
+ ctx.put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps);
+ }
+
+ // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping
+ final int index = interfaceContext.getIndex(key.getName());
+ final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index);
+ if(swInterfaceTapDetails == null) {
+ // Not a Tap interface type
+ return;
+ }
+
+ builder.setTapName(V3poUtils.toString(swInterfaceTapDetails.devName));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtils.java
index b4217df46..392dc4666 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtils.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtils.java
@@ -16,34 +16,22 @@
package io.fd.honeycomb.v3po.translate.v3po.utils;
+import static com.google.common.base.Preconditions.checkArgument;
+
import com.google.common.base.Splitter;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.SoftwareLoopback;
+import java.util.function.BiConsumer;
+import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
import org.openvpp.jvpp.dto.JVppReply;
public final class V3poUtils {
// TODO move to vpp-translate-utils
- public static final int RESPONSE_NOT_READY = -77;
- public static final int RELEASE = 1;
- public static final Splitter DOT_SPLITTER = Splitter.on('.');
- public static final BiMap<String, Class<? extends InterfaceType>> IFC_TYPES = HashBiMap.create();
- static {
- V3poUtils.IFC_TYPES.put("vxlan", VxlanTunnel.class);
- V3poUtils.IFC_TYPES.put("lo", SoftwareLoopback.class);
- V3poUtils.IFC_TYPES.put("Ether", EthernetCsmacd.class);
- // TODO missing types below
-// V3poUtils.IFC_TYPES.put("l2tpv3_tunnel", EthernetCsmacd.class);
-// V3poUtils.IFC_TYPES.put("tap", EthernetCsmacd.class);
- }
+ public static final Splitter COLON_SPLITTER = Splitter.on(':');
private V3poUtils() {}
@@ -77,4 +65,35 @@ public final class V3poUtils {
public static String toString(final byte[] cString) {
return new String(cString).replaceAll("\\u0000", "").intern();
}
+
+ /**
+ * Parse string represented mac address (using ":" as separator) into a byte array
+ */
+ @Nonnull
+ public static byte[] parseMac(@Nonnull final String macAddress) {
+ final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
+ checkArgument(parts.size() == 6, "Mac address is expected to have 6 parts but was: %s", macAddress);
+ return parseMacLikeString(parts);
+ }
+
+ private static byte[] parseMacLikeString(final List<String> strings) {
+ return strings.stream().limit(6).map(V3poUtils::parseHexByte).collect(
+ () -> new byte[strings.size()],
+ new BiConsumer<byte[], Byte>() {
+
+ private int i = -1;
+
+ @Override
+ public void accept(final byte[] bytes, final Byte aByte) {
+ bytes[++i] = aByte;
+ }
+ },
+ (bytes, bytes2) -> {
+ throw new UnsupportedOperationException("Parallel collect not supported");
+ });
+ }
+
+ private static byte parseHexByte(final String aByte) {
+ return (byte)Integer.parseInt(aByte, 16);
+ }
}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java
index addb425f6..1a3855ced 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java
@@ -109,21 +109,27 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
try {
final L2FibTableEntryReplyDump dump =
getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture().get();
- final List<L2Fib> l2Fibs = Lists.newArrayListWithCapacity(dump.l2FibTableEntry.size());
- for (L2FibTableEntry entry : dump.l2FibTableEntry) {
- // entry.mac is a long value in the format 66:55:44:33:22:11:XX:XX
- // where mac address is 11:22:33:44:55:66
- final PhysAddress address = new PhysAddress(getMacAddress(Longs.toByteArray(entry.mac)));
- l2Fibs.add(new L2FibBuilder()
+ final List<L2Fib> l2Fibs;
+
+ if(null == dump || null == dump.l2FibTableEntry) {
+ l2Fibs = Collections.emptyList();
+ } else {
+ l2Fibs = Lists.newArrayListWithCapacity(dump.l2FibTableEntry.size());
+ for (L2FibTableEntry entry : dump.l2FibTableEntry) {
+ // entry.mac is a long value in the format 66:55:44:33:22:11:XX:XX
+ // where mac address is 11:22:33:44:55:66
+ final PhysAddress address = new PhysAddress(getMacAddress(Longs.toByteArray(entry.mac)));
+ l2Fibs.add(new L2FibBuilder()
.setAction((byteToBoolean(entry.filterMac)
- ? L2Fib.Action.Filter
- : L2Fib.Action.Forward))
+ ? L2Fib.Action.Filter
+ : L2Fib.Action.Forward))
.setBridgedVirtualInterface(byteToBoolean(entry.bviMac))
.setOutgoingInterface(interfaceContext.getName(entry.swIfIndex))
.setStaticConfig(byteToBoolean(entry.staticMac))
.setPhysAddress(address)
.setKey(new L2FibKey(address))
.build());
+ }
}
builder.setL2Fib(l2Fibs);