From: Tomek Mrugalski Date: Fri, 22 Sep 2017 16:38:46 +0000 (+0200) Subject: [5307] Minor tweaks in alloc_engine, couple tests added. X-Git-Tag: trac5363_base~11^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e80567854bd1e980a78b995ccd76c0789faeabd8;p=thirdparty%2Fkea.git [5307] Minor tweaks in alloc_engine, couple tests added. --- diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index b58de9f9ed..95049a131d 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -960,12 +960,11 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, addr)) { - // Ok, let's create a new lease... - ctx.subnet_ = subnet; - // Let's remember the subnet from which the reserved address has been // allocated. We'll use this subnet for allocating other reserved // resources. + ctx.subnet_ = subnet; + if (!ctx.host_subnet_) { ctx.host_subnet_ = subnet; if (!host->getHostname().empty()) { @@ -986,6 +985,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, } } + // Ok, let's create a new lease... Lease6Ptr lease = createLease6(ctx, addr, prefix_len); // ... and add it to the existing leases list. diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index 43e4f5b3f8..1002958cfb 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -1977,28 +1977,103 @@ TEST_F(AllocEngine6Test, reuseReclaimedExpiredViaRequest) { EXPECT_TRUE(testStatistics("reclaimed-leases", 0, subnet_->getID())); } +/// @brief This test class is dedicated to testing shared networks +/// +/// It uses one common configuration: +/// 1 shared network with 2 subnets: +/// - 2001:db8:1::/56 subnet with a small pool of single address +/// - 2001:db8:1::/56 subnet with pool with 64K addresses. +class SharedNetworkAlloc6Test : public AllocEngine6Test { +public: + SharedNetworkAlloc6Test() + :engine_(AllocEngine::ALLOC_ITERATIVE, 0) { + + subnet1_.reset(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); + subnet2_.reset(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); + pool1_.reset(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), + IOAddress("2001:db8:1::1"))); + pool2_.reset(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), + IOAddress("2001:db8:2::FF"))); + subnet1_->addPool(pool1_); + subnet2_->addPool(pool2_); + + // Both subnets belong to the same network so they can be used + // interchangeably. + network_.reset(new SharedNetwork6("test_network")); + network_->add(subnet1_); + network_->add(subnet2_); + } + + Lease6Ptr + insertLease(std::string addr, SubnetID subnet_id) { + Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress(addr), duid_, iaid_, + 501, 502, 503, 504, subnet_->getID(), + HWAddrPtr(), 0)); + lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago + if (!LeaseMgrFactory::instance().addLease(lease)) { + ADD_FAILURE() << "Failed to add a lease for address " << addr + << " in subnet with subnet-id " << subnet_id; + return (Lease6Ptr()); + } + return (lease); + } + + /// Covenience pointers to configuration elements. These are initialized + /// in the constructor and are used throughout the tests. + AllocEngine engine_; + Subnet6Ptr subnet1_; + Subnet6Ptr subnet2_; + Pool6Ptr pool1_; + Pool6Ptr pool2_; + SharedNetwork6Ptr network_; +}; + +// This test verifies that the server can offer an address from a +// subnet and the introduction of shared network doesn't break anything here. +TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkSimple) { + + // Create context which will be used to try to allocate leases from the + // shared network. The context points to subnet1, which address space + // is exhausted. We expect the allocation engine to find another subnet + // within the same shared network and offer an address from there. + Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234)); + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true, + query); + ctx.currentIA().iaid_ = iaid_; + + Lease6Ptr lease; + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); + ASSERT_TRUE(lease); + ASSERT_TRUE(subnet1_->inRange(lease->addr_)); +} + + +// This test verifies that the server can pick a subnet from shared subnets +// based on hints. +TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkHint) { + + // Create context which will be used to try to allocate leases from the + // shared network. There's a hint that points to the subnet2. The + // shared network mechanism should be able to pick the second subnet + // based on it. + Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234)); + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true, + query); + ctx.currentIA().iaid_ = iaid_; + ctx.currentIA().addHint(IOAddress("2001:db8:2::12")); + + Lease6Ptr lease; + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); + ASSERT_TRUE(lease); + + // The second subnet should be selected. + ASSERT_TRUE(subnet2_->inRange(lease->addr_)); +} + // This test verifies that the client is offerred an address from an // alternative subnet within shared network when the address pool is // exhausted in the first address pool. -TEST_F(AllocEngine6Test, solicitSharedNetworkOutOfAddresses) { - boost::scoped_ptr engine; - ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100))); - ASSERT_TRUE(engine); - - Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); - Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); - Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), - IOAddress("2001:db8:1::1"))); - Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), - IOAddress("2001:db8:2::FFFF"))); - subnet1->addPool(pool1); - subnet2->addPool(pool2); - - // Both subnets belong to the same network so they can be used - // interchangeably. - SharedNetwork6Ptr network(new SharedNetwork6("test_network")); - network->add(subnet1); - network->add(subnet2); +TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkOutOfAddresses) { // Create a lease for a single address in the first address pool. The // pool is now exhausted. @@ -2006,7 +2081,7 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkOutOfAddresses) { const uint32_t other_iaid = 3568; Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), other_duid, other_iaid, 501, 502, 503, 504, - subnet1->getID(), + subnet1_->getID(), HWAddrPtr(), 0)); lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease)); @@ -2016,23 +2091,23 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkOutOfAddresses) { // is exhausted. We expect the allocation engine to find another subnet // within the same shared network and offer an address from there. Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234)); - AllocEngine::ClientContext6 ctx(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true, query); ctx.currentIA().iaid_ = iaid_; Lease6Ptr lease2; - ASSERT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease2 = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease2); - ASSERT_TRUE(subnet2->inRange(lease2->addr_)); + ASSERT_TRUE(subnet2_->inRange(lease2->addr_)); // The client having a lease should be offerred this lease, even if // the client starts allocation from the second subnet. The code should // determine that the client has a lease in subnet1 and use this subnet // instead. - AllocEngine::ClientContext6 ctx2(subnet2, other_duid, false, false, "", + AllocEngine::ClientContext6 ctx2(subnet2_, other_duid, false, false, "", true, query); ctx2.currentIA().iaid_ = other_iaid; - ASSERT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx2))); + ASSERT_NO_THROW(lease2 = expectOneLease(engine_.allocateLeases6(ctx2))); ASSERT_TRUE(lease2); ASSERT_EQ("2001:db8:1::1", lease2->addr_.toText()); @@ -2041,65 +2116,46 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkOutOfAddresses) { // Now, try requesting this address by providing a hint. The engine // should try to honor the hint even though we start from the subnet2. - ctx.subnet_ = subnet2; + ctx.subnet_ = subnet2_; ctx.currentIA().hints_.push_back(make_pair(IOAddress("2001:db8:1::1"), 128)); - ASSERT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease2 = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease2); - ASSERT_TRUE(subnet1->inRange(lease2->addr_)); + ASSERT_TRUE(subnet1_->inRange(lease2->addr_)); } // This test verifies that the server can offer an address from a // different subnet than orginally selected, when the address pool in // the first subnet is exhausted. -TEST_F(AllocEngine6Test, solicitSharedNetworkClassification) { - boost::scoped_ptr engine; - ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100))); - ASSERT_TRUE(engine); - - Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); - Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); - Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), - IOAddress("2001:db8:1::1"))); - Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), - IOAddress("2001:db8:2::FFFF"))); - subnet1->addPool(pool1); - subnet2->addPool(pool2); - - // Both subnets belong to the same network so they can be used - // interchangeably. - SharedNetwork6Ptr network(new SharedNetwork6("test_network")); - network->add(subnet1); - network->add(subnet2); - +TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkClassification) { // Try to offer address from subnet1. There is an address available so // it should be offerred. Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234)); - AllocEngine::ClientContext6 ctx(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true, query); ctx.currentIA().iaid_ = iaid_; Lease6Ptr lease; - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease); - ASSERT_TRUE(subnet1->inRange(lease->addr_)); + ASSERT_TRUE(subnet1_->inRange(lease->addr_)); // Apply restrictions on the subnet1. This should be only assigned // to clients belonging to cable-modem class. - subnet1->allowClientClass("cable-modem"); + subnet1_->allowClientClass("cable-modem"); // The allocation engine should determine that the subnet1 is not // available for the client not belonging to the cable-modem class. // Instead, it should offer an address from subnet2 that belongs // to the same shared network. - AllocEngine::ClientContext6 ctx2(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx2(subnet1_, duid_, false, false, "", true, query); ctx2.currentIA().iaid_ = iaid_; ctx2.query_ = query; - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx2))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx2))); ASSERT_TRUE(lease); - ASSERT_TRUE(subnet2->inRange(lease->addr_)); + ASSERT_TRUE(subnet2_->inRange(lease->addr_)); - AllocEngine::ClientContext6 ctx3(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx3(subnet1_, duid_, false, false, "", true, query); ctx3.currentIA().iaid_ = iaid_; ctx3.query_ = query; @@ -2107,24 +2163,24 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkClassification) { // Create host reservation in the first subnet for this client. The // allocation engine should not assign reserved address to the client // because client classification doesn't allow that. - subnet_ = subnet1; + subnet_ = subnet1_; createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128); AllocEngine::findReservation(ctx3); - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease); - ASSERT_TRUE(subnet2->inRange(lease->addr_)); + ASSERT_TRUE(subnet2_->inRange(lease->addr_)); - AllocEngine::ClientContext6 ctx4(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx4(subnet1_, duid_, false, false, "", true, query); ctx4.currentIA().iaid_ = iaid_; ctx4.query_ = query; // Assign cable-modem class and try again. This time, we should - // offer an address from the subnet1. + // offer an address from the subnet1_. ctx4.query_->addClass(ClientClass("cable-modem")); AllocEngine::findReservation(ctx4); - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx4))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx4))); ASSERT_TRUE(lease); EXPECT_EQ("2001:db8:1::1", lease->addr_.toText()); } @@ -2132,35 +2188,16 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkClassification) { // This test verifies that the client is offerred a reserved address // even if this address belongs to another subnet within the same // shared network. -TEST_F(AllocEngine6Test, solicitSharedNetworkReservations) { - boost::scoped_ptr engine; - ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100))); - ASSERT_TRUE(engine); - - Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); - Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); - Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), - IOAddress("2001:db8:1::1"))); - Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), - IOAddress("2001:db8:2::FFFF"))); - subnet1->addPool(pool1); - subnet2->addPool(pool2); - - // Both subnets belong to the same network so they can be used - // interchangeably. - SharedNetwork6Ptr network(new SharedNetwork6("test_network")); - network->add(subnet1); - network->add(subnet2); - +TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkReservations) { // Create reservation for the client in the second subnet. - subnet_ = subnet2; + subnet_ = subnet2_; createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:2::15"), 128); - // Start allocation from subnet1. The engine should determine that the - // client has reservations in subnet2 and should rather assign reserved + // Start allocation from subnet1_. The engine should determine that the + // client has reservations in subnet2_ and should rather assign reserved // addresses. Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234)); - AllocEngine::ClientContext6 ctx(subnet1, duid_, false, false, "", true, + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true, query); ctx.currentIA().iaid_ = iaid_; @@ -2168,7 +2205,7 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkReservations) { AllocEngine::findReservation(ctx); Lease6Ptr lease; - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease); ASSERT_EQ("2001:db8:2::15", lease->addr_.toText()); } @@ -2176,35 +2213,16 @@ TEST_F(AllocEngine6Test, solicitSharedNetworkReservations) { // This test verifies that the client is allocated a reserved address // even if this address belongs to another subnet within the same // shared network. -TEST_F(AllocEngine6Test, requestSharedNetworkReservations) { - boost::scoped_ptr engine; - ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100))); - ASSERT_TRUE(engine); - - Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); - Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); - Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), - IOAddress("2001:db8:1::1"))); - Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), - IOAddress("2001:db8:2::FFFF"))); - subnet1->addPool(pool1); - subnet2->addPool(pool2); - - // Both subnets belong to the same network so they can be used - // interchangeably. - SharedNetwork6Ptr network(new SharedNetwork6("test_network")); - network->add(subnet1); - network->add(subnet2); - +TEST_F(SharedNetworkAlloc6Test, requestSharedNetworkReservations) { // Create reservation for the client in the second subnet. - subnet_ = subnet2; + subnet_ = subnet2_; createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:2::15"), 128); - // Start allocation from subnet1. The engine should determine that the - // client has reservations in subnet2 and should rather assign reserved + // Start allocation from subnet1_. The engine should determine that the + // client has reservations in subnet2_ and should rather assign reserved // addresses. Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); - AllocEngine::ClientContext6 ctx(subnet1, duid_, false, false, "", false, + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", false, query); ctx.currentIA().iaid_ = iaid_; @@ -2212,7 +2230,7 @@ TEST_F(AllocEngine6Test, requestSharedNetworkReservations) { AllocEngine::findReservation(ctx); Lease6Ptr lease; - ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease); ASSERT_EQ("2001:db8:2::15", lease->addr_.toText()); } @@ -2221,32 +2239,13 @@ TEST_F(AllocEngine6Test, requestSharedNetworkReservations) { // shared network, regardless of the default subnet. It also verifies that // the client is assigned a reserved address from a shared network which // replaces existing lease within this shared network. -TEST_F(AllocEngine6Test, requestSharedNetworkExistingLeases) { - boost::scoped_ptr engine; - ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100))); - ASSERT_TRUE(engine); - - Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4)); - Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 56, 1, 2, 3, 4)); - Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), - IOAddress("2001:db8:1::1"))); - Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:2::"), - IOAddress("2001:db8:2::FFFF"))); - subnet1->addPool(pool1); - subnet2->addPool(pool2); - - // Both subnets belong to the same network so they can be used - // interchangeably. - SharedNetwork6Ptr network(new SharedNetwork6("test_network")); - network->add(subnet1); - network->add(subnet2); - +TEST_F(SharedNetworkAlloc6Test, requestSharedNetworkExistingLeases) { // Create a lease in subnet 2 for this client. The lease is in expired // reclaimed state initially to allow for checking whether the lease // gets renewed. Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:2::1"), duid_, iaid_, 501, 502, 503, 504, - subnet2->getID(), HWAddrPtr(), 128)); + subnet2_->getID(), HWAddrPtr(), 128)); lease->state_ = Lease::STATE_EXPIRED_RECLAIMED; ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease)); @@ -2255,29 +2254,29 @@ TEST_F(AllocEngine6Test, requestSharedNetworkExistingLeases) { // allocation engine should determine that there are existing leases // in subnet 2 and renew those. Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); - AllocEngine::ClientContext6 ctx(subnet1, duid_, false, false, "", false, + AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", false, query); ctx.currentIA().iaid_ = iaid_; // Check that we have been allocated the existing lease. Lease6Ptr lease2; - ASSERT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease2 = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease2); EXPECT_EQ("2001:db8:2::1", lease2->addr_.toText()); // Statistics should be bumped when the lease is re-assigned. - EXPECT_TRUE(testStatistics("assigned-nas", 1, subnet2->getID())); + EXPECT_TRUE(testStatistics("assigned-nas", 1, subnet2_->getID())); // Another interesting case is when there is a reservation in a different // subnet than the one from which the ease has been assigned. - subnet_ = subnet1; + subnet_ = subnet1_; createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128); // The reserved lease should take precedence. - ctx.subnet_ = subnet1; + ctx.subnet_ = subnet1_; ctx.currentIA().iaid_ = iaid_; AllocEngine::findReservation(ctx); - ASSERT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_NO_THROW(lease2 = expectOneLease(engine_.allocateLeases6(ctx))); ASSERT_TRUE(lease2); EXPECT_EQ("2001:db8:1::1", lease2->addr_.toText()); @@ -2286,6 +2285,46 @@ TEST_F(AllocEngine6Test, requestSharedNetworkExistingLeases) { EXPECT_EQ("2001:db8:2::1", ctx.currentIA().old_leases_[0]->addr_.toText()); } +// This test verifies that the server can offer an address from a shared +// subnet if there's at least 1 address left there, but will not offer +// anything if both subnets are completely full. +TEST_F(SharedNetworkAlloc6Test, requestRunningOut) { + + // Allocate everything in subnet1 + insertLease("2001:db8:1::1", subnet1_->getID()); + + // Allocate everything, except one address in subnet2. + for (int i = 0; i < 255; i++) { + stringstream tmp; + tmp << "2001:db8:2::" << hex << i; + insertLease(tmp.str(), subnet2_->getID()); + } + + // Create context which will be used to try to allocate leases from the + // shared network. The context points to subnet 1 initially, but the + // allocation engine should determine that there are existing leases + // in subnet 2 and renew those. + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx1(subnet1_, duid_, false, false, "", false, + query); + ctx1.currentIA().iaid_ = iaid_; + + // Check that we have been allocated the existing lease (there's only + // one lease left, so we know exactly which one will be given out. + Lease6Ptr lease; + ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx1))); + ASSERT_TRUE(lease); + EXPECT_EQ("2001:db8:2::ff", lease->addr_.toText()); + + // Ok, now try for anoher client. We should be completely full. + DuidPtr other_duid(new DUID(vector(12, 0xff))); + AllocEngine::ClientContext6 ctx2(subnet2_, other_duid, false, false, "", false, + query); + Lease6Collection leases = engine_.allocateLeases6(ctx2); + + // Bugger off, we're full! + EXPECT_TRUE(leases.empty()); +} }; // namespace test }; // namespace dhcp