From aa3fb2c1271c948f9a3c5a4ab22ce146be13163e Mon Sep 17 00:00:00 2001 From: Jan Srnicek Date: Wed, 31 Aug 2016 07:46:41 +0200 Subject: HONEYCOMB-75 - Lisp implemetation Rebased on final minimal distro Change-Id: Ib71fc59e62dda4633f4f79c5c7417a4aaf02a177 Signed-off-by: Jan Srnicek Signed-off-by: Florin Coras Signed-off-by: Maros Marsalek --- vpp-common/vpp-translate-utils/pom.xml | 5 + .../translate/v3po/util/TranslateUtils.java | 268 +++++++++++++++++++++ .../v3po/util/cache/EntityDumpExecutor.java | 2 + .../translate/v3po/util/TranslateUtilsTest.java | 61 +++++ 4 files changed, 336 insertions(+) (limited to 'vpp-common') diff --git a/vpp-common/vpp-translate-utils/pom.xml b/vpp-common/vpp-translate-utils/pom.xml index 32466c2e1..789338fcb 100644 --- a/vpp-common/vpp-translate-utils/pom.xml +++ b/vpp-common/vpp-translate-utils/pom.xml @@ -74,6 +74,11 @@ data-api ${project.version} + + commons-codec + commons-codec + 1.9 + diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java index 0902064eb..95b07743f 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java @@ -17,6 +17,8 @@ package io.fd.honeycomb.translate.v3po.util; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import com.google.common.base.Splitter; import com.google.common.net.InetAddresses; @@ -28,10 +30,21 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; +import java.util.stream.Collectors; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringUtils; +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.IpPrefix; +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.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +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.inet.types.rev130715.Ipv6AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.openvpp.jvpp.VppBaseCallException; import org.openvpp.jvpp.dto.JVppReply; @@ -102,6 +115,236 @@ public final class TranslateUtils { } } + public static final byte[] ipAddressToArray(IpAddress address) { + checkNotNull(address, "Cannot resolve null adddress"); + + if (isIpv6(address)) { + return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(address.getIpv6Address())); + } else { + return ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(address.getIpv4Address())); + } + } + + /** + * Creates address array from address part of {@link Ipv4Prefix} + */ + public static byte[] ipv4AddressPrefixToArray(@Nonnull final Ipv4Prefix ipv4Prefix) { + checkNotNull(ipv4Prefix, "Cannot convert null prefix"); + + byte[] retval = new byte[4]; + String[] address = ipv4Prefix.getValue().substring(0, ipv4Prefix.getValue().indexOf('/')).split("\\."); + + for (int d = 0; d < 4; d++) { + retval[d] = (byte) (Short.parseShort(address[d]) & 0xff); + } + return retval; + } + + /** + * Converts {@link IpAddress} to array representing {@link Ipv4Address} or {@link Ipv6Address} + */ + public static byte[] ipAddressToArray(boolean isIpv6, @Nonnull IpAddress address) { + checkNotNull(address, "Cannot convert null Address"); + + if (isIpv6) { + return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(address.getIpv6Address())); + } else { + return ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(address.getIpv4Address())); + } + } + + /** + * Converts array bytes to {@link IpAddress} + */ + @Nonnull + public static IpAddress arrayToIpAddress(boolean isIpv6, byte[] ip) { + if (isIpv6) { + return new IpAddress(arrayToIpv6AddressNoZone(ip)); + } else { + return new IpAddress(arrayToIpv4AddressNoZone(ip)); + } + } + + /** + * Extracts {@link Ipv4Prefix} prefix + */ + public static byte extractPrefix(Ipv4Prefix data) { + checkNotNull(data, "Cannot extract from null"); + + return Byte.valueOf(data.getValue().substring(data.getValue().indexOf('/') + 1)); + } + + /** + * Converts byte array to {@link Ipv4Prefix} with specified prefixLength + */ + public static Ipv4Prefix arrayToIpv4Prefix(final byte[] address, byte prefixLength) { + Ipv4AddressNoZone addressPart = arrayToIpv4AddressNoZone(address); + + return new Ipv4Prefix(addressPart.getValue().concat("/").concat(String.valueOf(prefixLength))); + } + + /** + * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order + * as the address. + * + * @return byte array with address bytes + */ + public static byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) { + byte[] retval = new byte[16]; + + //splits address and add ommited zeros for easier parsing + List segments = Arrays.asList(ipv6Addr.getValue().split(":")) + .stream() + .map(segment -> StringUtils.repeat('0',4-segment.length())+segment) + .collect(Collectors.toList()); + + byte index = 0; + for (String segment : segments) { + + String firstPart =segment.substring(0, 2); + String secondPart = segment.substring(2); + + //first part should be ommited + if("00".equals(firstPart)){ + index++; + }else{ + retval[index++] = ((byte) Short.parseShort(firstPart, 16)); + } + + retval[index++] = ((byte) Short.parseShort(secondPart, 16)); + } + + return retval; + } + + /** + * Creates address array from address part of {@link Ipv6Prefix} + */ + public static byte[] ipv6AddressPrefixToArray(@Nonnull final Ipv6Prefix ipv4Prefix) { + checkNotNull(ipv4Prefix, "Cannot convert null prefix"); + + return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone( + new Ipv6Address(ipv4Prefix.getValue().substring(0, ipv4Prefix.getValue().indexOf('/'))))); + } + + /** + * Extracts {@link Ipv6Prefix} prefix + */ + public static byte extractPrefix(Ipv6Prefix data) { + checkNotNull(data, "Cannot extract from null"); + + return Byte.valueOf(data.getValue().substring(data.getValue().indexOf('/') + 1)); + } + + /** + * Converts byte array to {@link Ipv6Prefix} with specified prefixLength + */ + public static Ipv6Prefix arrayToIpv6Prefix(final byte[] address, byte prefixLength) { + Ipv6AddressNoZone addressPart = arrayToIpv6AddressNoZone(address); + + return new Ipv6Prefix(addressPart.getValue().concat("/").concat(String.valueOf(prefixLength))); + } + + /** + * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in reversed order. + * + * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No + * change in order. + */ + @Nonnull + public static Ipv6AddressNoZone arrayToIpv6AddressNoZone(@Nonnull byte[] ip) { + checkArgument(ip.length == 16, "Illegal array length"); + + try { + return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Unable to parse ipv6", e); + } + } + + + /** + * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in natural order. + * + * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No + * change in order. + */ + @Nonnull + public static Ipv6AddressNoZone arrayToIpv6AddressNoZoneReversed(@Nonnull byte[] ip) { + checkArgument(ip.length == 16, "Illegal array length"); + + ip = reverseBytes(ip); + + try { + return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Unable to parse ipv6", e); + } + } + + /** + * Converts byte array to address string ,not separated with ":" + */ + public static String byteArrayToMacUnseparated(byte[] address) { + checkArgument(address.length == 6, "Illegal array length"); + return Hex.encodeHexString(address); + } + + /** + * Converts byte array to address string ,separated with ":" + */ + public static String byteArrayToMacSeparated(byte[] address) { + checkArgument(address.length == 6, "Illegal array length"); + + String unseparatedAddress = Hex.encodeHexString(address); + String separated = ""; + + for (int i = 0; i < unseparatedAddress.length(); i = i + 2) { + if (i == (unseparatedAddress.length() - 2)) { + separated = separated + unseparatedAddress.substring(0 + i, 2 + i); + } else { + separated = separated + unseparatedAddress.substring(0 + i, 2 + i) + ":"; + } + } + + return separated; + } + + /** + * Converts MAC string to byte array + * */ + public static byte[] macToByteArray(String mac){ + checkNotNull(mac,"MAC cannot be null"); + + mac = mac.replace(":",""); + + try { + return Hex.decodeHex(mac.toCharArray()); + } catch (DecoderException e) { + throw new IllegalArgumentException("Unable to convert mac",e); + } + } + + /** + * Detects whether {@code IpAddress} is ipv6 + */ + public static boolean isIpv6(IpAddress address) { + checkNotNull(address, "Address cannot be null"); + + checkState(!(address.getIpv4Address() == null && address.getIpv6Address() == null), "Invalid address"); + return address.getIpv6Address() != null; + } + + /** + * Detects whether {@code IpPrefix} is ipv6 + */ + public static boolean isIpv6(IpPrefix address) { + checkNotNull(address, "Address cannot be null"); + checkState(!(address.getIpv4Prefix() == null && address.getIpv6Prefix() == null), "Invalid address"); + return address.getIpv6Prefix() != null; + } + + /** * Transform Ipv4 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order * as the address. @@ -143,6 +386,31 @@ public final class TranslateUtils { } } + /** + * Parse byte array returned by VPP representing an Ipv4 address. Vpp returns IP byte arrays in reversed order. + * + * @return Ipv4AddressNoZone containing string representation of IPv4 address constructed from submitted bytes. No + * change in order. + */ + @Nonnull + public static Ipv4AddressNoZone arrayToIpv4AddressNoZoneReversed(@Nonnull byte[] ip) { + // VPP sends ipv4 in a 16 byte array + + if (ip.length == 16) { + ip = Arrays.copyOfRange(ip, 0, 4); + } + + ip = reverseBytes(ip); + + try { + // Not reversing the byte array here!! because the IP coming from VPP is in reversed byte order + // compared to byte order it was submitted + return new Ipv4AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Unable to parse ipv4", e); + } + } + /** * Return (interned) string from byte array while removing \u0000. Strings represented as fixed length byte[] from * vpp contain \u0000. diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/EntityDumpExecutor.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/EntityDumpExecutor.java index 8f3ae5596..5bc2a4b77 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/EntityDumpExecutor.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/EntityDumpExecutor.java @@ -26,6 +26,8 @@ import javax.annotation.concurrent.ThreadSafe; @ThreadSafe public interface EntityDumpExecutor { + static Void NO_PARAMS = null; + /** * Performs dump on {@link T} entity * diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java index d9cb52f3a..a55c3053a 100644 --- a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java +++ b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java @@ -15,6 +15,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.Test; 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.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -134,4 +137,62 @@ public class TranslateUtilsTest { TranslateUtils.byteToBoolean((byte) 123); } + @Test + public void testIpv6NoZone(){ + final Ipv6AddressNoZone ipv6Addr = new Ipv6AddressNoZone("3ffe:1900:4545:3:200:f8ff:fe21:67cf"); + byte[] bytes = TranslateUtils.ipv6AddressNoZoneToArray(ipv6Addr); + assertEquals((byte)63,bytes[0]); + + bytes = reverseBytes(bytes); + final Ipv6AddressNoZone ivp6AddressNoZone = TranslateUtils.arrayToIpv6AddressNoZone(bytes); + assertEquals(ipv6Addr,ivp6AddressNoZone); + } + + @Test + public void testByteArrayToMacUnseparated(){ + byte[] address = TranslateUtils.parseMac("aa:bb:cc:dd:ee:ff"); + + String converted = TranslateUtils.byteArrayToMacUnseparated(address); + + assertEquals("aabbccddeeff",converted); + } + + @Test + public void testByteArrayToMacSeparated(){ + byte[] address = TranslateUtils.parseMac("aa:bb:cc:dd:ee:ff"); + + String converted = TranslateUtils.byteArrayToMacSeparated(address); + + assertEquals("aa:bb:cc:dd:ee:ff",converted); + } + + @Test(expected = IllegalArgumentException.class) + public void testByteArrayToMacUnseparatedIllegal(){ + TranslateUtils.byteArrayToMacUnseparated(new byte[]{54,26,87,32,14}); + } + + @Test(expected = IllegalArgumentException.class) + public void testByteArrayToMacSeparatedIllegal() { + TranslateUtils.byteArrayToMacSeparated(new byte[]{54, 26, 87, 32, 14}); + } + + @Test + public void testIpv4AddressPrefixToArray() { + byte[] ip = TranslateUtils.ipv4AddressPrefixToArray(new Ipv4Prefix("192.168.2.1/24")); + + assertEquals("1.2.168.192", TranslateUtils.arrayToIpv4AddressNoZone(ip).getValue()); + } + + @Test + public void testIpv6AddressPrefixToArray() { + byte[] ip = TranslateUtils.ipv6AddressPrefixToArray(new Ipv6Prefix("3ffe:1900:4545:3:200:f8ff:fe21:67cf/48")); + + assertEquals("cf67:21fe:fff8:2:300:4545:19:fe3f", TranslateUtils.arrayToIpv6AddressNoZone(ip).getValue()); + } + + @Test + public void testExtractPrefix() { + assertEquals(24, TranslateUtils.extractPrefix(new Ipv4Prefix("192.168.2.1/24"))); + assertEquals(48, TranslateUtils.extractPrefix(new Ipv6Prefix("3ffe:1900:4545:3:200:f8ff:fe21:67cf/48"))); + } } \ No newline at end of file -- cgit 1.2.3-korg