Browse Source

[2237] Pool4 and tests implemented.

Tomek Mrugalski 12 years ago
parent
commit
574a6f8834
4 changed files with 186 additions and 4 deletions
  1. 54 3
      src/lib/dhcp/addr_utilities.cc
  2. 32 1
      src/lib/dhcp/pool.cc
  3. 27 0
      src/lib/dhcp/pool.h
  4. 73 0
      src/lib/dhcp/tests/pool_unittest.cc

+ 54 - 3
src/lib/dhcp/addr_utilities.cc

@@ -13,17 +13,30 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <string.h>
+#include <exceptions/exceptions.h>
 #include <dhcp/addr_utilities.h>
 
 using namespace isc::asiolink;
 
+const static uint32_t masks[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+                                  0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+                                  0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+                                  0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+                                  0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+                                  0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+                                  0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+                                  0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+                                  0xffffffff };
+
+const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+
 namespace isc {
 namespace dhcp {
 
-isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                             uint8_t len) {
 
-    const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
     uint8_t packed[V6ADDRESS_LEN];
 
     // First we copy the whole address as 16 bytes.
@@ -55,7 +68,36 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi
     return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
 }
 
-isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+                                            uint8_t len) {
+    uint32_t addr = prefix;
+    if (len>32) {
+        isc_throw(BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+    }
+
+    return (IOAddress(addr & (~masks[32-len])));
+}
+
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+                                            uint8_t len) {
+    if (prefix.getFamily() == AF_INET) {
+        return firstAddrInPrefix4(prefix, len);
+    } else {
+        return firstAddrInPrefix6(prefix, len);
+    }
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+                                           uint8_t len) {
+    uint32_t addr = prefix;
+    if (len>32) {
+        isc_throw(BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+    }
+
+    return (IOAddress(addr | masks[32-len]));
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                            uint8_t len) {
 
     const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
@@ -92,5 +134,14 @@ isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix
     return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
 }
 
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+                                           uint8_t len) {
+    if (prefix.getFamily() == AF_INET) {
+        return lastAddrInPrefix4(prefix, len);
+    } else {
+        return lastAddrInPrefix6(prefix, len);
+    }
+}
+
 };
 };

+ 32 - 1
src/lib/dhcp/pool.cc

@@ -30,6 +30,38 @@ bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
     return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
 }
 
+Pool4::Pool4(const isc::asiolink::IOAddress& first,
+             const isc::asiolink::IOAddress& last)
+    :Pool(first, last) {
+    // check if specified address boundaries are sane
+    if (first.getFamily() != AF_INET || last.getFamily() != AF_INET) {
+        isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+    }
+
+    if (last < first) {
+        isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+    }
+}
+
+Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
+             uint8_t prefix_len)
+    :Pool(prefix, IOAddress("0.0.0.0")) {
+
+    // check if the prefix is sane
+    if (prefix.getFamily() != AF_INET) {
+        isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+    }
+
+    // check if the prefix length is sane
+    if (prefix_len == 0 || prefix_len > 32) {
+        isc_throw(BadValue, "Invalid prefix length");
+    }
+
+    // Let's now calculate the last address in defined pool
+    last_ = lastAddrInPrefix(prefix, prefix_len);
+}
+
+
 Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
              const isc::asiolink::IOAddress& last)
     :Pool(first, last), type_(type), prefix_len_(0) {
@@ -52,7 +84,6 @@ Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
         // last_ = first;
     }
 
-
     // TYPE_PD is not supported by this constructor. first-last style
     // parameters are for IA and TA only. There is another dedicated
     // constructor for that (it uses prefix/length)

+ 27 - 0
src/lib/dhcp/pool.h

@@ -91,6 +91,33 @@ protected:
     std::string comments_;
 };
 
+/// @brief Pool information for IPv4 addresses
+///
+/// It holds information about pool4, i.e. a range of IPv4 address space that
+/// is configured for DHCP allocation.
+class Pool4 : public Pool {
+public:
+    /// @brief the constructor for Pool4 "min-max" style definition
+    ///
+    /// @param first the first address in a pool
+    /// @param last the last address in a pool
+    Pool4(const isc::asiolink::IOAddress& first,
+          const isc::asiolink::IOAddress& last);
+
+    /// @brief the constructor for Pool4 "prefix/len" style definition
+    ///
+    /// @param prefix specifies prefix of the pool
+    /// @param prefix_len specifies length of the prefix of the pool
+    Pool4(const isc::asiolink::IOAddress& prefix,
+          uint8_t prefix_len);
+};
+
+/// @brief a pointer an IPv4 Pool
+typedef boost::shared_ptr<Pool4> Pool4Ptr;
+
+/// @brief a container for IPv4 Pools
+typedef std::vector<Pool4Ptr> Pool4Collection;
+
 /// @brief Pool information for IPv6 addresses and prefixes
 ///
 /// It holds information about pool6, i.e. a range of IPv6 address space that

+ 73 - 0
src/lib/dhcp/tests/pool_unittest.cc

@@ -27,6 +27,79 @@ using namespace isc::asiolink;
 
 namespace {
 
+TEST(Pool4Test, constructor_first_last) {
+
+    // let's construct 192.0.2.1-192.0.2.255 pool
+    Pool4 pool1(IOAddress("192.0.2.1"), IOAddress("192.0.2.255"));
+
+    EXPECT_EQ(IOAddress("192.0.2.1"), pool1.getFirstAddress());
+    EXPECT_EQ(IOAddress("192.0.2.255"), pool1.getLastAddress());
+
+    // This is Pool4, IPv6 addresses do not belong here
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+                       IOAddress("192.168.0.5")), BadValue);
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+                       IOAddress("2001:db8::1")), BadValue);
+
+    // Should throw. Range should be 192.0.2.1-192.0.2.2, not
+    // the other way around.
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.0.2.2"),
+                       IOAddress("192.0.2.1")), BadValue);
+}
+
+TEST(Pool4Test, constructor_prefix_len) {
+
+    // let's construct 2001:db8:1::/96 pool
+    Pool4 pool1(IOAddress("192.0.2.0"), 25);
+
+    EXPECT_EQ("192.0.2.0", pool1.getFirstAddress().toText());
+    EXPECT_EQ("192.0.2.127", pool1.getLastAddress().toText());
+
+    // No such thing as /33 prefix
+    EXPECT_THROW(Pool4(IOAddress("192.0.2.1"), 33), BadValue);
+
+    // /0 prefix does not make sense
+    EXPECT_THROW(Pool4(IOAddress("192.0.2.0"), 0), BadValue);
+
+    // This is Pool6, IPv4 addresses do not belong here
+    EXPECT_THROW(Pool4(IOAddress("2001:db8::1"), 20), BadValue);
+}
+
+TEST(Pool4Test, in_range) {
+   Pool4 pool1(IOAddress("192.0.2.10"), IOAddress("192.0.2.20"));
+
+   EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.0")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.10")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.17")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.20")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.21")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.255")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("255.255.255.255")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("0.0.0.0")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool4Test, unique_id) {
+
+    const int num_pools = 100;
+    std::vector<Pool4Ptr> pools;
+
+    for (int i = 0; i < num_pools; ++i) {
+        pools.push_back(Pool4Ptr(new Pool4(IOAddress("192.0.2.0"),
+                                           IOAddress("192.0.2.255"))));
+    }
+
+    for (int i = 0; i < num_pools; ++i) {
+        for (int j = i + 1; j < num_pools; ++j) {
+            if (pools[i]->getId() == pools[j]->getId()) {
+                FAIL() << "Pool-ids must be unique";
+            }
+        }
+    }
+
+}
+
+
 TEST(Pool6Test, constructor_first_last) {
 
     // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool