BIND 10 trac3150, updated. ecc58c5e3a9e10f06357fcffaf169568b507901f [3150] Extra unit-test for temp. address pool

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Sep 16 12:44:43 UTC 2013


The branch, trac3150 has been updated
       via  ecc58c5e3a9e10f06357fcffaf169568b507901f (commit)
       via  eeacc3ac637e400c5f1512fc434ab08523521e2e (commit)
       via  c37f3b910e63df55b46516943a7e2ffd51e14e5c (commit)
       via  22b8b335e30ab84bdbac60244d74553e5bf3b719 (commit)
      from  f6619e644f62317afb4259e2af7732caa9d10c25 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ecc58c5e3a9e10f06357fcffaf169568b507901f
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Mon Sep 16 14:44:31 2013 +0200

    [3150] Extra unit-test for temp. address pool

commit eeacc3ac637e400c5f1512fc434ab08523521e2e
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Mon Sep 16 14:35:57 2013 +0200

    [3150] ChangeLog updated.

commit c37f3b910e63df55b46516943a7e2ffd51e14e5c
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Mon Sep 16 14:35:46 2013 +0200

    [3150] Checks for different pool types implemented.

commit 22b8b335e30ab84bdbac60244d74553e5bf3b719
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Mon Sep 16 13:55:18 2013 +0200

    [3150] checkType in Subnets implemented

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                      |   11 +-
 src/bin/dhcp4/dhcp4_srv.cc                     |    3 +-
 src/lib/dhcpsrv/alloc_engine.cc                |   20 +--
 src/lib/dhcpsrv/alloc_engine.h                 |    3 +-
 src/lib/dhcpsrv/pool.cc                        |    2 +-
 src/lib/dhcpsrv/subnet.cc                      |   33 ++++-
 src/lib/dhcpsrv/subnet.h                       |   34 ++++-
 src/lib/dhcpsrv/tests/alloc_engine_unittest.cc |   45 ++++--
 src/lib/dhcpsrv/tests/pool_unittest.cc         |   32 +++++
 src/lib/dhcpsrv/tests/subnet_unittest.cc       |  175 +++++++++++++++++++++++-
 10 files changed, 322 insertions(+), 36 deletions(-)

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 39c7247..a448ea3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,12 @@
-672.	[func]	tmark
+6XX.	[func]		tomek
+	libdhcpsrv: CfgMgr is now able to store IA, TA and PD pools in
+	Subnet6 structures.
+	(Trac #3150, git ABCD)
+
+672.	[func]		tmark
 	Added b10-dhcp-ddnsupdate transaction base class, NameChangeTransaction.
-	This class provides the common structure and methods to implement the state 
-	models described in the DHCP_DDNS design, plus integration with DNSClient 
+	This class provides the common structure and methods to implement the state
+	models described in the DHCP_DDNS design, plus integration with DNSClient
 	and its callback mechanism for asynchronous IO with the DNS servers.
 	(Trac #3086, git 079b862c9eb21056fdf957e560b8fe7b218441b6)
 
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index bf4f76b..7d13631 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -135,7 +135,8 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast,
             .arg(LeaseMgrFactory::instance().getName());
 
         // Instantiate allocation engine
-        alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
+        alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100,
+                                            false /* false = IPv4 */));
 
         // Register hook points
         hook_index_pkt4_receive_   = Hooks.hook_index_pkt4_receive_;
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
index 1f79897..f150f0f 100644
--- a/src/lib/dhcpsrv/alloc_engine.cc
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -117,7 +117,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
     if (it == pools.end()) {
         // ok to access first element directly. We checked that pools is non-empty
         IOAddress next = pools[0]->getFirstAddress();
-        subnet->setLastAllocated(next, lease_type_);
+        subnet->setLastAllocated(lease_type_, next);
         return (next);
     }
 
@@ -126,7 +126,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
     IOAddress next = increaseAddress(last); // basically addr++
     if ((*it)->inRange(next)) {
         // the next one is in the pool as well, so we haven't hit pool boundary yet
-        subnet->setLastAllocated(next, lease_type_);
+        subnet->setLastAllocated(lease_type_, next);
         return (next);
     }
 
@@ -136,13 +136,13 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
         // Really out of luck today. That was the last pool. Let's rewind
         // to the beginning.
         next = pools[0]->getFirstAddress();
-        subnet->setLastAllocated(next, lease_type_);
+        subnet->setLastAllocated(lease_type_, next);
         return (next);
     }
 
     // there is a next pool, let's try first address from it
     next = (*it)->getFirstAddress();
-    subnet->setLastAllocated(next, lease_type_);
+    subnet->setLastAllocated(lease_type_, next);
     return (next);
 }
 
@@ -173,17 +173,21 @@ AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&,
 }
 
 
-AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
+AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts,
+                         bool ipv6)
     :attempts_(attempts) {
+
+    Pool::PoolType pool_type = ipv6?Pool::TYPE_IA:Pool::TYPE_V4;
+
     switch (engine_type) {
     case ALLOC_ITERATIVE:
-        allocator_.reset(new IterativeAllocator(Pool6::TYPE_IA));
+        allocator_.reset(new IterativeAllocator(pool_type));
         break;
     case ALLOC_HASHED:
-        allocator_.reset(new HashedAllocator(Pool6::TYPE_IA));
+        allocator_.reset(new HashedAllocator(pool_type));
         break;
     case ALLOC_RANDOM:
-        allocator_.reset(new RandomAllocator(Pool6::TYPE_IA));
+        allocator_.reset(new RandomAllocator(pool_type));
         break;
 
     default:
diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h
index 553d41b..df9a2a6 100644
--- a/src/lib/dhcpsrv/alloc_engine.h
+++ b/src/lib/dhcpsrv/alloc_engine.h
@@ -193,7 +193,8 @@ protected:
     /// @param engine_type selects allocation algorithm
     /// @param attempts number of attempts for each lease allocation before
     ///        we give up (0 means unlimited)
-    AllocEngine(AllocType engine_type, unsigned int attempts);
+    /// @param ipv6 specifies if the engine should work for IPv4 or IPv6
+    AllocEngine(AllocType engine_type, unsigned int attempts, bool ipv6 = true);
 
     /// @brief Returns IPv4 lease.
     ///
diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc
index e9d057f..ee5e64e 100644
--- a/src/lib/dhcpsrv/pool.cc
+++ b/src/lib/dhcpsrv/pool.cc
@@ -63,7 +63,7 @@ Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
 
 Pool6::Pool6(PoolType type, const isc::asiolink::IOAddress& first,
              const isc::asiolink::IOAddress& last)
-    :Pool(type, first, last) {
+    :Pool(type, first, last), prefix_len_(128) {
 
     // check if specified address boundaries are sane
     if (!first.isV6() || !last.isV6()) {
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index d7892ba..b491454 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -89,6 +89,9 @@ Subnet::getOptionDescriptor(const std::string& option_space,
 }
 
 isc::asiolink::IOAddress Subnet::getLastAllocated(Pool::PoolType type) const {
+    // check if the type is valid (and throw if it isn't)
+    checkType(type);
+
     switch (type) {
     case Pool::TYPE_V4:
     case Pool::TYPE_IA:
@@ -102,8 +105,12 @@ isc::asiolink::IOAddress Subnet::getLastAllocated(Pool::PoolType type) const {
     }
 }
 
-void Subnet::setLastAllocated(const isc::asiolink::IOAddress& addr,
-                              Pool::PoolType type) {
+void Subnet::setLastAllocated(Pool::PoolType type,
+                              const isc::asiolink::IOAddress& addr) {
+
+    // check if the type is valid (and throw if it isn't)
+    checkType(type);
+
     switch (type) {
     case Pool::TYPE_V4:
     case Pool::TYPE_IA:
@@ -127,6 +134,12 @@ Subnet::toText() const {
     return (tmp.str());
 }
 
+void Subnet4::checkType(Pool::PoolType type) const {
+    if (type != Pool::TYPE_V4) {
+        isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
+    }
+}
+
 Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
                  const Triplet<uint32_t>& t1,
                  const Triplet<uint32_t>& t2,
@@ -139,6 +152,9 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
 }
 
 const PoolCollection& Subnet::getPools(Pool::PoolType type) const {
+    // check if the type is valid (and throw if it isn't)
+    checkType(type);
+
     switch (type) {
     case Pool::TYPE_V4:
     case Pool::TYPE_IA:
@@ -153,6 +169,8 @@ const PoolCollection& Subnet::getPools(Pool::PoolType type) const {
 }
 
 PoolPtr Subnet::getPool(Pool::PoolType type, isc::asiolink::IOAddress hint) {
+    // check if the type is valid (and throw if it isn't)
+    checkType(type);
 
     PoolCollection* pools = NULL;
 
@@ -204,6 +222,9 @@ Subnet::addPool(const PoolPtr& pool) {
 
     /// @todo: Check that pools do not overlap
 
+    // check if the type is valid (and throw if it isn't)
+    checkType(pool->getType());
+
     switch (pool->getType()) {
     case Pool::TYPE_V4:
     case Pool::TYPE_IA:
@@ -273,6 +294,14 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
     }
 }
 
+void Subnet6::checkType(Pool::PoolType type) const {
+    if ( (type != Pool::TYPE_IA) && (type != Pool::TYPE_TA) &&
+         (type != Pool::TYPE_PD)) {
+        isc_throw(BadValue, "Invalid Pool type: " << static_cast<int>(type)
+                  << ", must be TYPE_IA, TYPE_TA or TYPE_PD for Subnet6");
+    }
+}
+
 void
 Subnet6::validateOption(const OptionPtr& option) const {
     if (!option) {
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
index 6323944..7f88a2e 100644
--- a/src/lib/dhcpsrv/subnet.h
+++ b/src/lib/dhcpsrv/subnet.h
@@ -254,8 +254,8 @@ public:
     ///        AllocEngine::IterativeAllocator and keep the data there
     /// @param addr address/prefix to that was tried last
     /// @param type lease type to be set
-    void setLastAllocated(const isc::asiolink::IOAddress& addr,
-                          Pool::PoolType type);
+    void setLastAllocated(Pool::PoolType type,
+                          const isc::asiolink::IOAddress& addr);
 
     /// @brief returns unique ID for that subnet
     /// @return unique ID for that subnet
@@ -309,12 +309,12 @@ public:
     /// @param iface_name name of the interface
     void setIface(const std::string& iface_name);
 
-    /// @brief network interface name used to reach subnet (or "" for remote 
+    /// @brief network interface name used to reach subnet (or "" for remote
     /// subnets)
     /// @return network interface name for directly attached subnets or ""
     std::string getIface() const;
 
-    /// @brief returns textual representation of the subnet (e.g. 
+    /// @brief returns textual representation of the subnet (e.g.
     /// "2001:db8::/64")
     ///
     /// @return textual representation
@@ -344,6 +344,16 @@ protected:
         return (id++);
     }
 
+    /// @brief Checks if used pool type is valid
+    ///
+    /// Allowed type for Subnet4 is Pool::TYPE_V4.
+    /// Allowed types for Subnet6 are Pool::TYPE_{IA,TA,PD}.
+    /// This method is implemented in derived classes.
+    ///
+    /// @param type type to be checked
+    /// @throw BadValue if invalid value is used
+    virtual void checkType(Pool::PoolType type) const = 0;
+
     /// @brief Check if option is valid and can be added to a subnet.
     ///
     /// @param option option to be validated.
@@ -447,6 +457,14 @@ protected:
     virtual isc::asiolink::IOAddress default_pool() const {
         return (isc::asiolink::IOAddress("0.0.0.0"));
     }
+
+    /// @brief Checks if used pool type is valid
+    ///
+    /// Allowed type for Subnet4 is Pool::TYPE_V4.
+    ///
+    /// @param type type to be checked
+    /// @throw BadValue if invalid value is used
+    virtual void checkType(Pool::PoolType type) const;
 };
 
 /// @brief A pointer to a Subnet4 object
@@ -511,6 +529,14 @@ protected:
         return (isc::asiolink::IOAddress("::"));
     }
 
+    /// @brief Checks if used pool type is valid
+    ///
+    /// allowed types for Subnet6 are Pool::TYPE_{IA,TA,PD}.
+    ///
+    /// @param type type to be checked
+    /// @throw BadValue if invalid value is used
+    virtual void checkType(Pool::PoolType type) const;
+
     /// @brief specifies optional interface-id
     OptionPtr interface_id_;
 
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index 229692a..82f4419 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -55,8 +55,10 @@ public:
     /// @brief the sole constructor
     /// @param engine_type specifies engine type (e.g. iterative)
     /// @param attempts number of lease selection attempts before giving up
-    NakedAllocEngine(AllocEngine::AllocType engine_type, unsigned int attempts)
-        :AllocEngine(engine_type, attempts) {
+    /// @param ipv6 specifies if the engine is IPv6 or IPv4
+    NakedAllocEngine(AllocEngine::AllocType engine_type,
+                     unsigned int attempts, bool ipv6 = true)
+        :AllocEngine(engine_type, attempts, ipv6) {
     }
 
     // Expose internal classes for testing purposes
@@ -607,7 +609,8 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
 // This test checks if the simple IPv4 allocation can succeed
 TEST_F(AllocEngine4Test, simpleAlloc4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
@@ -636,7 +639,8 @@ TEST_F(AllocEngine4Test, simpleAlloc4) {
 // This test checks if the fake allocation (for DISCOVER) can succeed
 TEST_F(AllocEngine4Test, fakeAlloc4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
@@ -664,7 +668,8 @@ TEST_F(AllocEngine4Test, fakeAlloc4) {
 // in pool and free) can succeed
 TEST_F(AllocEngine4Test, allocWithValidHint4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
@@ -697,7 +702,8 @@ TEST_F(AllocEngine4Test, allocWithValidHint4) {
 // in pool, but is currently used) can succeed
 TEST_F(AllocEngine4Test, allocWithUsedHint4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     // Let's create a lease and put it in the LeaseMgr
@@ -745,7 +751,8 @@ TEST_F(AllocEngine4Test, allocWithUsedHint4) {
 // can succeed. The invalid hint should be ignored completely.
 TEST_F(AllocEngine4Test, allocBogusHint4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     // Client would like to get a 3000::abc lease, which does not belong to any
@@ -780,7 +787,8 @@ TEST_F(AllocEngine4Test, allocBogusHint4) {
 // This test checks that NULL values are handled properly
 TEST_F(AllocEngine4Test, allocateAddress4Nulls) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     // Allocations without subnet are not allowed
@@ -898,7 +906,8 @@ TEST_F(AllocEngine4Test, IterativeAllocator_manyPools4) {
 // This test checks if really small pools are working
 TEST_F(AllocEngine4Test, smallPool4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     IOAddress addr("192.0.2.17");
@@ -940,7 +949,8 @@ TEST_F(AllocEngine4Test, smallPool4) {
 // to find out a new lease fails.
 TEST_F(AllocEngine4Test, outOfAddresses4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     IOAddress addr("192.0.2.17");
@@ -978,7 +988,8 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
 // This test checks if an expired lease can be reused in DISCOVER (fake allocation)
 TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     IOAddress addr("192.0.2.15");
@@ -1045,7 +1056,8 @@ TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
 // This test checks if an expired lease can be reused in REQUEST (actual allocation)
 TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     IOAddress addr("192.0.2.105");
@@ -1098,7 +1110,8 @@ TEST_F(AllocEngine4Test, renewLease4) {
     boost::scoped_ptr<AllocEngine> engine;
     CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
 
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     IOAddress addr("192.0.2.102");
@@ -1471,7 +1484,8 @@ TEST_F(HookAllocEngine4Test, lease4_select) {
 
     // Create allocation engine (hook names are registered in its ctor)
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     // Initialize Hooks Manager
@@ -1534,7 +1548,8 @@ TEST_F(HookAllocEngine4Test, change_lease4_select) {
 
     // Create allocation engine (hook names are registered in its ctor)
     boost::scoped_ptr<AllocEngine> engine;
-    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
     ASSERT_TRUE(engine);
 
     // Initialize Hooks Manager
diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc
index d0cbf66..e7d8540 100644
--- a/src/lib/dhcpsrv/tests/pool_unittest.cc
+++ b/src/lib/dhcpsrv/tests/pool_unittest.cc
@@ -190,6 +190,38 @@ TEST(Pool6Test, PD) {
                                 77, 77));
 }
 
+// Checks that temporary address pools are handled properly
+TEST(Pool6Test, TA) {
+    // Note: since we defined TA pool types during PD work, we can test it
+    // now. Although the configuration to take advantage of it is not
+    // planned for now, we will support it some day.
+
+    // Let's construct 2001:db8:1::/96 temporary addresses
+    Pool6Ptr pool1;
+    EXPECT_NO_THROW(pool1.reset(new Pool6(Pool6::TYPE_TA,
+                                          IOAddress("2001:db8:1::"), 96)));
+
+    // Check that TA range can be only defined for single addresses
+    EXPECT_THROW(Pool6(Pool6::TYPE_TA, IOAddress("2001:db8:1::"), 96, 127),
+                 BadValue);
+
+    ASSERT_TRUE(pool1);
+    EXPECT_EQ(Pool6::TYPE_TA, pool1->getType());
+    EXPECT_EQ(128, pool1->getLength()); // singular addresses, not prefixes
+    EXPECT_EQ("2001:db8:1::", pool1->getFirstAddress().toText());
+    EXPECT_EQ("2001:db8:1::ffff:ffff", pool1->getLastAddress().toText());
+
+    // Check that it's possible to have min-max range for TA
+    Pool6Ptr pool2;
+    EXPECT_NO_THROW(pool2.reset(new Pool6(Pool6::TYPE_TA,
+                                          IOAddress("2001:db8:1::1"),
+                                          IOAddress("2001:db8:1::f"))));
+    ASSERT_TRUE(pool2);
+    EXPECT_EQ(Pool6::TYPE_TA, pool2->getType());
+    EXPECT_EQ(128, pool2->getLength()); // singular addresses, not prefixes
+    EXPECT_EQ("2001:db8:1::1", pool2->getFirstAddress().toText());
+    EXPECT_EQ("2001:db8:1::f", pool2->getLastAddress().toText());
+}
 
 // This test creates 100 pools and verifies that their IDs are unique.
 TEST(Pool6Test, unique_id) {
diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc
index cbb04bd..42b96d1 100644
--- a/src/lib/dhcpsrv/tests/subnet_unittest.cc
+++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc
@@ -175,6 +175,74 @@ TEST(Subnet4Test, get) {
     EXPECT_EQ(28, subnet->get().second);
 }
 
+
+// Checks if last allocated address/prefix is stored/retrieved properly
+TEST(Subnet4Test, lastAllocated) {
+    IOAddress addr("192.0.2.17");
+
+    IOAddress last("192.0.2.255");
+
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
+
+    // Check initial conditions (all should be set to the last address in range)
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_V4).toText());
+
+    // Now set last allocated for IA
+    EXPECT_NO_THROW(subnet->setLastAllocated(Pool::TYPE_V4, addr));
+    EXPECT_EQ(addr.toText(), subnet->getLastAllocated(Pool::TYPE_V4).toText());
+
+    // No, you can't set the last allocated IPv6 address in IPv4 subnet
+    EXPECT_THROW(subnet->setLastAllocated(Pool::TYPE_IA, addr), BadValue);
+    EXPECT_THROW(subnet->setLastAllocated(Pool::TYPE_TA, addr), BadValue);
+    EXPECT_THROW(subnet->setLastAllocated(Pool::TYPE_PD, addr), BadValue);
+}
+
+// Checks if the V4 is the only allowed type for Pool4 and if getPool()
+// is working properly.
+TEST(Subnet4Test, PoolType) {
+
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.2.0.0"), 16, 1, 2, 3));
+
+    PoolPtr pool1(new Pool4(IOAddress("192.2.1.0"), 24));
+    PoolPtr pool2(new Pool4(IOAddress("192.2.2.0"), 24));
+    PoolPtr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
+    PoolPtr pool4(new Pool6(Pool6::TYPE_TA, IOAddress("2001:db8:1:4::"), 64));
+    PoolPtr pool5(new Pool6(Pool6::TYPE_PD, IOAddress("2001:db8:1:1::"), 64));
+
+    // There should be no pools of any type by default
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_V4));
+
+    // It should not be possible to ask for V6 pools in Subnet4
+    EXPECT_THROW(subnet->getAnyPool(Pool::TYPE_IA), BadValue);
+    EXPECT_THROW(subnet->getAnyPool(Pool::TYPE_TA), BadValue);
+    EXPECT_THROW(subnet->getAnyPool(Pool::TYPE_PD), BadValue);
+
+    // Let's add a single V4 pool and check that it can be retrieved
+    subnet->addPool(pool1);
+
+    // If there's only one IA pool, get that pool (without and with hint)
+    EXPECT_EQ(pool1, subnet->getAnyPool(Pool::TYPE_V4));
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_V4, IOAddress("192.0.1.167")));
+
+    // Let's add additional V4 pool
+    subnet->addPool(pool2);
+
+    // Try without hints
+    EXPECT_EQ(pool1, subnet->getAnyPool(Pool::TYPE_V4));
+
+    // Try with valid hints
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_V4, IOAddress("192.2.1.5")));
+    EXPECT_EQ(pool2, subnet->getPool(Pool::TYPE_V4, IOAddress("192.2.2.254")));
+
+    // Try with bogus hints (hints should be ingored)
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_V4, IOAddress("10.1.1.1")));
+
+    // Trying to add Pool6 to Subnet4 is a big no,no!
+    EXPECT_THROW(subnet->addPool(pool3), BadValue);
+    EXPECT_THROW(subnet->addPool(pool4), BadValue);
+    EXPECT_THROW(subnet->addPool(pool5), BadValue);
+}
+
 // Tests for Subnet6
 
 TEST(Subnet6Test, constructor) {
@@ -218,7 +286,6 @@ TEST(Subnet6Test, Pool6InSubnet6) {
     PoolPtr mypool = subnet->getAnyPool(Pool::TYPE_IA);
     EXPECT_EQ(mypool, pool1);
 
-
     subnet->addPool(pool2);
     subnet->addPool(pool3);
 
@@ -234,6 +301,77 @@ TEST(Subnet6Test, Pool6InSubnet6) {
     EXPECT_EQ(mypool, pool3);
 }
 
+// Check if Subnet6 supports different types of pools properly.
+TEST(Subnet6Test, PoolTypes) {
+
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    PoolPtr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+    PoolPtr pool2(new Pool6(Pool6::TYPE_TA, IOAddress("2001:db8:1:2::"), 64));
+    PoolPtr pool3(new Pool6(Pool6::TYPE_PD, IOAddress("2001:db8:1:3::"), 64));
+    PoolPtr pool4(new Pool6(Pool6::TYPE_PD, IOAddress("2001:db8:1:4::"), 64));
+
+    PoolPtr pool5(new Pool4(IOAddress("192.0.2.0"), 24));
+
+    // There should be no pools of any type by default
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_IA));
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_TA));
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_PD));
+
+    // Trying to get IPv4 pool from Subnet6 is not allowed
+    EXPECT_THROW(subnet->getAnyPool(Pool::TYPE_V4), BadValue);
+
+    // Let's add a single IA pool and check that it can be retrieved
+    subnet->addPool(pool1);
+
+    // If there's only one IA pool, get that pool
+    EXPECT_EQ(pool1, subnet->getAnyPool(Pool::TYPE_IA));
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_IA, IOAddress("2001:db8:1:1::1")));
+
+    // Check if pools of different type are not returned
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_TA));
+    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Pool::TYPE_PD));
+
+    // We ask with good hints, but wrong types, should return nothing
+    EXPECT_EQ(PoolPtr(), subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8:1:2::1")));
+    EXPECT_EQ(PoolPtr(), subnet->getPool(Pool::TYPE_TA, IOAddress("2001:db8:1:3::1")));
+
+    // Let's add TA and PD pools
+    subnet->addPool(pool2);
+    subnet->addPool(pool3);
+
+    // Try without hints
+    EXPECT_EQ(pool1, subnet->getAnyPool(Pool::TYPE_IA));
+    EXPECT_EQ(pool2, subnet->getAnyPool(Pool::TYPE_TA));
+    EXPECT_EQ(pool3, subnet->getAnyPool(Pool::TYPE_PD));
+
+    // Try with valid hints
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_IA, IOAddress("2001:db8:1:1::1")));
+    EXPECT_EQ(pool2, subnet->getPool(Pool::TYPE_TA, IOAddress("2001:db8:1:2::1")));
+    EXPECT_EQ(pool3, subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8:1:3::1")));
+
+    // Try with bogus hints (hints should be ingored)
+    EXPECT_EQ(pool1, subnet->getPool(Pool::TYPE_IA, IOAddress("2001:db8:1:7::1")));
+    EXPECT_EQ(pool2, subnet->getPool(Pool::TYPE_TA, IOAddress("2001:db8:1:7::1")));
+    EXPECT_EQ(pool3, subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8:1:7::1")));
+
+    // Let's add a second PD pool
+    subnet->addPool(pool4);
+
+    // Without hints, it should return the first pool
+    EXPECT_EQ(pool3, subnet->getAnyPool(Pool::TYPE_PD));
+
+    // With valid hint, it should return that hint
+    EXPECT_EQ(pool3, subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8:1:3::1")));
+    EXPECT_EQ(pool4, subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8:1:4::1")));
+
+    // With invalid hint, it should return the first pool
+    EXPECT_EQ(pool3, subnet->getPool(Pool::TYPE_PD, IOAddress("2001:db8::123")));
+
+    // Adding Pool4 to Subnet6 is a big no, no!
+    EXPECT_THROW(subnet->addPool(pool5), BadValue);
+}
+
 TEST(Subnet6Test, Subnet6_Pool6_checks) {
 
     Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
@@ -532,4 +670,39 @@ TEST(Subnet6Test, interfaceId) {
 
 }
 
+// Checks if last allocated address/prefix is stored/retrieved properly
+TEST(Subnet6Test, lastAllocated) {
+    IOAddress ia("2001:db8:1::1");
+    IOAddress ta("2001:db8:1::abcd");
+    IOAddress pd("2001:db8:1::1234:5678");
+
+    IOAddress last("2001:db8:1::ffff:ffff:ffff:ffff");
+
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4));
+
+    // Check initial conditions (all should be set to the last address in range)
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_IA).toText());
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_TA).toText());
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_PD).toText());
+
+    // Now set last allocated for IA
+    EXPECT_NO_THROW(subnet->setLastAllocated(Pool::TYPE_IA, ia));
+    EXPECT_EQ(ia.toText(), subnet->getLastAllocated(Pool::TYPE_IA).toText());
+
+    // TA and PD should be unchanged
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_TA).toText());
+    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Pool::TYPE_PD).toText());
+
+    // Now set TA and PD
+    EXPECT_NO_THROW(subnet->setLastAllocated(Pool::TYPE_TA, ta));
+    EXPECT_NO_THROW(subnet->setLastAllocated(Pool::TYPE_PD, pd));
+
+    EXPECT_EQ(ia.toText(), subnet->getLastAllocated(Pool::TYPE_IA).toText());
+    EXPECT_EQ(ta.toText(), subnet->getLastAllocated(Pool::TYPE_TA).toText());
+    EXPECT_EQ(pd.toText(), subnet->getLastAllocated(Pool::TYPE_PD).toText());
+
+    // No, you can't set the last allocated IPv4 address in IPv6 subnet
+    EXPECT_THROW(subnet->setLastAllocated(Pool::TYPE_V4, ia), BadValue);
+}
+
 };



More information about the bind10-changes mailing list