summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp
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
commitbc4ca7479b2b2e0e9bdfa49c89de0bc0573d2cbd (patch)
tree60d6ba53a396e610ac84af983a41bb85470a281a /v3po/v3po2vpp
parent19f4462a451a2500a2f95c7b82b28f73de9aa567 (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')
-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
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java7
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java27
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java145
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java25
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtilsTest.java40
13 files changed, 734 insertions, 117 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);
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java
index 769589b3d..2095f3000 100644
--- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java
@@ -13,6 +13,7 @@ import io.fd.honeycomb.v3po.translate.v3po.interfaces.EthernetCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.InterfaceCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.L2Customizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.RoutingCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.TapCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.VxlanCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4Customizer;
import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv6Customizer;
@@ -28,6 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.ChildOf;
@@ -96,12 +98,15 @@ public class InterfacesHoneycombWriterModule extends org.opendaylight.yang.gen.v
final ChildWriter<Vxlan> vxlanWriter = new CompositeChildWriter<>(Vxlan.class,
new VxlanCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+ final ChildWriter<Tap> tapWriter = new CompositeChildWriter<>(Tap.class,
+ new TapCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+
final ChildWriter<L2> l2Writer = new CompositeChildWriter<>(L2.class,
new L2Customizer(getVppJvppIfcDependency(), getInterfaceContextDependency(), getBridgeDomainContextDependency()));
final List<ChildWriter<? extends ChildOf<VppInterfaceAugmentation>>> vppIfcChildWriters = Lists.newArrayList();
- // TODO what's the order here ?
vppIfcChildWriters.add(vxlanWriter);
+ vppIfcChildWriters.add(tapWriter);
vppIfcChildWriters.add(ethernetWriter);
vppIfcChildWriters.add(l2Writer);
vppIfcChildWriters.add(routingWriter);
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
index e753cf56e..13fcf008e 100644
--- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
+++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
@@ -6,20 +6,28 @@ import static io.fd.honeycomb.v3po.translate.util.RWUtils.emptyChildReaderList;
import static io.fd.honeycomb.v3po.translate.util.RWUtils.singletonAugReaderList;
import static io.fd.honeycomb.v3po.translate.util.RWUtils.singletonChildReaderList;
+import com.google.common.collect.Lists;
import io.fd.honeycomb.v3po.translate.impl.read.CompositeChildReader;
import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader;
import io.fd.honeycomb.v3po.translate.impl.read.CompositeRootReader;
import io.fd.honeycomb.v3po.translate.read.ChildReader;
import io.fd.honeycomb.v3po.translate.util.read.CloseableReader;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveAugmentReaderCustomizer;
import io.fd.honeycomb.v3po.translate.util.read.ReflexiveRootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.EthernetCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VppInterfaceStateCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.TapCustomizer;
+import java.util.List;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
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.Tap;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
public class InterfacesStateHoneycombReaderModule extends
org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractInterfacesStateHoneycombReaderModule {
@@ -43,10 +51,23 @@ public class InterfacesStateHoneycombReaderModule extends
@Override
public java.lang.AutoCloseable createInstance() {
+ final ChildReader<? extends ChildOf<VppInterfaceStateAugmentation>> ethernetReader =
+ new CompositeChildReader<>(Ethernet.class,
+ new EthernetCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
+
+ final ChildReader<? extends ChildOf<VppInterfaceStateAugmentation>> tapReader =
+ new CompositeChildReader<>(Tap.class,
+ new TapCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
+
+ final List<ChildReader<? extends ChildOf<VppInterfaceStateAugmentation>>> childReaders = Lists.newArrayList();
+ childReaders.add(ethernetReader);
+ childReaders.add(tapReader);
+
final ChildReader<VppInterfaceStateAugmentation> vppInterfaceStateAugmentationChildReader =
new CompositeChildReader<>(VppInterfaceStateAugmentation.class,
- new VppInterfaceStateCustomizer(getVppJvppDependency()));
-
+ childReaders,
+ new ReflexiveAugmentReaderCustomizer<>(VppInterfaceStateAugmentationBuilder.class,
+ VppInterfaceStateAugmentation.class));
final CompositeListReader<Interface, InterfaceKey, InterfaceBuilder> interfaceReader =
new CompositeListReader<>(Interface.class,
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java
new file mode 100644
index 000000000..668eed4cf
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.v3po.interfaces;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.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.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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder;
+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;
+
+public class TapCustomizerTest {
+
+ @Mock
+ private FutureJVpp vppApi;
+ private NamingContext ctx;
+ private TapCustomizer tapCustomizer;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ ctx = new NamingContext("ifcintest");
+ tapCustomizer = new TapCustomizer(vppApi, ctx);
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ doAnswer(new Answer() {
+
+ int idx = 0;
+
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ final CompletableFuture<Object> reply = new CompletableFuture<>();
+ final TapConnectReply t = new TapConnectReply();
+ t.swIfIndex = idx++;
+ t.retval = 0;
+ reply.complete(t);
+ return reply;
+ }
+ }).when(vppApi).tapConnect(any(TapConnect.class));
+
+ tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), new Context());
+ tapCustomizer.writeCurrentAttributes(getTapId("tap2"), getTapData("tap2", "ff:ff:ff:ff:ff:ff"), new Context());
+
+ verify(vppApi, times(2)).tapConnect(any(TapConnect.class));
+ assertTrue(ctx.containsIndex("tap"));
+ assertTrue(ctx.containsIndex("tap2"));
+ }
+
+ @Test
+ public void testModify() throws Exception {
+ final CompletableFuture<TapConnectReply> reply = new CompletableFuture<>();
+ final TapConnectReply t = new TapConnectReply();
+ t.swIfIndex = 0;
+ reply.complete(t);
+ doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class));
+
+ final CompletableFuture<TapModifyReply> replyModif = new CompletableFuture<>();
+ final TapModifyReply tmodif = new TapModifyReply();
+ tmodif.swIfIndex = 0;
+ tmodif.retval = 0;
+ replyModif.complete(tmodif);
+ doReturn(replyModif).when(vppApi).tapModify(any(TapModify.class));
+
+ tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), new Context());
+ tapCustomizer.updateCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), getTapData("tap", "ff:ff:ff:ff:ff:f1"), new Context());
+
+ verify(vppApi).tapConnect(any(TapConnect.class));
+ verify(vppApi).tapModify(any(TapModify.class));
+ assertTrue(ctx.containsIndex("tap"));
+ assertFalse(ctx.containsIndex("tap2"));
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final CompletableFuture<TapConnectReply> reply = new CompletableFuture<>();
+ final TapConnectReply t = new TapConnectReply();
+ t.swIfIndex = 0;
+ reply.complete(t);
+ doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class));
+
+ final CompletableFuture<TapDeleteReply> replyDelete = new CompletableFuture<>();
+ final TapDeleteReply tmodif = new TapDeleteReply();
+ tmodif.retval = 0;
+ replyDelete.complete(tmodif);
+ doReturn(replyDelete).when(vppApi).tapDelete(any(TapDelete.class));
+
+ tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), new Context());
+ tapCustomizer.deleteCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), new Context());
+
+ verify(vppApi).tapConnect(any(TapConnect.class));
+ verify(vppApi).tapDelete(any(TapDelete.class));
+ assertFalse(ctx.containsIndex("tap"));
+ }
+
+ private InstanceIdentifier<Tap> getTapId(final String tap) {
+ return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(tap)).augmentation(
+ VppInterfaceAugmentation.class).child(Tap.class);
+ }
+
+ private Tap getTapData(final String tap, final String mac) {
+ return new TapBuilder().setTapName(tap).setMac(new PhysAddress(mac)).build();
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java
index 7c88c3198..3f33d141f 100644
--- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java
@@ -16,16 +16,16 @@
package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
-import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.YangIfIndexToVpp;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.yangIfIndexToVpp;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest;
import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
@@ -63,6 +63,8 @@ public class InterfaceCustomizerTest extends
@Override
protected RootReaderCustomizer<Interface, InterfaceBuilder> initCustomizer() {
+ interfacesContext.addName(0, "eth0");
+ interfacesContext.addName(1, "eth1");
return new InterfaceCustomizer(api, interfacesContext);
}
@@ -75,10 +77,11 @@ public class InterfaceCustomizerTest extends
verify(builder).setInterface(value);
}
- private void verifyBridgeDomainDumpUpdateWasInvoked(final int nameFilterValid, final String ifaceName) {
+ private void verifyBridgeDomainDumpUpdateWasInvoked(final int nameFilterValid, final String ifaceName,
+ final int dumpIfcsInvocationCount) {
// TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete
ArgumentCaptor<SwInterfaceDump> argumentCaptor = ArgumentCaptor.forClass(SwInterfaceDump.class);
- verify(api).swInterfaceDump(argumentCaptor.capture());
+ verify(api, times(dumpIfcsInvocationCount)).swInterfaceDump(argumentCaptor.capture());
final SwInterfaceDump actual = argumentCaptor.getValue();
assertEquals(nameFilterValid, actual.nameFilterValid);
assertArrayEquals(ifaceName.getBytes(), actual.nameFilter);
@@ -86,7 +89,7 @@ public class InterfaceCustomizerTest extends
private static void assertIfacesAreEqual(final Interface iface, final SwInterfaceDetails details) {
assertEquals(iface.getName(), new String(details.interfaceName));
- assertEquals(YangIfIndexToVpp(iface.getIfIndex().intValue()), details.swIfIndex);
+ assertEquals(yangIfIndexToVpp(iface.getIfIndex().intValue()), details.swIfIndex);
assertEquals(iface.getPhysAddress().getValue(), InterfaceUtils.vppPhysAddrToYang(details.l2Address));
}
@@ -119,7 +122,7 @@ public class InterfaceCustomizerTest extends
getCustomizer().readCurrentAttributes(id, builder, ctx);
- verifyBridgeDomainDumpUpdateWasInvoked(1, ifaceName);
+ verifyBridgeDomainDumpUpdateWasInvoked(1, ifaceName, 1);
assertIfacesAreEqual(builder.build(), iface);
}
@@ -134,8 +137,8 @@ public class InterfaceCustomizerTest extends
try {
getCustomizer().readCurrentAttributes(id, builder, ctx);
- } catch (ReadFailedException e) {
- verifyBridgeDomainDumpUpdateWasInvoked(1, ifaceName);
+ } catch (IllegalArgumentException e) {
+ verifyBridgeDomainDumpUpdateWasInvoked(0, ifaceName, 2);
return;
}
@@ -149,16 +152,18 @@ public class InterfaceCustomizerTest extends
final String swIf0Name = "eth0";
final SwInterfaceDetails swIf0 = new SwInterfaceDetails();
+ swIf0.swIfIndex = 0;
swIf0.interfaceName = swIf0Name.getBytes();
- final String swIf1Name = "eth0";
+ final String swIf1Name = "eth1";
final SwInterfaceDetails swIf1 = new SwInterfaceDetails();
+ swIf1.swIfIndex = 1;
swIf1.interfaceName = swIf1Name.getBytes();
whenSwInterfaceDumpThenReturn(Arrays.asList(swIf0, swIf1));
final List<InterfaceKey> expectedIds = Arrays.asList(new InterfaceKey(swIf0Name), new InterfaceKey(swIf1Name));
final List<InterfaceKey> actualIds = getCustomizer().getAllIds(id, ctx);
- verifyBridgeDomainDumpUpdateWasInvoked(0, "");
+ verifyBridgeDomainDumpUpdateWasInvoked(0, "", 1);
assertEquals(expectedIds, actualIds);
}
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtilsTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtilsTest.java
index 115eb2b9c..b28234db4 100644
--- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtilsTest.java
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/utils/V3poUtilsTest.java
@@ -1,6 +1,7 @@
package io.fd.honeycomb.v3po.translate.v3po.utils;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import org.junit.Test;
@@ -14,4 +15,41 @@ public class V3poUtilsTest {
final String jString = V3poUtils.toString(cString);
assertArrayEquals(expected, jString.getBytes());
}
-} \ No newline at end of file
+
+ @Test
+ public void testParseMac() throws Exception {
+ byte[] bytes = V3poUtils.parseMac("00:fF:7f:15:5e:A9");
+ assertMac(bytes);
+ }
+
+ private void assertMac(final byte[] bytes) {
+ assertEquals(6, bytes.length);
+ assertEquals((byte)0, bytes[0]);
+ assertEquals((byte)255, bytes[1]);
+ assertEquals((byte)127, bytes[2]);
+ assertEquals((byte)21, bytes[3]);
+ assertEquals((byte)94, bytes[4]);
+ assertEquals((byte)169, bytes[5]);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseMacLonger() throws Exception {
+ byte[] bytes = V3poUtils.parseMac("00:fF:7f:15:5e:A9:88:77");
+ assertMac(bytes);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseMacShorter() throws Exception {
+ V3poUtils.parseMac("00:fF:7f");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testParseRandomString() throws Exception {
+ V3poUtils.parseMac("random{}}@$*&*!");
+ }
+
+ @Test(expected = NumberFormatException.class)
+ public void testParseMacNumberFormatEx() throws Exception {
+ V3poUtils.parseMac("00:XX:7f:15:5e:77\"");
+ }
+}