Browse Source

[2238] Pool6 implemented, Subnet6 work in progress.

Tomek Mrugalski 12 years ago
parent
commit
d1c7c9057b
4 changed files with 281 additions and 33 deletions
  1. 92 0
      src/lib/dhcp/cfgmgr.cc
  2. 86 30
      src/lib/dhcp/cfgmgr.h
  3. 1 0
      src/lib/dhcp/tests/Makefile.am
  4. 102 3
      src/lib/dhcp/tests/cfgmgr_unittest.cc

+ 92 - 0
src/lib/dhcp/cfgmgr.cc

@@ -12,11 +12,103 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/addr_utilities.h>
+#include <asiolink/io_address.h>
 #include <dhcp/cfgmgr.h>
 
+using namespace isc::asiolink;
+using namespace isc::util;
+
 namespace isc {
 namespace dhcp {
 
+Pool::Pool(const isc::asiolink::IOAddress& first,
+           const isc::asiolink::IOAddress& last,
+           const Triplet<uint32_t>& t1,
+           const Triplet<uint32_t>& t2,
+           const Triplet<uint32_t>& valid_lifetime)
+    :id_(getNextID()), first_(first), last_(last), t1_(t1), t2_(t2), valid_(valid_lifetime) {
+
+}
+
+bool Pool::inRange(const isc::asiolink::IOAddress& addr) {
+    return ( first_.smallerEqual(addr) && addr.smallerEqual(last_) );
+}
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+             const isc::asiolink::IOAddress& last,
+             const Triplet<uint32_t>& t1,
+             const Triplet<uint32_t>& t2,
+             const Triplet<uint32_t>& preferred_lifetime,
+             const Triplet<uint32_t>& valid_lifetime)
+    :Pool(first, last, t1, t2, valid_lifetime),
+     type_(type), prefix_len_(0), preferred_(preferred_lifetime) {
+
+    if (last < first) {
+        isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+        // This check is strict. If we decide that it is too strict,
+        // we need to comment it and uncomment lines below.
+
+        // first_  = last;
+        // last_ = first;
+    }
+
+    if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
+        isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+    }
+
+    // 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)
+    if ((type != TYPE_IA) && (type != TYPE_TA)) {
+        isc_throw(BadValue, "Invalid Pool6 type specified");
+    }
+}
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& addr,
+             uint8_t prefix_len,
+             const Triplet<uint32_t>& t1,
+             const Triplet<uint32_t>& t2,
+             const Triplet<uint32_t>& preferred_lifetime,
+             const Triplet<uint32_t>& valid_lifetime)
+    :Pool(addr, IOAddress("::"), t1, t2, valid_lifetime),
+     type_(type), prefix_len_(prefix_len), preferred_(preferred_lifetime) {
+
+    if (prefix_len == 0 || prefix_len > 128) {
+        isc_throw(BadValue, "Invalid prefix length");
+    }
+
+    if (addr.getFamily() != AF_INET6) {
+        isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+    }
+
+    // Let's now calculate the last address in defined pool
+    last_ = lastAddrInPrefix(addr, prefix_len);
+}
+
+
+Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len)
+    :id_(getNextID()), prefix_(prefix), len_(len) {
+    if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
+         (prefix.getFamily() == AF_INET && len > 32) ) {
+        isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
+    }
+}
+
+bool Subnet::inRange(const isc::asiolink::IOAddress& addr) {
+    IOAddress first = firstAddrInPrefix(prefix_, len_);
+    IOAddress last = lastAddrInPrefix(prefix_, len_);
+
+    return ( (first <= addr) && (addr <= last) );
+}
+
+Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length)
+    :Subnet(prefix, length) {
+    if (prefix.getFamily() != AF_INET6) {
+        isc_throw(BadValue, "Invalid prefix " << prefix.toText() << " specified in subnet6");
+    }
+}
+
 
 
 

+ 86 - 30
src/lib/dhcp/cfgmgr.h

@@ -107,27 +107,15 @@ protected:
     T max_;
 };
 
-class Pool6 {
-public:
-    typedef enum {
-        TYPE_IA,
-        TYPE_TA,
-        TYPE_PD
-    }  Pool6Type;
-
-    Pool6(Pool6Type type, const isc::asiolink::IOAddress first,
-          const isc::asiolink::IOAddress last,
-          const Triplet<uint32_t>& t1,
-          const Triplet<uint32_t>& t2,
-          const Triplet<uint32_t>& preferred_lifetime,
-          const Triplet<uint32_t>& valid_lifetime);
+class Pool {
 
+public:
     uint32_t getId() const {
         return (id_);
     }
 
-    Pool6Type getType() const {
-        return (type_);
+    Triplet<uint32_t> getValid() const {
+        return (valid_);
     }
 
     const isc::asiolink::IOAddress& getFirstAddress() const {
@@ -146,22 +134,28 @@ public:
         return (t2_);
     }
 
-    Triplet<uint32_t> getPreferred() const {
-        return (preferred_);
-    }
+    /// @brief checks if specified address is in range
+    bool inRange(const isc::asiolink::IOAddress& addr);
 
-    Triplet<uint32_t> getValid() const {
-        return (valid_);
+protected:
+
+    /// @brief protected constructor
+    Pool(const isc::asiolink::IOAddress& first,
+         const isc::asiolink::IOAddress& last,
+         const Triplet<uint32_t>& t1,
+         const Triplet<uint32_t>& t2,
+         const Triplet<uint32_t>& valid_lifetime);
+
+    static uint32_t getNextID() {
+        static uint32_t id = 0;
+        return (id++);
     }
 
-protected:
     /// @brief pool-id
     ///
     /// This ID is used to indentify this specific pool.
     uint32_t id_;
 
-    Pool6Type type_;
-
     isc::asiolink::IOAddress first_;
 
     isc::asiolink::IOAddress last_;
@@ -170,32 +164,94 @@ protected:
 
     Triplet<uint32_t> t2_;
 
-    Triplet<uint32_t> preferred_;
-
     Triplet<uint32_t> valid_;
 
+    std::string comments_;
+
     ///uint128_t available_leases_;
 
     ///uint128_t total_leases_;
+};
 
-    std::string comments_;
+class Pool6 : public Pool {
+public:
+    typedef enum {
+        TYPE_IA,
+        TYPE_TA,
+        TYPE_PD
+    }  Pool6Type;
+
+    Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+          const isc::asiolink::IOAddress& last,
+          const Triplet<uint32_t>& t1,
+          const Triplet<uint32_t>& t2,
+          const Triplet<uint32_t>& preferred_lifetime,
+          const Triplet<uint32_t>& valid_lifetime);
+
+    Pool6(Pool6Type type, const isc::asiolink::IOAddress& addr,
+          uint8_t prefix_len,
+          const Triplet<uint32_t>& t1,
+          const Triplet<uint32_t>& t2,
+          const Triplet<uint32_t>& preferred_lifetime,
+          const Triplet<uint32_t>& valid_lifetime);
+
+    Pool6Type getType() const {
+        return (type_);
+    }
+
+    Triplet<uint32_t> getPreferred() const {
+        return (preferred_);
+    }
+
+protected:
+
+    Pool6Type type_;
+
+    /// @brief prefix length
+    /// used by TYPE_PD only (zeroed for other types)
+    uint8_t prefix_len_;
+
+    Triplet<uint32_t> preferred_;
 };
 
+typedef boost::shared_ptr<Pool> PoolPtr;
 typedef boost::shared_ptr<Pool6> Pool6Ptr;
 
 typedef std::vector<Pool6Ptr> Pool6Collection;
 
-class Subnet6 {
+class Subnet {
 public:
+    /// @brief checks if specified address is in range
+    bool inRange(const isc::asiolink::IOAddress& addr);
+
+protected:
+    /// @brief protected constructor
+    //
+    /// By making the constructor protected, we make sure that noone will
+    /// ever instantiate that class. Pool4 and Pool6 should be used instead.
+    Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len);
+
+    static uint32_t getNextID() {
+        static uint32_t id = 0;
+        return (id++);
+    }
+
     /// @brief subnet-id
     uint32_t id_;
 
-    isc::asiolink::IOAddress addr_;
+    isc::asiolink::IOAddress prefix_;
 
-    uint8_t prefix_len_;
+    uint8_t len_;
+};
 
+class Subnet6 : public Subnet {
+public:
+    Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length);
+
+protected:
     /// collection of pools in that list
     Pool6Collection pools_;
+
 };
 
 } // namespace isc::dhcp

+ 1 - 0
src/lib/dhcp/tests/Makefile.am

@@ -52,6 +52,7 @@ libdhcpsrv_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 libdhcpsrv_unittests_CXXFLAGS = $(AM_CXXFLAGS)
 libdhcpsrv_unittests_LDADD  = $(GTEST_LDADD)
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 
 
 if USE_CLANGPP

+ 102 - 3
src/lib/dhcp/tests/cfgmgr_unittest.cc

@@ -55,7 +55,7 @@ TEST(TripletTest, constructor) {
     EXPECT_EQ(17, x.get(17));
 
     EXPECT_EQ(30, x.get(30));
-    
+
     EXPECT_EQ(30, x.get(35));
 
     // this will be boring. It is expected to return 42 no matter what
@@ -71,8 +71,8 @@ TEST(TripletTest, constructor) {
     EXPECT_EQ(42, y.get(80));  // time!
 }
 
-// triplets must be easy to use
-// simple int conversions must be done on the fly
+// Triplets must be easy to use.
+// Simple to/from int conversions must be done on the fly.
 TEST(TripletTest, operator) {
 
     uint32_t x = 47;
@@ -99,4 +99,103 @@ TEST(TripletTest, sanity_check) {
 
 }
 
+TEST(Pool6Test, constructor_first_last) {
+
+    // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
+    Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+                IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+                1000, 2000, 3000, 4000);
+
+    EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+    EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
+    EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+              pool1.getLastAddress());
+    EXPECT_EQ(1000, pool1.getT1());
+    EXPECT_EQ(2000, pool1.getT2());
+    EXPECT_EQ(3000, pool1.getPreferred());
+    EXPECT_EQ(4000, pool1.getValid());
+
+    // This is Pool6, IPv4 addresses do not belong here
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+                       IOAddress("192.168.0.5"),
+                       1000, 2000, 3000, 4000), BadValue);
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+                       IOAddress("2001:db8::1"),
+                       1000, 2000, 3000, 4000), BadValue);
+
+
+    // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
+    // the other way around.
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
+                       IOAddress("2001:db8::1"),
+                       1000, 2000, 3000, 4000), BadValue);
+}
+
+TEST(Pool6Test, constructor_prefix_len) {
+
+    // let's construct 2001:db8:1::/96 pool
+    Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+                96, 1000, 2000, 3000, 4000);
+
+    EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+    EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
+    EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
+    EXPECT_EQ(1000, pool1.getT1());
+    EXPECT_EQ(2000, pool1.getT2());
+    EXPECT_EQ(3000, pool1.getPreferred());
+    EXPECT_EQ(4000, pool1.getValid());
+
+    // This is Pool6, IPv4 addresses do not belong here
+    EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+                       96, 1000, 2000, 3000, 4000),
+                 BadValue);
+}
+
+TEST(Pool6Test, in_range) {
+   Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
+               IOAddress("2001:db8:1::f"),
+               1000, 2000, 3000, 4000);
+
+   EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
+   EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
+   EXPECT_FALSE(pool1.inRange(IOAddress("::")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool6Test, unique_id) {
+
+    const int num_pools = 100;
+    vector<Pool6Ptr> pools;
+
+    for (int i = 0; i < num_pools; ++i) {
+        pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+                                           IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+                                           1000, 2000, 3000, 4000)));
+    }
+
+    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(Subnet6Test, in_range) {
+    Subnet6 subnet(IOAddress("2001:db8:1::"), 64);
+
+   EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
+   EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
+   EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
+   EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
+   EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
+   EXPECT_FALSE(subnet.inRange(IOAddress("::")));
+}
+
 } // end of anonymous namespace