BUG-2825: introduce Ipv4 prefix parser for short bytes 22/35422/2
authorRobert Varga <robert.varga@pantheon.sk>
Thu, 25 Feb 2016 20:42:44 +0000 (21:42 +0100)
committerRobert Varga <robert.varga@pantheon.sk>
Thu, 25 Feb 2016 21:32:51 +0000 (22:32 +0100)
BGP uses a short encoding schema, where they have only partial byte
array. Add support for parsing such short byte arrays, padding the tail
with zeros.

Change-Id: Ib4ce202256d26b1cbee23e05320d8cef6f729257
Signed-off-by: Robert Varga <robert.varga@pantheon.sk>
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/StringValueObjectFactory.java
model/ietf/ietf-type-util/src/main/java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfInetUtil.java

index 8cf66c2512491ec3b553d0d47afb73ab7c75fc29..0955681442dc9e1bfae79201ffd23bc63f9a0dfd 100644 (file)
@@ -41,9 +41,11 @@ public final class StringValueObjectFactory<T> {
 
     private final MethodHandle constructor;
     private final MethodHandle setter;
+    private final T template;
 
-    private StringValueObjectFactory(final MethodHandle constructor, final MethodHandle setter) {
-        this.constructor = Preconditions.checkNotNull(constructor);
+    private StringValueObjectFactory(final T template, final MethodHandle constructor, final MethodHandle setter) {
+        this.template = Preconditions.checkNotNull(template);
+        this.constructor = constructor.bindTo(template);
         this.setter = Preconditions.checkNotNull(setter);
     }
 
@@ -80,8 +82,8 @@ public final class StringValueObjectFactory<T> {
 
         final StringValueObjectFactory<T> ret;
         try {
-            ret = new StringValueObjectFactory<>(
-                    LOOKUP.unreflectConstructor(copyConstructor).asType(CONSTRUCTOR_METHOD_TYPE).bindTo(template),
+            ret = new StringValueObjectFactory<>(template,
+                    LOOKUP.unreflectConstructor(copyConstructor).asType(CONSTRUCTOR_METHOD_TYPE),
                     LOOKUP.unreflectSetter(f).asType(SETTER_METHOD_TYPE));
         } catch (IllegalAccessException e) {
             throw new IllegalStateException("Failed to instantiate method handles", e);
@@ -123,4 +125,8 @@ public final class StringValueObjectFactory<T> {
             throw Throwables.propagate(e);
         }
     }
+
+    public T getTemplate() {
+        return template;
+    }
 }
index 2b30e1303313dd66812aaf837636324a7556b3a9..65f9f27ba64f1726b36f5ee7a3bbe44af9330f55 100644 (file)
@@ -138,6 +138,24 @@ public abstract class AbstractIetfInetUtil<A4, P4, A6, P6, A> {
         return prefix4Factory.newInstance(prefixStringV4(address, mask));
     }
 
+    @Nonnull public final P4 ipv4PrefixForShort(@Nonnull final byte[] address, final int mask) {
+        if (mask == 0) {
+            // Easy case, reuse the template
+            return prefix4Factory.getTemplate();
+        }
+
+        return v4PrefixForShort(address, 0, (mask / Byte.SIZE) + ((mask % Byte.SIZE == 0) ? 0 : 1), mask);
+    }
+
+    @Nonnull public final P4 ipv4PrefixForShort(@Nonnull final byte[] array, final int startOffset, final int mask) {
+        if (mask == 0) {
+            // Easy case, reuse the template
+            return prefix4Factory.getTemplate();
+        }
+
+        return v4PrefixForShort(array, startOffset, (mask / Byte.SIZE) + ((mask % Byte.SIZE == 0) ? 0 : 1), mask);
+    }
+
     /**
      * Create a /32 Ipv4Prefix for an {@link Inet4Address}
      *
@@ -261,6 +279,25 @@ public abstract class AbstractIetfInetUtil<A4, P4, A6, P6, A> {
         return prefix6Factory.newInstance(addressStringV6(address) + '/' + mask);
     }
 
+    @Nonnull public final P6 ipv6PrefixForShort(@Nonnull final byte[] address, final int mask) {
+        return ipv6PrefixForShort(address, 0, mask);
+    }
+
+    @Nonnull public final P6 ipv6PrefixForShort(@Nonnull final byte[] array, final int startOffset, final int mask) {
+        if (mask == 0) {
+            // Easy case, reuse the template
+            return prefix6Factory.getTemplate();
+        }
+
+        Preconditions.checkArgument(mask > 0 && mask <= 128, "Invalid mask %s", mask);
+        final int size = (mask / Byte.SIZE) + ((mask % Byte.SIZE == 0) ? 0 : 1);
+
+        // Until we can instantiate an IPv6 address for a partial array, use a temporary buffer
+        byte[] tmp = new byte[INET6_LENGTH];
+        System.arraycopy(array, startOffset, tmp, 0, size);
+        return ipv6PrefixFor(tmp, mask);
+    }
+
     /**
      * Create a /128 Ipv6Prefix by interpreting input bytes as an IPv4 address.
      *
@@ -372,4 +409,33 @@ public abstract class AbstractIetfInetUtil<A4, P4, A6, P6, A> {
         sb.append(mask);
         return sb.toString();
     }
+
+    private P4 v4PrefixForShort(@Nonnull final byte[] array, final int startOffset, final int size, final int mask) {
+        if (startOffset == 0 && size == INET4_LENGTH && array.length == INET4_LENGTH) {
+            // Easy case, fall back to non-short
+            return ipv4PrefixFor(array, mask);
+        }
+
+        final StringBuilder sb = new StringBuilder(18);
+
+        // Add from address
+        sb.append(Byte.toUnsignedInt(array[startOffset]));
+        for (int i = 1; i < size; i++) {
+            sb.append('.');
+            sb.append(Byte.toUnsignedInt(array[startOffset + i]));
+        }
+
+        // Add zeros
+        for (int i = size; i < INET4_LENGTH; i++) {
+            sb.append('.');
+            sb.append(0);
+        }
+
+        // Add mask
+        Preconditions.checkArgument(mask > 0 && mask <= 32, "Invalid mask %s", mask);
+        sb.append('/');
+        sb.append(mask);
+
+        return prefix4Factory.newInstance(sb.toString());
+    }
 }