Fix Bug 2290 22/17122/1
authorFlavio Fernandes <ffernand@redhat.com>
Wed, 25 Mar 2015 19:28:02 +0000 (15:28 -0400)
committerFlavio Fernandes <ffernand@redhat.com>
Wed, 25 Mar 2015 19:41:08 +0000 (15:41 -0400)
Ensure that isIPInUse, getLowAddr, allocateIP, releaseIP, gatewayIP_Pool_overlap and
initDefaults are all V6 friendly.

This is a port of gerrit: https://git.opendaylight.org/gerrit/#/c/12516/

Change-Id: I28c09691f02d339fc271a7eb62fa808e52e4b8b7
Signed-off-by: Flavio Fernandes <ffernand@redhat.com>
Also-By: Ryan Moats <rmoats@us.ibm.com>
neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronSubnet.java
neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronSubnet_IPAllocationPool.java

index 4a12e9aa81b9007c189c7467de5bed200822f5f7..c61854ea6fcc54cae7bc11673faa2161ced5c50e 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.neutron.spi;
 
 import java.io.Serializable;
+import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.Inet6Address;
 import java.util.ArrayList;
@@ -305,8 +306,15 @@ public class NeutronSubnet implements Serializable, INeutronObject {
         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
         while (i.hasNext()) {
             NeutronSubnet_IPAllocationPool pool = i.next();
-            if (pool.contains(gatewayIP)) {
-                return true;
+            if (ipVersion == 4) {
+                if (pool.contains(gatewayIP)) {
+                    return true;
+                }
+            }
+            if (ipVersion == 6) {
+                if (pool.contains_V6(gatewayIP)) {
+                    return true;
+                }
             }
         }
         return false;
@@ -326,20 +334,46 @@ public class NeutronSubnet implements Serializable, INeutronObject {
         }
         if (allocationPools == null) {
             allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
-            try {
-                SubnetUtils util = new SubnetUtils(cidr);
-                SubnetInfo info = util.getInfo();
-                if (gatewayIP == null || ("").equals(gatewayIP)) {
-                    gatewayIP = info.getLowAddress();
+            if (ipVersion == 4) {
+                try {
+                    SubnetUtils util = new SubnetUtils(cidr);
+                    SubnetInfo info = util.getInfo();
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = info.getLowAddress();
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnet_IPAllocationPool source =
+                            new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
+                                    info.getHighAddress());
+                        allocationPools = source.splitPool(gatewayIP);
+                    }
+                } catch (Exception e) {
+                    return false;
                 }
-                if (allocationPools.size() < 1) {
-                    NeutronSubnet_IPAllocationPool source =
-                        new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
-                                info.getHighAddress());
-                    allocationPools = source.splitPool(gatewayIP);
+            }
+            if (ipVersion == 6) {
+                String[] parts = cidr.split("/");
+                if (parts.length != 2) {
+                    return false;
+                }
+                try {
+                    int length = Integer.parseInt(parts[1]);
+                    BigInteger lowAddress_bi = NeutronSubnet_IPAllocationPool.convert_V6(parts[0]);
+                    String lowAddress = NeutronSubnet_IPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
+                    BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
+                    String highAddress = NeutronSubnet_IPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = lowAddress;
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnet_IPAllocationPool source =
+                            new NeutronSubnet_IPAllocationPool(lowAddress,
+                                    highAddress);
+                        allocationPools = source.splitPool_V6(gatewayIP);
+                    }
+                } catch (Exception e) {
+                    return false;
                 }
-            } catch (Exception e) {
-                return false;
             }
         }
         return true;
@@ -380,7 +414,10 @@ public class NeutronSubnet implements Serializable, INeutronObject {
         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
         while (i.hasNext()) {
             NeutronSubnet_IPAllocationPool pool = i.next();
-            if (pool.contains(ipAddress)) {
+            if (ipVersion == 4 && pool.contains(ipAddress)) {
+                return false;
+            }
+            if (ipVersion == 6 && pool.contains_V6(ipAddress)) {
                 return false;
             }
         }
@@ -399,11 +436,19 @@ public class NeutronSubnet implements Serializable, INeutronObject {
             if (ans == null) {
                 ans = pool.getPoolStart();
             }
-            else
-                if (NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart()) <
-                        NeutronSubnet_IPAllocationPool.convert(ans)) {
-                    ans = pool.getPoolStart();
+            else {
+                if (ipVersion == 4) {
+                    if (NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart()) <
+                            NeutronSubnet_IPAllocationPool.convert(ans)) {
+                        ans = pool.getPoolStart();
+                    }
+                }
+                if (ipVersion == 6) {
+                    if (NeutronSubnet_IPAllocationPool.convert_V6(pool.getPoolStart()).compareTo(NeutronSubnet_IPAllocationPool.convert_V6(ans)) < 0) {
+                        ans = pool.getPoolStart();
+                    }
                 }
+           }
         }
         return ans;
     }
@@ -426,11 +471,21 @@ public class NeutronSubnet implements Serializable, INeutronObject {
              */
             if (!(pool.getPoolEnd().equalsIgnoreCase(ipAddress) &&
                     pool.getPoolStart().equalsIgnoreCase(ipAddress))) {
-                if (pool.contains(ipAddress)) {
-                    List<NeutronSubnet_IPAllocationPool> pools = pool.splitPool(ipAddress);
-                    newList.addAll(pools);
-                } else {
-                    newList.add(pool);
+                if (ipVersion == 4) {
+                    if (pool.contains(ipAddress)) {
+                        List<NeutronSubnet_IPAllocationPool> pools = pool.splitPool(ipAddress);
+                        newList.addAll(pools);
+                    } else {
+                        newList.add(pool);
+                    }
+                }
+                if (ipVersion == 6) {
+                    if (pool.contains_V6(ipAddress)) {
+                        List<NeutronSubnet_IPAllocationPool> pools = pool.splitPool_V6(ipAddress);
+                        newList.addAll(pools);
+                    } else {
+                        newList.add(pool);
+                    }
                 }
             }
         }
@@ -446,18 +501,36 @@ public class NeutronSubnet implements Serializable, INeutronObject {
         NeutronSubnet_IPAllocationPool lPool = null;
         NeutronSubnet_IPAllocationPool hPool = null;
         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
-        long sIP = NeutronSubnet_IPAllocationPool.convert(ipAddress);
-        //look for lPool where ipAddr - 1 is high address
-        //look for hPool where ipAddr + 1 is low address
-        while (i.hasNext()) {
-            NeutronSubnet_IPAllocationPool pool = i.next();
-            long lIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart());
-            long hIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolEnd());
-            if (sIP+1 == lIP) {
-                hPool = pool;
+        if (ipVersion == 4) {
+            long sIP = NeutronSubnet_IPAllocationPool.convert(ipAddress);
+            //look for lPool where ipAddr - 1 is high address
+            //look for hPool where ipAddr + 1 is low address
+            while (i.hasNext()) {
+                NeutronSubnet_IPAllocationPool pool = i.next();
+                long lIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart());
+                long hIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolEnd());
+                if (sIP+1 == lIP) {
+                    hPool = pool;
+                }
+                if (sIP-1 == hIP) {
+                    lPool = pool;
+                }
             }
-            if (sIP-1 == hIP) {
-                lPool = pool;
+        }
+        if (ipVersion == 6) {
+            BigInteger sIP = NeutronSubnet_IPAllocationPool.convert_V6(ipAddress);
+            //look for lPool where ipAddr - 1 is high address
+            //look for hPool where ipAddr + 1 is low address
+            while (i.hasNext()) {
+                NeutronSubnet_IPAllocationPool pool = i.next();
+                BigInteger lIP = NeutronSubnet_IPAllocationPool.convert_V6(pool.getPoolStart());
+                BigInteger hIP = NeutronSubnet_IPAllocationPool.convert_V6(pool.getPoolEnd());
+                if (lIP.compareTo(sIP.add(BigInteger.ONE)) == 0) {
+                    hPool = pool;
+                }
+                if (hIP.compareTo(sIP.subtract(BigInteger.ONE)) == 0) {
+                    lPool = pool;
+                }
             }
         }
         //if (lPool == NULL and hPool == NULL) create new pool where low = ip = high
index 09fa6d0b0854182862ba7838c7e6b42a66ff8eb5..c0c898d53c7718f39f9d5bbbc6ee5b6658ec9705 100644 (file)
@@ -9,6 +9,9 @@
 package org.opendaylight.neutron.spi;
 
 import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -93,6 +96,43 @@ public class NeutronSubnet_IPAllocationPool implements Serializable {
         return ans;
     }
 
+    /**
+     * This method determines if this allocation pool contains the
+     * input IPv4 address
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @returns a boolean on whether the pool contains the address or not
+     */
+
+    public boolean contains_V6(String inputString) {
+        BigInteger inputIP = convert_V6(inputString);
+        BigInteger startIP = convert_V6(poolStart);
+        BigInteger endIP = convert_V6(poolEnd);
+        return (inputIP.compareTo(startIP) >= 0 && inputIP.compareTo(endIP) <= 0);
+    }
+
+    /**
+     * This static method converts the supplied IPv4 address to a long
+     * integer for comparison
+     *
+     * @param inputString
+     *            IPv6 address in dotted decimal format
+     * @returns high-endian representation of the IPv4 address as a BigInteger.
+     *          This method will return 0 if the input is null.
+     */
+
+    static BigInteger convert_V6(String inputString) {
+        if (inputString == null) {
+            return BigInteger.ZERO;
+        }
+        try {
+            return new BigInteger(((Inet6Address) InetAddress.getByName(inputString)).getAddress());
+        } catch (Exception e) {
+            return BigInteger.ZERO;
+        }
+    }
+
     /**
      * This static method converts the supplied high-ending long back
      * into a dotted decimal representation of an IPv4 address
@@ -101,7 +141,7 @@ public class NeutronSubnet_IPAllocationPool implements Serializable {
      *            high-endian representation of the IPv4 address as a long
      * @returns IPv4 address in dotted decimal format
      */
-    static String longtoIP(long l) {
+    static String longToIP(long l) {
         int i;
         String[] parts = new String[4];
         for (i=0; i<4; i++) {
@@ -111,8 +151,24 @@ public class NeutronSubnet_IPAllocationPool implements Serializable {
         return join(parts,".");
     }
 
+    /**
+     * This static method converts the supplied high-ending long back
+     * into a dotted decimal representation of an IPv4 address
+     *
+     * @param l
+     *            high-endian representation of the IPv4 address as a long
+     * @returns IPv4 address in dotted decimal format
+     */
+    static String bigIntegerToIP(BigInteger b) {
+        try {
+            return Inet6Address.getByAddress(b.toByteArray()).getHostAddress();
+        } catch (Exception e) {
+            return "ERROR";
+        }
+    }
+
     /*
-     * helper routine used by longtoIP
+     * helper routine used by longToIP
      */
     public static String join(String r[],String d)
     {
@@ -154,30 +210,30 @@ public class NeutronSubnet_IPAllocationPool implements Serializable {
                     poolStarted = true;
                 } else {
                     //FIX for bug 533
-                    p.setPoolStart(NeutronSubnet_IPAllocationPool.longtoIP(i+1));
+                    p.setPoolStart(NeutronSubnet_IPAllocationPool.longToIP(i+1));
                 }
             }
             if (i == eIP) {
                 if (i != gIP) {
                     p.setPoolEnd(poolEnd);
                 } else {
-                    p.setPoolEnd(NeutronSubnet_IPAllocationPool.longtoIP(i-1));
+                    p.setPoolEnd(NeutronSubnet_IPAllocationPool.longToIP(i-1));
                 }
                 ans.add(p);
             }
             if (i != sIP && i != eIP) {
                 if (i != gIP) {
                     if (!poolStarted) {
-                        p.setPoolStart(NeutronSubnet_IPAllocationPool.longtoIP(i));
+                        p.setPoolStart(NeutronSubnet_IPAllocationPool.longToIP(i));
                         poolStarted = true;
                     }
                 } else {
-                    p.setPoolEnd(NeutronSubnet_IPAllocationPool.longtoIP(i-1));
+                    p.setPoolEnd(NeutronSubnet_IPAllocationPool.longToIP(i-1));
                     poolStarted = false;
                     ans.add(p);
                     p = new NeutronSubnet_IPAllocationPool();
                     // Fix for 2120
-                    p.setPoolStart(NeutronSubnet_IPAllocationPool.longtoIP(i+1));
+                    p.setPoolStart(NeutronSubnet_IPAllocationPool.longToIP(i+1));
                     poolStarted = true;
                 }
             }
@@ -191,4 +247,50 @@ public class NeutronSubnet_IPAllocationPool implements Serializable {
             "start=" + poolStart +
             ", end=" + poolEnd + "]";
     }
+
+    /*
+     * This method splits the current instance by removing the supplied
+     * parameter.
+     *
+     * If the parameter is either the low or high address,
+     * then that member is adjusted and a list containing just this instance
+     * is returned.
+     new *
+     * If the parameter is in the middle of the pool, then
+     * create two new instances, one ranging from low to parameter-1
+     * the other ranging from parameter+1 to high
+     * If the pool is a single address, return null
+     */
+    public List<NeutronSubnet_IPAllocationPool> splitPool_V6(String ipAddress) {
+        List<NeutronSubnet_IPAllocationPool> ans = new ArrayList<NeutronSubnet_IPAllocationPool>();
+        BigInteger gIP = NeutronSubnet_IPAllocationPool.convert_V6(ipAddress);
+        BigInteger sIP = NeutronSubnet_IPAllocationPool.convert_V6(poolStart);
+        BigInteger eIP = NeutronSubnet_IPAllocationPool.convert_V6(poolEnd);
+        if (gIP.compareTo(sIP) == 0 && gIP.compareTo(eIP) < 0) {
+            NeutronSubnet_IPAllocationPool p = new NeutronSubnet_IPAllocationPool();
+            p.setPoolStart(NeutronSubnet_IPAllocationPool.bigIntegerToIP(sIP.add(BigInteger.ONE)));
+            p.setPoolEnd(poolEnd);
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) == 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnet_IPAllocationPool p = new NeutronSubnet_IPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnet_IPAllocationPool.bigIntegerToIP(eIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) < 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnet_IPAllocationPool p = new NeutronSubnet_IPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnet_IPAllocationPool.bigIntegerToIP(gIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            NeutronSubnet_IPAllocationPool p2 = new NeutronSubnet_IPAllocationPool();
+            p2.setPoolStart(NeutronSubnet_IPAllocationPool.bigIntegerToIP(gIP.add(BigInteger.ONE)));
+            p2.setPoolEnd(poolEnd);
+            ans.add(p2);
+            return ans;
+        }
+        return null;
+    }
 }