From 8b051e21ed6e4e4c24415c40fd0b6c6b684c071d Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 15 Aug 2017 14:04:51 +0200 Subject: HC2VPP-105: add support for nat64 pool configuration Change-Id: I5e57b7855e081056ad0d675084209fc9cd4add23 Signed-off-by: Marek Gradzki --- .../hc2vpp/nat/write/ExternalIpPoolCustomizer.java | 51 ++++++++++++++----- .../io/fd/hc2vpp/nat/write/NatWriterFactory.java | 6 ++- .../io/fd/hc2vpp/nat/NatTestSchemaContext.java | 4 +- .../nat/write/ExternalIpPoolCustomizerTest.java | 57 +++++++++++++++++----- .../src/test/resources/nat64/external-ip-pool.json | 13 +++++ 5 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 nat/nat2vpp/src/test/resources/nat64/external-ip-pool.json diff --git a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizer.java index 61fedbd48..62331620d 100644 --- a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizer.java +++ b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizer.java @@ -17,13 +17,16 @@ package io.fd.hc2vpp.nat.write; import static com.google.common.base.Preconditions.checkArgument; +import static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nat.rev170804.NatPoolType.Nat64; -import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; import io.fd.hc2vpp.common.translate.util.Ipv4AddressRange; import io.fd.hc2vpp.common.translate.util.Ipv4Translator; 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.snat.dto.Nat64AddDelPoolAddrRange; import io.fd.vpp.jvpp.snat.dto.SnatAddAddressRange; import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade; import javax.annotation.Nonnull; @@ -31,12 +34,13 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. 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.ExternalIpAddressPool; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPoolKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nat.rev170804.ExternalIpAddressPoolConfigAugmentation; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class ExternalIpPoolCustomizer implements ListWriterCustomizer, - JvppReplyConsumer, Ipv4Translator { + JvppReplyConsumer, Ipv4Translator, ByteDataTranslator { private static final Logger LOG = LoggerFactory.getLogger(ExternalIpPoolCustomizer.class); @@ -54,8 +58,7 @@ final class ExternalIpPoolCustomizer implements ListWriterCustomizer id, + @Nonnull final ExternalIpAddressPool addressPool, + final boolean isAdd) throws WriteFailedException { + boolean isNat64 = false; + final ExternalIpAddressPoolConfigAugmentation augmentation = + addressPool.getAugmentation(ExternalIpAddressPoolConfigAugmentation.class); + if (augmentation != null) { + isNat64 = Nat64.equals(augmentation.getPoolType()); + } + if (isNat64) { + final Nat64AddDelPoolAddrRange request = getNat64Request(addressPool.getExternalIpPool(), isAdd); + getReplyForWrite(jvppSnat.nat64AddDelPoolAddrRange(request).toCompletableFuture(), id); + } else { + final SnatAddAddressRange request = getNat44Request(addressPool.getExternalIpPool(), isAdd); + getReplyForWrite(jvppSnat.snatAddAddressRange(request).toCompletableFuture(), id); + } + } + + private SnatAddAddressRange getNat44Request(final Ipv4Prefix externalIpPool, boolean isAdd) { + final SnatAddAddressRange request = new SnatAddAddressRange(); final Ipv4AddressRange range = Ipv4AddressRange.fromPrefix(externalIpPool); - LOG.trace("Handling address range: {}", range); + LOG.trace("Handling NAT44 address range: {}", range); request.isIp4 = 1; - request.isAdd = (byte) (isAdd ? 1 : 0); + request.isAdd = booleanToByte(isAdd); request.firstIpAddress = ipv4AddressNoZoneToArray(range.getStart()); request.lastIpAddress = ipv4AddressNoZoneToArray(range.getEnd()); return request; } + + private Nat64AddDelPoolAddrRange getNat64Request(final Ipv4Prefix externalIpPool, boolean isAdd) { + final Nat64AddDelPoolAddrRange request = new Nat64AddDelPoolAddrRange(); + final Ipv4AddressRange range = Ipv4AddressRange.fromPrefix(externalIpPool); + LOG.trace("Handling NAT64 address range: {}", range); + request.isAdd = booleanToByte(isAdd); + request.startAddr = ipv4AddressNoZoneToArray(range.getStart()); + request.endAddr = ipv4AddressNoZoneToArray(range.getEnd()); + return request; + } } 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 e239721d4..ef2a2afdd 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,7 @@ 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.opendaylight.params.xml.ns.yang.vpp.nat.rev170804.ExternalIpAddressPoolConfigAugmentation; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** @@ -66,7 +67,10 @@ public final class NatWriterFactory implements WriterFactory { // External address pool has to be executed before mapping entry. Because adding mapping entries requires to // already have an IP range predefined ... in some cases - registry.addBefore(new GenericListWriter<>(NAT_INSTANCE_ID.child(ExternalIpAddressPool.class), + registry.subtreeAddBefore( + Sets.newHashSet(InstanceIdentifier.create(ExternalIpAddressPool.class) + .augmentation(ExternalIpAddressPoolConfigAugmentation.class)), + new GenericListWriter<>(NAT_INSTANCE_ID.child(ExternalIpAddressPool.class), new ExternalIpPoolCustomizer(jvppSnat)), MAP_ENTRY_ID); } diff --git a/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/NatTestSchemaContext.java b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/NatTestSchemaContext.java index 8a30df277..041096f88 100644 --- a/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/NatTestSchemaContext.java +++ b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/NatTestSchemaContext.java @@ -34,7 +34,9 @@ public interface NatTestSchemaContext { .getInstance(), org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.$YangModuleInfoImpl .getInstance(), - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170801.$YangModuleInfoImpl + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.nat.rev170804.$YangModuleInfoImpl + .getInstance(), + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev170801.$YangModuleInfoImpl .getInstance())); return context; } diff --git a/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizerTest.java b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizerTest.java index e2db427a5..8f25bfa12 100644 --- a/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizerTest.java +++ b/nat/nat2vpp/src/test/java/io/fd/hc2vpp/nat/write/ExternalIpPoolCustomizerTest.java @@ -22,10 +22,13 @@ 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.hc2vpp.nat.NatTestSchemaContext; import io.fd.honeycomb.test.tools.HoneycombTestRunner; import io.fd.honeycomb.test.tools.annotations.InjectTestData; import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.snat.dto.Nat64AddDelPoolAddrRange; +import io.fd.vpp.jvpp.snat.dto.Nat64AddDelPoolAddrRangeReply; import io.fd.vpp.jvpp.snat.dto.SnatAddAddressRange; import io.fd.vpp.jvpp.snat.dto.SnatAddAddressRangeReply; import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade; @@ -41,7 +44,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev1509 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @RunWith(HoneycombTestRunner.class) -public class ExternalIpPoolCustomizerTest extends WriterCustomizerTest implements NatTestSchemaContext { +public class ExternalIpPoolCustomizerTest extends WriterCustomizerTest implements NatTestSchemaContext, + ByteDataTranslator { private static final long NAT_INSTANCE_ID = 0; private static final long POOL_ID = 22; @@ -59,43 +63,70 @@ public class ExternalIpPoolCustomizerTest extends WriterCustomizerTest implement public void setUpTest() { customizer = new ExternalIpPoolCustomizer(jvppSnat); when(jvppSnat.snatAddAddressRange(any())).thenReturn(future(new SnatAddAddressRangeReply())); + when(jvppSnat.nat64AddDelPoolAddrRange(any())).thenReturn(future(new Nat64AddDelPoolAddrRangeReply())); } @Test - public void testWrite( - @InjectTestData(resourcePath = "/nat44/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) - throws WriteFailedException { + public void testWriteNat44( + @InjectTestData(resourcePath = "/nat44/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) + throws WriteFailedException { customizer.writeCurrentAttributes(IID, extractIpPool(data), writeContext); - final SnatAddAddressRange expectedRequest = getExpectedRequest(); - expectedRequest.isAdd = 1; + final SnatAddAddressRange expectedRequest = getExpectedRequestNat44(true); verify(jvppSnat).snatAddAddressRange(expectedRequest); } - @Test(expected = UnsupportedOperationException.class) - public void testUpdate() throws WriteFailedException { + @Test + public void testWriteNat64( + @InjectTestData(resourcePath = "/nat64/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) + throws WriteFailedException { + customizer.writeCurrentAttributes(IID, extractIpPool(data), writeContext); + final Nat64AddDelPoolAddrRange expectedRequest = getExpectedRequestNat64(true); + verify(jvppSnat).nat64AddDelPoolAddrRange(expectedRequest); + } + + @Test(expected = UnsupportedOperationException.class) + public void testUpdateNat44() throws WriteFailedException { final ExternalIpAddressPool data = mock(ExternalIpAddressPool.class); customizer.updateCurrentAttributes(IID, data, data, writeContext); } @Test - public void testDelete( - @InjectTestData(resourcePath = "/nat44/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) - throws WriteFailedException { + public void testDeleteNat44( + @InjectTestData(resourcePath = "/nat44/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) + throws WriteFailedException { customizer.deleteCurrentAttributes(IID, extractIpPool(data), writeContext); - final SnatAddAddressRange expectedRequest = getExpectedRequest(); + final SnatAddAddressRange expectedRequest = getExpectedRequestNat44(false); verify(jvppSnat).snatAddAddressRange(expectedRequest); } + @Test + public void testDeleteNat64( + @InjectTestData(resourcePath = "/nat64/external-ip-pool.json", id = NAT_INSTANCES_PATH) NatInstances data) + throws WriteFailedException { + customizer.deleteCurrentAttributes(IID, extractIpPool(data), writeContext); + final Nat64AddDelPoolAddrRange expectedRequest = getExpectedRequestNat64(false); + verify(jvppSnat).nat64AddDelPoolAddrRange(expectedRequest); + } + private static ExternalIpAddressPool extractIpPool(NatInstances data) { // assumes single nat instance and single ip pool return data.getNatInstance().get(0).getExternalIpAddressPool().get(0); } - private static SnatAddAddressRange getExpectedRequest() { + private SnatAddAddressRange getExpectedRequestNat44(final boolean isAdd) { final SnatAddAddressRange expectedRequest = new SnatAddAddressRange(); + expectedRequest.isAdd = booleanToByte(isAdd); expectedRequest.isIp4 = 1; expectedRequest.firstIpAddress = new byte[] {(byte) 192, (byte) 168, 1, 0}; expectedRequest.lastIpAddress = new byte[] {(byte) 192, (byte) 168, 1, (byte) 255}; return expectedRequest; } + + private Nat64AddDelPoolAddrRange getExpectedRequestNat64(final boolean isAdd) { + final Nat64AddDelPoolAddrRange expectedRequest = new Nat64AddDelPoolAddrRange(); + expectedRequest.isAdd = booleanToByte(isAdd); + expectedRequest.startAddr = new byte[] {(byte) 192, (byte) 168, 1, 0}; + expectedRequest.endAddr = new byte[] {(byte) 192, (byte) 168, 1, (byte) 255}; + return expectedRequest; + } } \ No newline at end of file diff --git a/nat/nat2vpp/src/test/resources/nat64/external-ip-pool.json b/nat/nat2vpp/src/test/resources/nat64/external-ip-pool.json new file mode 100644 index 000000000..3be25d299 --- /dev/null +++ b/nat/nat2vpp/src/test/resources/nat64/external-ip-pool.json @@ -0,0 +1,13 @@ +{ + "nat-instances" : { + "nat-instance" : { + "id" : 0, + "external-ip-address-pool": { + "pool-id": 22, + "external-ip-pool": "192.168.1.1/24", + "vpp-nat:pool-type": "nat64" + } + } + } +} + -- cgit 1.2.3-korg