summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2017-08-22 14:33:22 +0200
committerMarek Gradzki <mgradzki@cisco.com>2017-08-28 11:02:30 +0200
commit29456ce94c09768405c31f8fb315425b3c98638f (patch)
tree435c6dcd845ce5e5a9d335d9792baec1dc473aa6
parent3cd34066949aa503d4e440345be829f0c05fbd35 (diff)
HC2VPP-105: nat64 prefix configuration
Change-Id: I205fb426ab9c0e47ef40b81c2f6dcd397524f1eb Signed-off-by: Marek Gradzki <mgradzki@cisco.com> Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizer.java103
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/NatWriterFactory.java10
-rw-r--r--nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizerTest.java99
3 files changed, 212 insertions, 0 deletions
diff --git a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizer.java
new file mode 100644
index 000000000..b62733e75
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017 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.hc2vpp.nat.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.Ipv6Translator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.nat.dto.Nat64AddDelPrefix;
+import io.fd.vpp.jvpp.nat.future.FutureJVppNatFacade;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64Prefixes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64PrefixesKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.nat64.prefixes.DestinationIpv4Prefix;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class Nat64PrefixesCustomizer
+ implements ListWriterCustomizer<Nat64Prefixes, Nat64PrefixesKey>, ByteDataTranslator, Ipv6Translator,
+ JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Nat64PrefixesCustomizer.class);
+
+ private final FutureJVppNatFacade jvppNat;
+
+ Nat64PrefixesCustomizer(final FutureJVppNatFacade jvppNat) {
+ this.jvppNat = checkNotNull(jvppNat, "jvppNat should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Nat64Prefixes> id,
+ @Nonnull final Nat64Prefixes dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final int natInstanceId = id.firstKeyOf(NatInstance.class).getId().intValue();
+ LOG.debug("Configuring nat64 prefix: {} for nat-instance(vrf): {}", dataAfter, natInstanceId);
+
+ // VPP supports only single nat64-prefix per VRF/nat-instance (we map nat-instances to VRFs)
+ // To ensure that (and for simplicity), we require nat64-prefix-id = 0.
+ final Long nat64PrefixId = id.firstKeyOf(Nat64Prefixes.class).getNat64PrefixId();
+ checkArgument(nat64PrefixId == 0, "Only single nat64 prefix is supported (expected id=0, but %s given)",
+ nat64PrefixId);
+
+ // VPP does not support configuring different nat64-prefixes depending on ipv4 destination prefix:
+ final List<DestinationIpv4Prefix> destinationIpv4PrefixList = dataAfter.getDestinationIpv4Prefix();
+ checkArgument(destinationIpv4PrefixList == null || destinationIpv4PrefixList.isEmpty(),
+ "destination-ipv4-prefix is not supported by VPP");
+
+ addDelPrefix(id, dataAfter, natInstanceId, true);
+ LOG.debug("Nat64 prefix written successfully: {} for nat-instance(vrf): {}", dataAfter, natInstanceId);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Nat64Prefixes> id,
+ @Nonnull final Nat64Prefixes dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final int natInstanceId = id.firstKeyOf(NatInstance.class).getId().intValue();
+ LOG.debug("Removing nat64 prefix configuration: {} for nat-instance(vrf): {}", dataBefore, natInstanceId);
+ // No need for validation here (it was done on write)
+ addDelPrefix(id, dataBefore, natInstanceId, false);
+ LOG.debug("Nat64 prefix removed successfully: {} for nat-instance(vrf): {}", dataBefore, natInstanceId);
+
+ }
+
+ private void addDelPrefix(@Nonnull final InstanceIdentifier<Nat64Prefixes> id, @Nonnull final Nat64Prefixes data,
+ final int vrfId, final boolean isAdd)
+ throws WriteFailedException {
+
+ // The nat64-prefix is optional in ietf-nat, but we require it
+ final Ipv6Prefix nat64Prefix = data.getNat64Prefix();
+ checkArgument(nat64Prefix != null, "Missing nat64-prefix leaf value.");
+
+ final Nat64AddDelPrefix request = new Nat64AddDelPrefix();
+ request.prefix = ipv6AddressPrefixToArray(nat64Prefix);
+ request.prefixLen = extractPrefix(nat64Prefix);
+ request.isAdd = booleanToByte(isAdd);
+ request.vrfId = vrfId;
+ getReplyForWrite(jvppNat.nat64AddDelPrefix(request).toCompletableFuture(), id);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/NatWriterFactory.java b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/NatWriterFactory.java
index e315da637..764da68b8 100644
--- a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/NatWriterFactory.java
+++ b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/NatWriterFactory.java
@@ -32,6 +32,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev1509
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64Prefixes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.nat64.prefixes.DestinationIpv4Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nat.rev170804.ExternalIpAddressPoolConfigAugmentation;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -45,6 +47,8 @@ public final class NatWriterFactory implements WriterFactory {
NAT_CFG_ID.child(NatInstances.class).child(NatInstance.class);
private static final InstanceIdentifier<MappingEntry> MAP_ENTRY_ID =
NAT_INSTANCE_ID.child(MappingTable.class).child(MappingEntry.class);
+ private static final InstanceIdentifier<Nat64Prefixes> NAT64_PREFIXES =
+ NAT_INSTANCE_ID.child(Nat64Prefixes.class);
private final FutureJVppNatFacade jvppNat;
private final MappingEntryContext mappingEntryContext;
@@ -73,5 +77,11 @@ public final class NatWriterFactory implements WriterFactory {
new GenericListWriter<>(NAT_INSTANCE_ID.child(ExternalIpAddressPool.class),
new ExternalIpPoolCustomizer(jvppNat)),
MAP_ENTRY_ID);
+
+ // nat64-prefixes
+ registry.subtreeAdd(
+ Sets.newHashSet(InstanceIdentifier.create(Nat64Prefixes.class).child(DestinationIpv4Prefix.class)),
+ new GenericListWriter<>(NAT_INSTANCE_ID.child(Nat64Prefixes.class),
+ new Nat64PrefixesCustomizer(jvppNat)));
}
}
diff --git a/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizerTest.java b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizerTest.java
new file mode 100644
index 000000000..63a3b4673
--- /dev/null
+++ b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/Nat64PrefixesCustomizerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017 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.hc2vpp.nat.write;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.vpp.jvpp.nat.dto.Nat64AddDelPrefix;
+import io.fd.vpp.jvpp.nat.dto.Nat64AddDelPrefixReply;
+import io.fd.vpp.jvpp.nat.future.FutureJVppNatFacade;
+import java.util.Collections;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatConfig;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstances;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64Prefixes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64PrefixesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.Nat64PrefixesKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.nat64.prefixes.DestinationIpv4Prefix;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class Nat64PrefixesCustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+
+ private static final long VRF_ID = 123;
+
+ private static final InstanceIdentifier<NatInstance> NAT_INSTANCE_ID =
+ InstanceIdentifier.create(NatConfig.class).child(NatInstances.class).child(NatInstance.class, new NatInstanceKey(VRF_ID));
+
+ private static final Nat64Prefixes VALID_DATA = new Nat64PrefixesBuilder().setNat64Prefix(new Ipv6Prefix("2001:db8::/32")).build();
+
+ @Mock
+ private FutureJVppNatFacade jvppNat;
+
+ private Nat64PrefixesCustomizer customizer;
+
+ @Override
+ protected void setUpTest() throws Exception {
+ customizer = new Nat64PrefixesCustomizer(jvppNat);
+ when(jvppNat.nat64AddDelPrefix(any())).thenReturn(future(new Nat64AddDelPrefixReply()));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWriteNonZeroPrefixIdFails() throws Exception {
+ customizer.writeCurrentAttributes(getID(1), mock(Nat64Prefixes.class), writeContext);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWriteDestinationPrefixFails() throws Exception {
+ final Nat64Prefixes data = mock(Nat64Prefixes.class);
+ when(data.getDestinationIpv4Prefix()).thenReturn(Collections.singletonList(mock(DestinationIpv4Prefix.class)));
+ customizer.writeCurrentAttributes(getID(1), data, writeContext);
+ }
+
+ @Test
+ public void testWrite() throws Exception {
+ customizer.writeCurrentAttributes(getID(0), VALID_DATA, writeContext);
+ verify(jvppNat).nat64AddDelPrefix(expectedRequest(true));
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ customizer.deleteCurrentAttributes(getID(0), VALID_DATA, writeContext);
+ verify(jvppNat).nat64AddDelPrefix(expectedRequest(false));
+ }
+
+ private static InstanceIdentifier<Nat64Prefixes> getID(final long prefixId) {
+ return NAT_INSTANCE_ID.child(Nat64Prefixes.class, new Nat64PrefixesKey(prefixId));
+ }
+
+ private Nat64AddDelPrefix expectedRequest(final boolean isAdd) {
+ final Nat64AddDelPrefix request = new Nat64AddDelPrefix();
+ request.isAdd = booleanToByte(isAdd);
+ request.vrfId = (int) VRF_ID;
+ request.prefix = new byte[]{0x20, 0x01, 0x0d, (byte) 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ request.prefixLen = 32;
+ return request;
+ }
+} \ No newline at end of file