From: Tomek Mrugalski Date: Fri, 6 Feb 2015 19:32:06 +0000 (+0100) Subject: [3677] Initial handful of reservation+renewal tests implemented. X-Git-Tag: trac3712_base~7^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4698f4642a71c7b0d676eff236f0f141cd63fa9e;p=thirdparty%2Fkea.git [3677] Initial handful of reservation+renewal tests implemented. --- diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 74b6e99caf..46f6f13354 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -1672,6 +1672,11 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { removeNonreservedLeases6(ctx, leases); } + // If we happen to removed all leases, get something new for this guy. + if (leases.empty()) { + leases = allocateUnreservedLeases6(ctx); + } + // Extend all existing leases that passed all checks. for (Lease6Collection::iterator l = leases.begin(); l != leases.end(); ++l) { extendLease6(ctx, *l); diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc index 241cea224d..ce75253439 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -298,6 +299,98 @@ public: return (lease); } + /// @brief Checks if the simple allocation can succeed + /// + /// The type of lease is determined by pool type (pool->getType() + /// + /// @param pool pool from which the lease will be allocated from + /// @param hint address to be used as a hint + /// @param fake true - this is fake allocation (SOLICIT) + /// @param in_pool specifies whether the lease is expected to be in pool + /// @return allocated lease(s) (may be empty) + Lease6Collection allocateTest(AllocEngine& engine, const Pool6Ptr& pool, + const IOAddress& hint, bool fake, bool in_pool = true) { + Lease::Type type = pool->getType(); + uint8_t expected_len = pool->getLength(); + + AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, + false, false, "", fake); + + Lease6Collection leases; + EXPECT_NO_THROW(leases = engine.allocateLeases6(ctx)); + + for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) { + + // Do all checks on the lease + checkLease6(*it, type, expected_len, in_pool, in_pool); + + // Check that the lease is indeed in LeaseMgr + Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type, + (*it)->addr_); + if (!fake) { + // This is a real (REQUEST) allocation, the lease must be in the DB + EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText() + << " returned by allocateLeases6(), " + << "but was not present in LeaseMgr"; + if (!from_mgr) { + return (leases); + } + + // Now check that the lease in LeaseMgr has the same parameters + detailCompareLease(*it, from_mgr); + } else { + // This is a fake (SOLICIT) allocation, the lease must not be in DB + EXPECT_FALSE(from_mgr) << "Lease " << from_mgr->addr_.toText() + << " returned by allocateLeases6(), " + << "was present in LeaseMgr (expected to be" + << " not present)"; + if (from_mgr) { + return (leases); + } + } + } + + return (leases); + } + + Lease6Collection renewTest(AllocEngine& engine, const Pool6Ptr& pool, + AllocEngine::HintContainer& hints, bool in_pool = true) { + + Lease::Type type = pool->getType(); + uint8_t expected_len = pool->getLength(); + + AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"), + type, false, false, "", false); + ctx.hints_ = hints; + ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 123)); + + Lease6Collection leases = engine.renewLeases6(ctx); + + + for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) { + + // Do all checks on the lease + checkLease6(*it, type, expected_len, in_pool, in_pool); + + // Check that the lease is indeed in LeaseMgr + Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type, + (*it)->addr_); + + // This is a real (REQUEST) allocation, the lease must be in the DB + EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText() + << " returned by allocateLeases6(), " + << "but was not present in LeaseMgr"; + if (!from_mgr) { + return (leases); + } + + // Now check that the lease in LeaseMgr has the same parameters + detailCompareLease(*it, from_mgr); + } + + return (leases); + } + /// @brief Checks if the address allocation with a hint that is in range, /// in pool, but is currently used, can succeed /// @@ -1526,6 +1619,127 @@ TEST_F(AllocEngine6Test, allocateLeasesInvalidData) { } +// Checks whether an address can be renewed (simple case, no reservation tricks) +TEST_F(AllocEngine6Test, addressRenewal) { + AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); + + Lease6Collection leases; + + leases = allocateTest(engine, pool_, IOAddress("::"), false, true); + ASSERT_EQ(1, leases.size()); + + // This is what the client will send in his renew message. + AllocEngine::HintContainer hints; + hints.push_back(make_pair(leases[0]->addr_, 128)); + + Lease6Collection renewed = renewTest(engine, pool_, hints); + ASSERT_EQ(1, renewed.size()); + + // Check that the lease was indeed renewed and hasn't changed + // (i.e. the same address, preferred and valid lifetimes) + + /// @todo: use leaseCompare, but ignore cltt_ + EXPECT_EQ(leases[0]->addr_, renewed[0]->addr_); + EXPECT_EQ(leases[0]->type_, renewed[0]->type_); + EXPECT_EQ(leases[0]->preferred_lft_, renewed[0]->preferred_lft_); + EXPECT_EQ(leases[0]->valid_lft_, renewed[0]->valid_lft_); +} + +// Checks whether an address can be renewed (in-pool reservation) +TEST_F(AllocEngine6Test, reservedAddressRenewal) { + // Create reservation for the client. This is in-pool reservation, + // as the pool is 2001:db8:1::10 - 2001:db8:1::20. + createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1c"), 128); + + AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); + + Lease6Collection leases; + + leases = allocateTest(engine, pool_, IOAddress("::"), false, true); + ASSERT_EQ(1, leases.size()); + ASSERT_EQ("2001:db8:1::1c", leases[0]->addr_.toText()); + + // This is what the client will send in his renew message. + AllocEngine::HintContainer hints; + hints.push_back(make_pair(leases[0]->addr_, 128)); + + Lease6Collection renewed = renewTest(engine, pool_, hints); + ASSERT_EQ(1, renewed.size()); + ASSERT_EQ("2001:db8:1::1c", leases[0]->addr_.toText()); +} + +// Checks whether address can change during renew (if there is a new +// reservation for this client) +TEST_F(AllocEngine6Test, reservedAddressRenewChange) { + + AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); + + Lease6Collection leases; + + leases = allocateTest(engine, pool_, IOAddress("::"), false, true); + ASSERT_EQ(1, leases.size()); + ASSERT_NE("2001:db8:1::1c", leases[0]->addr_.toText()); + + // This is what the client will send in his renew message. + AllocEngine::HintContainer hints; + hints.push_back(make_pair(leases[0]->addr_, 128)); + + // Create reservation for the client. This is in-pool reservation, + // as the pool is 2001:db8:1::10 - 2001:db8:1::20. + createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1c"), 128); + + Lease6Collection renewed = renewTest(engine, pool_, hints); + ASSERT_EQ(1, renewed.size()); + ASSERT_EQ("2001:db8:1::1c", renewed[0]->addr_.toText()); +} + +// Checks whether address can change during renew (if there is a new +// reservation for this address for another client) +TEST_F(AllocEngine6Test, reservedAddressRenewReserved) { + + AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100); + + Lease6Collection leases; + + leases = allocateTest(engine, pool_, IOAddress("::"), false, true); + ASSERT_EQ(1, leases.size()); + + // This is what the client will send in his renew message. + AllocEngine::HintContainer hints; + hints.push_back(make_pair(leases[0]->addr_, 128)); + + // Create reservation for this address, but for another client. + // This is in-pool reservation, as the pool is 2001:db8:1::10 - 2001:db8:1::20. + HostPtr host = createHost6(false, IPv6Resrv::TYPE_NA, leases[0]->addr_, 128); + + // We need to tweak reservation id: use a different DUID for client Y + vector other_duid(8, 0x45); + host->setIdentifier(&other_duid[0], other_duid.size(), Host::IDENT_DUID); + // Ok, now add it to the HostMgr + CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); + CfgMgr::instance().commit(); + + Lease6Collection renewed = renewTest(engine, pool_, hints); + ASSERT_EQ(1, renewed.size()); + + // Check that we no longer have the reserved address. + ASSERT_NE(leases[0]->addr_.toText(), renewed[0]->addr_.toText()); + + // Check that the lease for the now reserved address is no longer in + // the lease database. + Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, + leases[0]->addr_); + EXPECT_FALSE(from_mgr); +} + + +TEST_F(AllocEngine6Test, prefixRenewal) { + + +} + + + /// @todo: The following methods are tested indirectly by allocateLeases6() /// tests, but could use more direct testing: /// - AllocEngine::allocateUnreservedLeases6