Browse Source

[3171] IterativeAllocator::pickAddress() now handles prefixes as well

 - pickAddress() handles prefixes as well
 - Subnet::delPools() implemented
 - tests for iterating over address and prefix pools implemented.
Tomek Mrugalski 11 years ago
parent
commit
4b7664ccfd

+ 15 - 1
src/lib/dhcpsrv/alloc_engine.cc

@@ -137,6 +137,9 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
                                              const DuidPtr&,
                                              const IOAddress&) {
 
+    // Is this prefix allocation?
+    bool prefix = pool_type_ == Lease::TYPE_PD;
+
     // Let's get the last allocated address. It is usually set correctly,
     // but there are times when it won't be (like after removing a pool or
     // perhaps restarting the server).
@@ -169,7 +172,18 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
 
     // Ok, we have a pool that the last address belonged to, let's use it.
 
-    IOAddress next = increaseAddress(last); // basically addr++
+    IOAddress next("::");
+    if (!prefix) {
+        next = increaseAddress(last); // basically addr++
+    } else {
+        Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
+        if (!pool6) {
+            // Something is gravely wrong here
+            isc_throw(InvalidParameter, "Wrong type of pool");
+        }
+        // Get the next prefix
+        next = increasePrefix(last, (pool6)->getLength());
+    }
     if ((*it)->inRange(next)) {
         // the next one is in the pool as well, so we haven't hit pool boundary yet
         subnet->setLastAllocated(pool_type_, next);

+ 19 - 0
src/lib/dhcpsrv/subnet.cc

@@ -244,6 +244,25 @@ Subnet::addPool(const PoolPtr& pool) {
 }
 
 void
+Subnet::delPools(Lease::Type type) {
+    switch (type) {
+    case Lease::TYPE_V4:
+    case Lease::TYPE_NA:
+        pools_.clear();
+        return;
+    case Lease::TYPE_TA:
+        pools_ta_.clear();
+        return;
+    case Lease::TYPE_PD:
+        pools_pd_.clear();
+        return;
+    default:
+        isc_throw(BadValue, "Invalid pool type specified: "
+                  << static_cast<int>(type));
+    }
+}
+
+void
 Subnet::setIface(const std::string& iface_name) {
     iface_ = iface_name;
 }

+ 7 - 0
src/lib/dhcpsrv/subnet.h

@@ -272,6 +272,13 @@ public:
     /// @param pool pool to be added
     void addPool(const PoolPtr& pool);
 
+
+    /// @brief Deletes all pools of specified type
+    ///
+    /// This method is used for testing purposes only
+    /// @param type type of pools to be deleted
+    void delPools(Lease::Type type);
+
     /// @brief Returns a pool that specified address belongs to
     ///
     /// If there is no pool that the address belongs to (hint is invalid), other

+ 95 - 2
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc

@@ -451,10 +451,100 @@ TEST_F(AllocEngine6Test, IterativeAllocator) {
     }
 }
 
-// This test verifies that the allocator iterates over addresses properly
 TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) {
     NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
 
+    subnet_->delPools(Lease::TYPE_NA); // Get rid of default pool
+
+    Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
+                             IOAddress("2001:db8:1::5")));
+    Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
+                             IOAddress("2001:db8:1::100")));
+    Pool6Ptr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::105"),
+                             IOAddress("2001:db8:1::106")));
+    subnet_->addPool(pool1);
+    subnet_->addPool(pool2);
+    subnet_->addPool(pool3);
+
+    // Let's check the first pool (5 addresses here)
+    EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // The second pool is easy - only one address here
+    EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // This is the third and last pool, with 2 addresses in it
+    EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // We iterated over all addresses and reached to the end of the last pool.
+    // Let's wrap around and start from the beginning
+    EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+}
+
+TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStep) {
+    NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
+
+    subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
+
+    Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
+    Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
+    Pool6Ptr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 56, 64));
+    subnet_->addPool(pool1);
+    subnet_->addPool(pool2);
+    subnet_->addPool(pool3);
+
+    // We have a 2001:db8::/48 subnet that has 3 pools defined in it:
+    // 2001:db8::/56 split into /60 prefixes (16 leases) (or 2001:db8:0:X0::)
+    // 2001:db8:1::/48 split into a single /48 prefix (just 1 lease)
+    // 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
+
+    // First pool check (Let's check over all 16 leases)
+    EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // Second pool (just one lease here)
+    EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // Third pool (256 leases, let's check first and last explictly and the
+    // rest over in a pool
+    EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    for (int i = 1; i < 255; i++) {
+        stringstream exp;
+        exp << "2001:db8:2:" << hex << i << dec << "::";
+        EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    }
+    EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+
+    // Ok, we've iterated over all prefixes in all pools. We now wrap around.
+    // We're looping over now (iterating over first pool again)
+    EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+}
+
+// This test verifies that the iterative allocator can step over addresses
+TEST_F(AllocEngine6Test, IterativeAllocatorAddressIncrease) {
+    NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
+
     // Let's pick the first address
     IOAddress addr1 = alloc.pickAddress(subnet_, duid_, IOAddress("2001:db8:1::10"));
 
@@ -469,8 +559,11 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) {
     checkAddrIncrease(alloc, "2001:db8::ffff", "2001:db8::1:0");
     checkAddrIncrease(alloc, "::", "::1");
     checkAddrIncrease(alloc, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::");
+}
 
-    // Check that prefixes can be increased properly
+// This test verifies that the allocator can step over prefixes
+TEST_F(AllocEngine6Test, IterativeAllocatorPrefixIncrease) {
+    NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
 
     // For /128 prefix, increasePrefix should work the same as addressIncrease
     checkPrefixIncrease(alloc, "2001:db8::9", 128, "2001:db8::a");