summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHongjun Ni <hongjun.ni@intel.com>2016-07-22 19:20:18 +0800
committerHongjun Ni <hongjun.ni@intel.com>2016-08-03 19:31:16 +0800
commit3edacf6ea046b837907571911090aa1df4d60f69 (patch)
tree8d71c38693bf651b54c20894255f4d80cb2fa1b4
parent84eb5829ae847a08db1e6fd08de1be51762392a4 (diff)
HONEYCOMB-83: Add Gre Feature within HC
PatchSet 7: refactor code PatchSet 6: Refactor based on new code organization PatchSet 5: consolidate review comments PatchSet 4: refactor to support reader registry PatchSet 3: rebuild PatchSet 2: update outer-fib-id in v3po.yang. PatchSet 1: Add GRE feature and support IPv6. Change-Id: I1fc064b618f161eaef06395380949277e2f9f060 Signed-off-by: Hongjun Ni <hongjun.ni@intel.com>
-rw-r--r--v3po/api/src/main/yang/v3po.yang28
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java15
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizer.java171
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizer.java143
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java5
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java8
-rw-r--r--v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java6
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizerTest.java249
-rw-r--r--v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizerTest.java137
9 files changed, 762 insertions, 0 deletions
diff --git a/v3po/api/src/main/yang/v3po.yang b/v3po/api/src/main/yang/v3po.yang
index 5d582181f..409da3041 100644
--- a/v3po/api/src/main/yang/v3po.yang
+++ b/v3po/api/src/main/yang/v3po.yang
@@ -49,6 +49,10 @@ module v3po {
base if:interface-type;
}
+ identity gre-tunnel {
+ base if:interface-type;
+ }
+
identity vhost-user {
base if:interface-type;
}
@@ -291,6 +295,20 @@ module v3po {
}
}
+ grouping gre-base-attributes {
+ leaf src {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf dst {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf outer-fib-id {
+ type uint32;
+ }
+ }
+
grouping vxlan-gpe-base-attributes {
leaf local {
/*mandatory true;*/
@@ -423,6 +441,11 @@ module v3po {
uses vxlan-base-attributes;
}
+ container gre {
+ when "../if:type = 'v3po:gre-tunnel'";
+ uses gre-base-attributes;
+ }
+
container l2 {
must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
"not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
@@ -496,6 +519,11 @@ module v3po {
uses vxlan-gpe-base-attributes;
}
+ container gre {
+ when "../if:type = 'gre-tunnel'";
+ uses gre-base-attributes;
+ }
+
container l2 {
must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
"not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java
index 1d58bd18d..c218e5456 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java
@@ -52,6 +52,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.VhostUserBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.GreBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
@@ -59,6 +60,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.state._interface.VhostUser;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Gre;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder;
@@ -128,6 +130,11 @@ public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesS
setVxlanGpe(augmentBuilder, vxlanGpe);
}
+ final Gre gre = vppIfcAugmentation.getGre();
+ if (gre != null) {
+ setGre(augmentBuilder, gre);
+ }
+
final Tap tap = vppIfcAugmentation.getTap();
if (tap != null) {
setTap(input, augmentBuilder, tap);
@@ -279,4 +286,12 @@ public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesS
vxlanGpeBuilder.setDecapVrfId(vxlanGpe.getDecapVrfId());
augmentBuilder.setVxlanGpe(vxlanGpeBuilder.build());
}
+
+ private static void setGre(final VppInterfaceAugmentationBuilder augmentBuilder, final Gre gre) {
+ final GreBuilder greBuilder = new GreBuilder();
+ greBuilder.setDst(gre.getDst());
+ greBuilder.setSrc(gre.getSrc());
+ greBuilder.setOuterFibId(gre.getOuterFibId());
+ augmentBuilder.setGre(greBuilder.build());
+ }
}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizer.java
new file mode 100644
index 000000000..673eef9da
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizer.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016 Intel and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.GreTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Gre;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.GreAddDelTunnel;
+import org.openvpp.jvpp.dto.GreAddDelTunnelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GreCustomizer extends AbstractInterfaceTypeCustomizer<Gre> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GreCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public GreCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return GreTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ createGreTunnel(id, swIfName, dataAfter, writeContext);
+ } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
+ LOG.warn("Failed to set gre tunnel for interface: {}, gre: {}", swIfName, dataAfter, e);
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataBefore,
+ @Nonnull final Gre dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Gre tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ try {
+ deleteGreTunnel(id, swIfName, dataBefore, writeContext);
+ } catch (VppBaseCallException e) {
+ LOG.debug("Failed to delete gre tunnel for interface: {}, gre: {}", swIfName, dataBefore);
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void createGreTunnel(final InstanceIdentifier<Gre> id, final String swIfName, final Gre gre,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(gre) ? 1 : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(gre.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(gre.getDst()));
+
+ int outerFibId = gre.getOuterFibId().intValue();
+
+ LOG.debug("Setting gre tunnel for interface: {}. Gre: {}", swIfName, gre);
+ final CompletionStage<GreAddDelTunnelReply> greAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().greAddDelTunnel(getGreTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), outerFibId, isIpv6));
+
+ final GreAddDelTunnelReply reply =
+ TranslateUtils.getReplyForWrite(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Gre tunnel set successfully for: {}, gre: {}", swIfName, gre);
+ if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ // VPP keeps gre tunnels present even after they are delete(reserving ID for next tunnel)
+ // This may cause inconsistencies in mapping context when configuring tunnels like this:
+ // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. gre_tunnel0 -> 6
+ // will get into mapping context) 4. Add tunnel (this will add another mapping with the same
+ // reserved ID and context is invalid)
+ // That's why a check has to be performed here removing mapping gre_tunnel0 -> 6 mapping and storing
+ // new name for that ID
+ final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a gre tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceContext.removeName(formerName, writeContext.getMappingContext());
+ }
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final Gre gre) {
+ if (gre.getSrc().getIpv4Address() == null) {
+ checkArgument(gre.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", gre.getSrc(),
+ gre.getDst());
+ return true;
+ } else {
+ checkArgument(gre.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", gre.getSrc(),
+ gre.getDst());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteGreTunnel(final InstanceIdentifier<Gre> id, final String swIfName, final Gre gre,
+ final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException {
+ final byte isIpv6 = (byte) (isIpv6(gre) ? 1 : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(gre.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(gre.getDst()));
+
+ int outerFibId = gre.getOuterFibId().intValue();
+
+ LOG.debug("Deleting gre tunnel for interface: {}. Gre: {}", swIfName, gre);
+ final CompletionStage<GreAddDelTunnelReply> greAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().greAddDelTunnel(getGreTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), outerFibId, isIpv6));
+
+ TranslateUtils.getReplyForWrite(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Gre tunnel deleted successfully for: {}, gre: {}", swIfName, gre);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private static GreAddDelTunnel getGreTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr,
+ final int outerFibId, final byte isIpv6) {
+ final GreAddDelTunnel greAddDelTunnel = new GreAddDelTunnel();
+ greAddDelTunnel.isAdd = isAdd;
+ greAddDelTunnel.srcAddress = srcAddr;
+ greAddDelTunnel.dstAddress = dstAddr;
+ greAddDelTunnel.outerFibId = outerFibId;
+ greAddDelTunnel.isIpv6 = isIpv6;
+ return greAddDelTunnel;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizer.java
new file mode 100644
index 000000000..a17a1f15b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizer.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016 Intel and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.GreTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.GreBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.GreTunnelDetails;
+import org.openvpp.jvpp.dto.GreTunnelDetailsReplyDump;
+import org.openvpp.jvpp.dto.GreTunnelDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GreCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Gre, GreBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GreCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public GreCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull Gre readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setGre(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public GreBuilder getBuilder(@Nonnull InstanceIdentifier<Gre> id) {
+ return new GreBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id,
+ @Nonnull final GreBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ try {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, GreTunnel.class)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for gre tunnel: {}", key.getName());
+ // Dump just a single
+ final GreTunnelDump request = new GreTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<GreTunnelDetailsReplyDump> swInterfaceGreDetailsReplyDumpCompletionStage =
+ getFutureJVpp().greTunnelDump(request);
+ final GreTunnelDetailsReplyDump reply =
+ TranslateUtils.getReplyForRead(swInterfaceGreDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ // VPP keeps gre tunnel interfaces even after they were deleted (optimization)
+ // However there ar no longer any gre tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.greTunnelDetails == null || reply.greTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "Gre tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.greTunnelDetails.size() == 1,
+ "Unexpected number of returned gre tunnels: {} for tunnel: {}", reply.greTunnelDetails, key.getName());
+ LOG.trace("Gre tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final GreTunnelDetails swInterfaceGreDetails = reply.greTunnelDetails.get(0);
+ if (swInterfaceGreDetails.isIpv6 == 1) {
+ final Ipv6Address dstIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceGreDetails.dstAddress).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv6));
+ final Ipv6Address srcIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceGreDetails.srcAddress).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceGreDetails.dstAddress, 0, 4);
+ final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceGreDetails.srcAddress, 0, 4);
+ final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv4));
+ }
+ builder.setOuterFibId((long) swInterfaceGreDetails.outerFibId);
+ LOG.debug("Gre tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ } catch (VppBaseCallException e) {
+ LOG.warn("Failed to readCurrentAttributes for: {}", id, e);
+ throw new ReadFailedException( id, e );
+ }
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java
index b7c1e518a..e47fc05c9 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java
@@ -38,6 +38,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.VhostUser;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.GreTunnel;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.openvpp.jvpp.VppBaseCallException;
import org.openvpp.jvpp.dto.SwInterfaceDetails;
@@ -255,6 +256,10 @@ public final class InterfaceUtils {
return VxlanTunnel.class;
}
+ if (interfaceName.startsWith("gre")) {
+ return GreTunnel.class;
+ }
+
if (interfaceName.startsWith("VirtualEthernet")) {
return VhostUser.class;
}
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 c3e56ef80..d0a868319 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
@@ -8,6 +8,7 @@ import io.fd.honeycomb.translate.impl.write.GenericListWriter;
import io.fd.honeycomb.translate.impl.write.GenericWriter;
import io.fd.honeycomb.translate.v3po.interfaces.AclCustomizer;
import io.fd.honeycomb.translate.v3po.interfaces.EthernetCustomizer;
+import io.fd.honeycomb.translate.v3po.interfaces.GreCustomizer;
import io.fd.honeycomb.translate.v3po.interfaces.InterfaceCustomizer;
import io.fd.honeycomb.translate.v3po.interfaces.L2Customizer;
import io.fd.honeycomb.translate.v3po.interfaces.RoutingCustomizer;
@@ -42,6 +43,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.VhostUser;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Gre;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.openvpp.jvpp.future.FutureJVpp;
@@ -151,6 +153,12 @@ public class InterfacesHoneycombWriterModule extends
registry.addBefore(new GenericWriter<>(tapId, new TapCustomizer(jvpp, ifcContext)),
ifcId);
+ // Gre(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<Gre> greId = VPP_IFC_AUG_ID.child(Gre.class);
+ registry.addBefore(new GenericWriter<>(greId, new GreCustomizer(jvpp, ifcContext)),
+ ifcId);
+
+
final Set<InstanceIdentifier<?>> specificIfcTypes = Sets.newHashSet(vhostId, vxlanGpeId, vxlanGpeId, tapId);
// Ethernet(No dependency, customizer not finished TODO) =
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 e2fd01cd2..5b4450a91 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
@@ -7,6 +7,7 @@ import io.fd.honeycomb.translate.read.ReaderFactory;
import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
import io.fd.honeycomb.translate.v3po.interfacesstate.AclCustomizer;
import io.fd.honeycomb.translate.v3po.interfacesstate.EthernetCustomizer;
+import io.fd.honeycomb.translate.v3po.interfacesstate.GreCustomizer;
import io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceCustomizer;
import io.fd.honeycomb.translate.v3po.interfacesstate.L2Customizer;
import io.fd.honeycomb.translate.v3po.interfacesstate.TapCustomizer;
@@ -41,6 +42,9 @@ 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.state._interface.VxlanGpe;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.openvpp.jvpp.future.FutureJVpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Gre;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+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 {
@@ -141,6 +145,8 @@ public class InterfacesStateHoneycombReaderModule extends
registry.add(new GenericReader<>(vppIfcAugId.child(Vxlan.class), new VxlanCustomizer(jvpp, ifcCtx)));
// VxlanGpe
registry.add(new GenericReader<>(vppIfcAugId.child(VxlanGpe.class), new VxlanGpeCustomizer(jvpp, ifcCtx)));
+ // Gre
+ registry.add(new GenericReader<>(vppIfcAugId.child(Gre.class), new GreCustomizer(jvpp, ifcCtx)));
// L2
registry.add(new GenericReader<>(vppIfcAugId.child(L2.class), new L2Customizer(jvpp, ifcCtx, bdCtx)));
// Acl(Subtree)
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizerTest.java
new file mode 100644
index 000000000..cc4854de6
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/GreCustomizerTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po.interfaces;
+
+import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid;
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+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 static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.v3po.test.TestHelperUtils;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.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.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.GreBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.VppInvocationException;
+import org.openvpp.jvpp.dto.GreAddDelTunnel;
+import org.openvpp.jvpp.dto.GreAddDelTunnelReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+public class GreCustomizerTest {
+
+ private static final byte ADD_GRE = 1;
+ private static final byte DEL_GRE = 0;
+
+ @Mock
+ private FutureJVpp api;
+ @Mock
+ private WriteContext writeContext;
+ @Mock
+ private MappingContext mappingContext;
+
+ private GreCustomizer customizer;
+ private String ifaceName;
+ private InstanceIdentifier<Gre> id;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ InterfaceTypeTestUtils.setupWriteContext(writeContext,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.GreTunnel.class);
+ // TODO create base class for tests using vppApi
+ NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance");
+ final ModificationCache toBeReturned = new ModificationCache();
+ doReturn(toBeReturned).when(writeContext).getModificationCache();
+ doReturn(mappingContext).when(writeContext).getMappingContext();
+
+ customizer = new GreCustomizer(api, namingContext);
+
+ ifaceName = "eth0";
+ id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName))
+ .augmentation(VppInterfaceAugmentation.class).child(Gre.class);
+ }
+
+ private void whenGreAddDelTunnelThenSuccess()
+ throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException {
+ final CompletionStage<GreAddDelTunnelReply> replyCS = mock(CompletionStage.class);
+ final CompletableFuture<GreAddDelTunnelReply> replyFuture = mock(CompletableFuture.class);
+ when(replyCS.toCompletableFuture()).thenReturn(replyFuture);
+ final GreAddDelTunnelReply reply = new GreAddDelTunnelReply();
+ when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply);
+ when(api.greAddDelTunnel(any(GreAddDelTunnel.class))).thenReturn(replyCS);
+ }
+
+ /**
+ * Failure response send
+ */
+ private void whenGreAddDelTunnelThenFailure()
+ throws ExecutionException, InterruptedException, VppInvocationException {
+ doReturn(TestHelperUtils.<GreAddDelTunnelReply>createFutureException()).when(api)
+ .greAddDelTunnel(any(GreAddDelTunnel.class));
+ }
+
+ private GreAddDelTunnel verifyGreAddDelTunnelWasInvoked(final Gre gre) throws VppInvocationException {
+ ArgumentCaptor<GreAddDelTunnel> argumentCaptor = ArgumentCaptor.forClass(GreAddDelTunnel.class);
+ verify(api).greAddDelTunnel(argumentCaptor.capture());
+ final GreAddDelTunnel actual = argumentCaptor.getValue();
+ assertEquals(0, actual.isIpv6);
+ assertArrayEquals(InetAddresses.forString(gre.getSrc().getIpv4Address().getValue()).getAddress(),
+ actual.srcAddress);
+ assertArrayEquals(InetAddresses.forString(gre.getDst().getIpv4Address().getValue()).getAddress(),
+ actual.dstAddress);
+ assertEquals(gre.getOuterFibId().intValue(), actual.outerFibId);
+ return actual;
+ }
+
+ private void verifyGreAddWasInvoked(final Gre gre) throws VppInvocationException {
+ final GreAddDelTunnel actual = verifyGreAddDelTunnelWasInvoked(gre);
+ assertEquals(ADD_GRE, actual.isAdd);
+ }
+
+ private void verifyGreDeleteWasInvoked(final Gre gre) throws VppInvocationException {
+ final GreAddDelTunnel actual = verifyGreAddDelTunnelWasInvoked(gre);
+ assertEquals(DEL_GRE, actual.isAdd);
+ }
+
+ private static Gre generateGre(long vni) {
+ final GreBuilder builder = new GreBuilder();
+ builder.setSrc(new IpAddress(new Ipv4Address("192.168.20.10")));
+ builder.setDst(new IpAddress(new Ipv4Address("192.168.20.11")));
+ builder.setOuterFibId(Long.valueOf(123));
+ return builder.build();
+ }
+
+ private static Gre generateGre() {
+ return generateGre(Long.valueOf(11));
+ }
+
+ @Test
+ public void testWriteCurrentAttributes() throws Exception {
+ final Gre gre = generateGre();
+
+ whenGreAddDelTunnelThenSuccess();
+
+ doReturn(Optional.absent())
+ .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class));
+
+ customizer.writeCurrentAttributes(id, gre, writeContext);
+ verifyGreAddWasInvoked(gre);
+ verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
+ }
+
+ @Test
+ public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception {
+ final Gre gre = generateGre();
+
+ whenGreAddDelTunnelThenSuccess();
+ final Optional<Mapping> ifcMapping = getMapping(ifaceName, 0);
+
+ doReturn(Optional.of(new MappingsBuilder().setMapping(singletonList(ifcMapping.get())).build()))
+ .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class));
+
+ customizer.writeCurrentAttributes(id, gre, writeContext);
+ verifyGreAddWasInvoked(gre);
+
+ // Remove the first mapping before putting in the new one
+ verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance")));
+ verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(ifcMapping.get()));
+ }
+
+ @Test
+ public void testWriteCurrentAttributesFailed() throws Exception {
+ final Gre gre = generateGre();
+
+ whenGreAddDelTunnelThenFailure();
+
+ try {
+ customizer.writeCurrentAttributes(id, gre, writeContext);
+ } catch (WriteFailedException.CreateFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyGreAddWasInvoked(gre);
+ // Mapping not stored due to failure
+ verify(mappingContext, times(0)).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
+ return;
+ }
+ fail("WriteFailedException.CreateFailedException was expected");
+ }
+
+ @Test
+ public void testUpdateCurrentAttributes() throws Exception {
+ try {
+ customizer.updateCurrentAttributes(id, generateGre(10), generateGre(11), writeContext);
+ } catch (WriteFailedException.UpdateFailedException e) {
+ assertEquals(UnsupportedOperationException.class, e.getCause().getClass());
+ return;
+ }
+ fail("WriteFailedException.UpdateFailedException was expected");
+ }
+
+ @Test
+ public void testDeleteCurrentAttributes() throws Exception {
+ final Gre gre = generateGre();
+
+ whenGreAddDelTunnelThenSuccess();
+ doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance"));
+
+ customizer.deleteCurrentAttributes(id, gre, writeContext);
+ verifyGreDeleteWasInvoked(gre);
+ verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance")));
+ }
+
+ @Test
+ public void testDeleteCurrentAttributesaFailed() throws Exception {
+ final Gre gre = generateGre();
+
+ whenGreAddDelTunnelThenFailure();
+ doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance"));
+
+ try {
+ customizer.deleteCurrentAttributes(id, gre, writeContext);
+ } catch (WriteFailedException.DeleteFailedException e) {
+ assertTrue(e.getCause() instanceof VppBaseCallException);
+ verifyGreDeleteWasInvoked(gre);
+ verify(mappingContext, times(0)).delete(eq(getMappingIid(ifaceName, "test-instance")));
+ return;
+ }
+ fail("WriteFailedException.DeleteFailedException was expected");
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizerTest.java
new file mode 100644
index 000000000..8ac13e442
--- /dev/null
+++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/GreCustomizerTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po.interfacesstate;
+
+import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.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.VppInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.GreBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppInvocationException;
+import org.openvpp.jvpp.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.dto.GreTunnelDetails;
+import org.openvpp.jvpp.dto.GreTunnelDetailsReplyDump;
+import org.openvpp.jvpp.dto.GreTunnelDump;
+
+public class GreCustomizerTest extends ReaderCustomizerTest<Gre, GreBuilder> {
+
+ private NamingContext interfacesContext;
+ static final InstanceIdentifier<Gre> IID =
+ InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc1"))
+ .augmentation(VppInterfaceStateAugmentation.class).child(Gre.class);
+
+ public GreCustomizerTest() {
+ super(Gre.class);
+ }
+
+ @Override
+ public void setUpBefore() {
+ interfacesContext = new NamingContext("gre-tunnel", "test-instance");
+ doReturn(getMapping("ifc1", 0)).when(mappingContext).read(getMappingIid("ifc1", "test-instance"));
+
+ final SwInterfaceDetails v = new SwInterfaceDetails();
+ v.interfaceName = "gre-tunnel4".getBytes();
+ final Map<Integer, SwInterfaceDetails> map = new HashMap<>();
+ map.put(0, v);
+ cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map);
+ }
+
+ @Override
+ protected void setUpAfter() throws UnknownHostException, VppInvocationException {
+ final CompletableFuture<GreTunnelDetailsReplyDump> greTunnelDetailsReplyDumpCompletionStage =
+ new CompletableFuture<>();
+
+ final GreTunnelDetailsReplyDump value = new GreTunnelDetailsReplyDump();
+ final GreTunnelDetails greTunnelDetails = new GreTunnelDetails();
+ greTunnelDetails.isIpv6 = 0;
+ greTunnelDetails.dstAddress = InetAddress.getByName("1.2.3.4").getAddress();
+ greTunnelDetails.srcAddress = InetAddress.getByName("1.2.3.5").getAddress();
+ greTunnelDetails.outerFibId = 55;
+ greTunnelDetails.swIfIndex = 0;
+
+ value.greTunnelDetails = Lists.newArrayList(greTunnelDetails);
+ greTunnelDetailsReplyDumpCompletionStage.complete(value);
+
+ doReturn(greTunnelDetailsReplyDumpCompletionStage).when(api).greTunnelDump(any(GreTunnelDump.class));
+ }
+
+ @Test
+ public void testReadCurrentAttributes() throws Exception {
+ final GreBuilder builder = getCustomizer().getBuilder(IID);
+ getCustomizer().readCurrentAttributes(IID, builder, ctx);
+
+ assertEquals(55, builder.getOuterFibId().intValue());
+
+ assertNull(builder.getSrc().getIpv6Address());
+ assertNotNull(builder.getSrc().getIpv4Address());
+ assertEquals("1.2.3.5", builder.getSrc().getIpv4Address().getValue());
+
+ assertNull(builder.getDst().getIpv6Address());
+ assertNotNull(builder.getDst().getIpv4Address());
+ assertEquals("1.2.3.4", builder.getDst().getIpv4Address().getValue());
+
+ verify(api).greTunnelDump(any(GreTunnelDump.class));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testReadCurrentAttributesVppNameNotCached() throws Exception {
+ InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0);
+
+ final GreBuilder builder = getCustomizer().getBuilder(IID);
+ getCustomizer().readCurrentAttributes(IID, builder, ctx);
+ }
+
+ @Test
+ public void testReadCurrentAttributesWrongType() throws Exception {
+ final SwInterfaceDetails v = new SwInterfaceDetails();
+ v.interfaceName = "tap-2".getBytes();
+ InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v);
+
+ final GreBuilder builder = getCustomizer().getBuilder(IID);
+ getCustomizer().readCurrentAttributes(IID, builder, ctx);
+
+ // Should be ignored
+ verifyZeroInteractions(api);
+ }
+
+ @Override
+ protected ReaderCustomizer<Gre, GreBuilder> initCustomizer() {
+ return new GreCustomizer(api, interfacesContext);
+ }
+} \ No newline at end of file