From: Razvan Becheriu Date: Tue, 9 Apr 2019 14:54:16 +0000 (+0300) Subject: make allocation engine thread safe X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87b52af7033da4ad9af932410037b155af5b57c6;p=thirdparty%2Fkea.git make allocation engine thread safe --- diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index df3d1b085f..2c665e746c 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -32,21 +33,22 @@ #include #include -#include #include -#include +#include #include #include #include +#include + using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::dhcp_ddns; using namespace isc::hooks; using namespace isc::stats; +using namespace isc::util::thread; namespace { - /// Structure that holds registered hook indexes struct AllocEngineHooks { int hook_index_lease4_select_; ///< index for "lease4_receive" hook point @@ -79,13 +81,12 @@ struct AllocEngineHooks { // module is called. AllocEngineHooks Hooks; -}; // anonymous namespace +} // namespace namespace isc { namespace dhcp { - -AllocEngine::IterativeAllocator::IterativeAllocator(Lease::Type lease_type) - :Allocator(lease_type) { +AllocEngine::IterativeAllocator::IterativeAllocator(Lease::Type lease_type) : + Allocator(lease_type) { } isc::asiolink::IOAddress @@ -160,6 +161,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet, const ClientClasses& client_classes, const DuidPtr&, const IOAddress&) { + LockGuard lock(&mutex_); // Is this prefix allocation? bool prefix = pool_type_ == Lease::TYPE_PD; @@ -284,12 +286,11 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet, return (last); } -AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type) - :Allocator(lease_type) { +AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type) : + Allocator(lease_type) { isc_throw(NotImplemented, "Hashed allocator is not implemented"); } - isc::asiolink::IOAddress AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&, const ClientClasses&, @@ -298,12 +299,11 @@ AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&, isc_throw(NotImplemented, "Hashed allocator is not implemented"); } -AllocEngine::RandomAllocator::RandomAllocator(Lease::Type lease_type) - :Allocator(lease_type) { +AllocEngine::RandomAllocator::RandomAllocator(Lease::Type lease_type) : + Allocator(lease_type) { isc_throw(NotImplemented, "Random allocator is not implemented"); } - isc::asiolink::IOAddress AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&, const ClientClasses&, @@ -312,12 +312,9 @@ AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&, isc_throw(NotImplemented, "Random allocator is not implemented"); } - -AllocEngine::AllocEngine(AllocType engine_type, uint64_t attempts, - bool ipv6) - : attempts_(attempts), incomplete_v4_reclamations_(0), - incomplete_v6_reclamations_(0) { - +AllocEngine::AllocEngine(AllocType engine_type, uint64_t attempts, bool ipv6) : + attempts_(attempts), incomplete_v4_reclamations_(0), + incomplete_v6_reclamations_(0) { // Choose the basic (normal address) lease type Lease::Type basic_type = ipv6 ? Lease::TYPE_NA : Lease::TYPE_V4; @@ -376,7 +373,6 @@ AllocEngine::AllocatorPtr AllocEngine::getAllocator(Lease::Type type) { } // end of namespace isc namespace { - /// @brief Checks if the specified address belongs to one of the subnets /// within a shared network. /// @@ -395,8 +391,8 @@ inAllowedPool(AllocEngine::ClientContext6& ctx, const Lease::Type& lease_type, // If the subnet belongs to a shared network we will be iterating // over the subnets that belong to this shared network. Subnet6Ptr current_subnet = ctx.subnet_; - while (current_subnet) { + while (current_subnet) { if (current_subnet->clientSupported(ctx.query_->getClasses())) { if (check_subnet) { if (current_subnet->inPool(lease_type, address)) { @@ -418,14 +414,12 @@ inAllowedPool(AllocEngine::ClientContext6& ctx, const Lease::Type& lease_type, } - // ########################################################################## // # DHCPv6 lease allocation code starts here. // ########################################################################## namespace isc { namespace dhcp { - AllocEngine::ClientContext6::ClientContext6() : query_(), fake_allocation_(false), subnet_(), host_subnet_(), duid_(), hwaddr_(), host_identifiers_(), hosts_(), fwd_dns_update_(false), @@ -445,7 +439,6 @@ AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns), hostname_(hostname), callout_handle_(callout_handle), allocated_resources_(), new_leases_(), ias_() { - // Initialize host identifiers. if (duid) { addHostIdentifier(Host::IDENT_DUID, duid->getDuid()); @@ -568,7 +561,6 @@ void AllocEngine::findReservation(ClientContext6& ctx) { // We can only search for the reservation if a subnet has been selected. while (subnet) { - // Only makes sense to get reservations if the client has access // to the class and host reservations are enabled. if (subnet->clientSupported(ctx.query_->getClasses()) && @@ -580,7 +572,6 @@ void AllocEngine::findReservation(ClientContext6& ctx) { if (host_map.count(subnet->getID()) > 0) { ctx.hosts_[subnet->getID()] = host_map[subnet->getID()]; } - } else { // Attempt to find a host using a specified identifier. ConstHostPtr host = HostMgr::instance().get6(subnet->getID(), @@ -594,7 +585,6 @@ void AllocEngine::findReservation(ClientContext6& ctx) { } } } - } // We need to get to the next subnet if this is a shared network. If it @@ -621,10 +611,8 @@ AllocEngine::findGlobalReservation(ClientContext6& ctx) { return (host); } - Lease6Collection AllocEngine::allocateLeases6(ClientContext6& ctx) { - try { if (!ctx.subnet_) { isc_throw(InvalidOperation, "Subnet is required for IPv6 lease allocation"); @@ -672,7 +660,6 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { // Case 1: There are no leases and there's a reservation for this host. if (leases.empty() && !ctx.hosts_.empty()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_ALLOC_NO_LEASES_HR) .arg(ctx.query_->getLabel()); @@ -696,7 +683,6 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { // We will return these leases for the client, but we may need to update // FQDN information. } else if (!leases.empty() && ctx.hosts_.empty()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_ALLOC_LEASES_NO_HR) .arg(ctx.query_->getLabel()); @@ -715,7 +701,6 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { // Case 3: There are leases and there are reservations. } else if (!leases.empty() && !ctx.hosts_.empty()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_ALLOC_LEASES_HR) .arg(ctx.query_->getLabel()); @@ -787,10 +772,7 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { } return (leases); } - - } catch (const isc::Exception& e) { - // Some other error, return an empty lease. LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_ALLOC_ERROR) .arg(ctx.query_->getLabel()) @@ -802,7 +784,6 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) { Lease6Collection AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { - AllocatorPtr allocator = getAllocator(ctx.currentIA().type_); if (!allocator) { @@ -826,7 +807,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { CalloutHandle::CalloutNextStep callout_status = CalloutHandle::NEXT_STEP_CONTINUE; while (subnet) { - if (!subnet->clientSupported(ctx.query_->getClasses())) { subnet = subnet->getNextSubnet(original_subnet); continue; @@ -837,8 +817,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // check if the hint is in pool and is available // This is equivalent of subnet->inPool(hint), but returns the pool pool = boost::dynamic_pointer_cast - (subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), - hint)); + (subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), hint)); // check if the pool is allowed if (pool && !pool->clientSupported(ctx.query_->getClasses())) { @@ -846,15 +825,14 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } if (pool) { - // Check which host reservation mode is supported in this subnet. Network::HRMode hr_mode = subnet->getHostReservationMode(); /// @todo: We support only one hint for now Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, hint); - if (!lease) { + if (!lease) { // In-pool reservations: Check if this address is reserved for someone // else. There is no need to check for whom it is reserved, because if // it has been reserved for us we would have already allocated a lease. @@ -877,7 +855,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // no longer usable and we need to continue the regular // allocation path. if (lease) { - /// @todo: We support only one lease per ia for now Lease6Collection collection; collection.push_back(lease); @@ -889,12 +866,9 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { .arg(ctx.query_->getLabel()) .arg(hint.toText()); } - } else { - // If the lease is expired, we may likely reuse it, but... if (lease->expired()) { - ConstHostPtr host; if (hr_mode != Network::HR_DISABLED) { host = HostMgr::instance().get6(subnet->getID(), hint); @@ -902,7 +876,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // Let's check if there is a reservation for this address. if (!host) { - // Copy an existing, expired lease so as it can be returned // to the caller. Lease6Ptr old_lease(new Lease6(*lease)); @@ -915,7 +888,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { /// @todo: We support only one lease per ia for now leases.push_back(lease); return (leases); - } else { LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_EXPIRED_HINT_RESERVED) @@ -954,7 +926,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { ctx.subnet_ = subnet = original_subnet; while (subnet) { - if (!subnet->clientSupported(ctx.query_->getClasses())) { subnet = subnet->getNextSubnet(original_subnet); continue; @@ -985,7 +956,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } for (uint64_t i = 0; i < max_attempts; ++i) { - ++total_attempts; IOAddress candidate = allocator->pickAddress(subnet, @@ -998,7 +968,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { /// it has been reserved for us we would have already allocated a lease. if (hr_mode == Network::HR_ALL && HostMgr::instance().get6(subnet->getID(), candidate)) { - // Don't allocate. continue; } @@ -1017,12 +986,11 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, - candidate); - if (!existing) { + candidate); + if (!existing) { // there's no existing lease for selected candidate, so it is // free. Let's allocate it. - ctx.subnet_ = subnet; Lease6Ptr lease = createLease6(ctx, candidate, prefix_len, callout_status); if (lease) { @@ -1032,7 +1000,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { leases.push_back(lease); return (leases); - } else if (ctx.callout_handle_ && (callout_status != CalloutHandle::NEXT_STEP_CONTINUE)) { // Don't retry when the callout status is not continue. @@ -1074,7 +1041,6 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { void AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& existing_leases) { - // If there are no reservations or the reservation is v4, there's nothing to do. if (ctx.hosts_.empty()) { LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, @@ -1154,7 +1120,6 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Subnet6Ptr subnet = ctx.subnet_; while (subnet) { - SubnetID subnet_id = subnet->getID(); // No hosts for this subnet or the subnet not supported. @@ -1181,9 +1146,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // If there's a lease for this address, let's not create it. // It doesn't matter whether it is for this client or for someone else. - if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, - addr)) { - + if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, addr)) { // Let's remember the subnet from which the reserved address has been // allocated. We'll use this subnet for allocating other reserved // resources. @@ -1216,7 +1179,6 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // ... and add it to the existing leases list. existing_leases.push_back(lease); - if (ctx.currentIA().type_ == Lease::TYPE_NA) { LOG_INFO(alloc_engine_logger, ALLOC_ENGINE_V6_HR_ADDR_GRANTED) .arg(addr.toText()) @@ -1239,7 +1201,6 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // would work for any number of reservations. return; } - } subnet = subnet->getNextSubnet(ctx.subnet_); @@ -1315,7 +1276,6 @@ AllocEngine::allocateGlobalReservedLeases6(ClientContext6& ctx, // If there's a lease for this address, let's not create it. // It doesn't matter whether it is for this client or for someone else. if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, addr)) { - if (!ghost->getHostname().empty()) { // If there is a hostname reservation here we should stick // to this reservation. By updating the hostname in the @@ -1495,7 +1455,6 @@ AllocEngine::removeNonmatchingReservedNoHostLeases6(ClientContext6& ctx, bool AllocEngine::removeLeases(Lease6Collection& container, const asiolink::IOAddress& addr) { - bool removed = false; for (Lease6Collection::iterator lease = container.begin(); lease != container.end(); ++lease) { @@ -1528,7 +1487,6 @@ AllocEngine::removeNonreservedLeases6(ClientContext6& ctx, // leases for deletion, by setting appropriate pointers to NULL. for (Lease6Collection::iterator lease = existing_leases.begin(); lease != existing_leases.end(); ++lease) { - // If there is reservation for this keep it. IPv6Resrv resv = makeIPv6Resrv(*(*lease)); if (ctx.hasGlobalReservation(resv) || @@ -1565,7 +1523,6 @@ AllocEngine::removeNonreservedLeases6(ClientContext6& ctx, // If there's only one lease left, break the loop. break; } - } // Remove all elements that we previously marked for deletion (those that @@ -1578,7 +1535,6 @@ Lease6Ptr AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx, uint8_t prefix_len, CalloutHandle::CalloutNextStep& callout_status) { - if (!expired->expired()) { isc_throw(BadValue, "Attempt to recycle lease that is still valid"); } @@ -1617,7 +1573,6 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx, // Let's execute all callouts registered for lease6_select if (ctx.callout_handle_ && HooksManager::getHooksManager().calloutsPresent(hook_index_lease6_select_)) { - // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -1691,7 +1646,6 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, const IOAddress& addr, uint8_t prefix_len, CalloutHandle::CalloutNextStep& callout_status) { - if (ctx.currentIA().type_ != Lease::TYPE_PD) { prefix_len = 128; // non-PD lease types must be always /128 } @@ -1709,7 +1663,6 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, // Let's execute all callouts registered for lease6_select if (ctx.callout_handle_ && HooksManager::getHooksManager().calloutsPresent(hook_index_lease6_select_)) { - // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -1807,12 +1760,12 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { *ctx.duid_, ctx.currentIA().iaid_, subnet->getID()); + leases.insert(leases.end(), leases_subnet.begin(), leases_subnet.end()); subnet = subnet->getNextSubnet(ctx.subnet_); } - if (!leases.empty()) { LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_RENEW_REMOVE_RESERVED) @@ -1824,7 +1777,6 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { } if (!ctx.hosts_.empty()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_RENEW_HR) .arg(ctx.query_->getLabel()); @@ -1844,7 +1796,6 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { // new leases during renewals. This is controlled with the // allow_new_leases_in_renewals_ field. if (leases.empty()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_EXTEND_ALLOC_UNRESERVED) .arg(ctx.query_->getLabel()); @@ -1873,9 +1824,7 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { } return (leases); - } catch (const isc::Exception& e) { - // Some other error, return an empty lease. LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_EXTEND_ERROR) .arg(ctx.query_->getLabel()) @@ -1887,7 +1836,6 @@ AllocEngine::renewLeases6(ClientContext6& ctx) { void AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { - if (!lease || !ctx.subnet_) { return; } @@ -2028,7 +1976,6 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { // Now that the lease has been reclaimed, we can go ahead and update it // in the lease database. LeaseMgrFactory::instance().updateLease6(lease); - } else { // Copy back the original date to the lease. For MySQL it doesn't make // much sense, but for memfile, the Lease6Ptr points to the actual lease @@ -2042,7 +1989,6 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { ctx.currentIA().changed_leases_.push_back(old_data); } - Lease6Collection AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases) { Lease6Collection updated_leases; @@ -2053,8 +1999,8 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases lease->fqdn_fwd_ = ctx.fwd_dns_update_; lease->fqdn_rev_ = ctx.rev_dns_update_; lease->hostname_ = ctx.hostname_; - if (!ctx.fake_allocation_) { + if (!ctx.fake_allocation_) { if (lease->state_ == Lease::STATE_EXPIRED_RECLAIMED) { // Transition lease state to default (aka assigned) lease->state_ = Lease::STATE_DEFAULT; @@ -2097,7 +2043,6 @@ void AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeout, const bool remove_lease, const uint16_t max_unwarned_cycles) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_LEASES_RECLAMATION_START) .arg(max_leases) @@ -2127,7 +2072,6 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo leases.pop_back(); incomplete_reclamation = true; } - } else { // If there is no limitation on the number of leases to reclaim, // we will try to process all. Hence, we don't mark it as incomplete @@ -2145,12 +2089,10 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo size_t leases_processed = 0; BOOST_FOREACH(Lease6Ptr lease, leases) { - try { // Reclaim the lease. reclaimExpiredLease(lease, remove_lease, callout_handle); ++leases_processed; - } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED) .arg(lease->addr_.toText()) @@ -2199,7 +2141,6 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo // We issued a warning, so let's now reset the counter. incomplete_v6_reclamations_ = 0; } - } else { // This was a complete reclamation, so let's reset the counter. incomplete_v6_reclamations_ = 0; @@ -2220,7 +2161,6 @@ AllocEngine::deleteExpiredReclaimedLeases6(const uint32_t secs) { // Try to delete leases from the lease database. LeaseMgr& lease_mgr = LeaseMgrFactory::instance(); deleted_leases = lease_mgr.deleteExpiredReclaimedLeases6(secs); - } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_RECLAIMED_LEASES_DELETE_FAILED) .arg(ex.what()); @@ -2231,12 +2171,10 @@ AllocEngine::deleteExpiredReclaimedLeases6(const uint32_t secs) { .arg(deleted_leases); } - void AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeout, const bool remove_lease, const uint16_t max_unwarned_cycles) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_LEASES_RECLAMATION_START) .arg(max_leases) @@ -2266,7 +2204,6 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo leases.pop_back(); incomplete_reclamation = true; } - } else { // If there is no limitation on the number of leases to reclaim, // we will try to process all. Hence, we don't mark it as incomplete @@ -2274,7 +2211,6 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo lease_mgr.getExpiredLeases4(leases, max_leases); } - // Do not initialize the callout handle until we know if there are any // lease4_expire callouts installed. CalloutHandlePtr callout_handle; @@ -2285,12 +2221,10 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo size_t leases_processed = 0; BOOST_FOREACH(Lease4Ptr lease, leases) { - try { // Reclaim the lease. reclaimExpiredLease(lease, remove_lease, callout_handle); ++leases_processed; - } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED) .arg(lease->addr_.toText()) @@ -2339,7 +2273,6 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo // We issued a warning, so let's now reset the counter. incomplete_v4_reclamations_ = 0; } - } else { // This was a complete reclamation, so let's reset the counter. incomplete_v4_reclamations_ = 0; @@ -2373,7 +2306,6 @@ void AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease, const DbReclaimMode& reclaim_mode, const CalloutHandlePtr& callout_handle) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V6_LEASE_RECLAIM) .arg(Pkt6::makeLabel(lease->duid_, lease->hwaddr_)) @@ -2385,8 +2317,8 @@ AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease, // it reclaims the lease itself. In this case the reclamation routine // will not update DNS nor update the database. bool skipped = false; - if (callout_handle) { + if (callout_handle) { // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -2407,7 +2339,6 @@ AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease, /// Not sure if we need to support every possible status everywhere. if (!skipped) { - // Generate removal name change request for D2, if required. // This will return immediately if the DNS wasn't updated // when the lease was created. @@ -2447,14 +2378,12 @@ AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease, lease->subnet_id_, "assigned-nas"), int64_t(-1)); - } else if (lease->type_ == Lease::TYPE_PD) { // IA_PD StatsMgr::instance().addValue(StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-pds"), int64_t(-1)); - } // Increase total number of reclaimed leases. @@ -2471,7 +2400,6 @@ void AllocEngine::reclaimExpiredLease(const Lease4Ptr& lease, const DbReclaimMode& reclaim_mode, const CalloutHandlePtr& callout_handle) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_LEASE_RECLAIM) .arg(Pkt4::makeLabel(lease->hwaddr_, lease->client_id_)) @@ -2482,8 +2410,8 @@ AllocEngine::reclaimExpiredLease(const Lease4Ptr& lease, // it reclaims the lease itself. In this case the reclamation routine // will not update DNS nor update the database. bool skipped = false; - if (callout_handle) { + if (callout_handle) { // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -2503,7 +2431,6 @@ AllocEngine::reclaimExpiredLease(const Lease4Ptr& lease, /// Not sure if we need to support every possible status everywhere. if (!skipped) { - // Generate removal name change request for D2, if required. // This will return immediately if the DNS wasn't updated // when the lease was created. @@ -2563,7 +2490,6 @@ AllocEngine::deleteExpiredReclaimedLeases4(const uint32_t secs) { // Try to delete leases from the lease database. LeaseMgr& lease_mgr = LeaseMgrFactory::instance(); deleted_leases = lease_mgr.deleteExpiredReclaimedLeases4(secs); - } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_RECLAIMED_LEASES_DELETE_FAILED) .arg(ex.what()); @@ -2576,13 +2502,11 @@ AllocEngine::deleteExpiredReclaimedLeases4(const uint32_t secs) { bool AllocEngine::reclaimDeclined(const Lease4Ptr& lease) { - if (!lease || (lease->state_ != Lease::STATE_DECLINED) ) { return (true); } if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease4_recover_)) { - // Let's use a static callout handle. It will be initialized the first // time lease4_recover is called and will keep to that value. static CalloutHandlePtr callout_handle; @@ -2637,13 +2561,11 @@ AllocEngine::reclaimDeclined(const Lease4Ptr& lease) { bool AllocEngine::reclaimDeclined(const Lease6Ptr& lease) { - if (!lease || (lease->state_ != Lease::STATE_DECLINED) ) { return (true); } if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_recover_)) { - // Let's use a static callout handle. It will be initialized the first // time lease6_recover is called and will keep to that value. static CalloutHandlePtr callout_handle; @@ -2697,20 +2619,17 @@ AllocEngine::reclaimDeclined(const Lease6Ptr& lease) { return (true); } - template void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease, const bool remove_lease, const boost::function& lease_update_fun) const { - LeaseMgr& lease_mgr = LeaseMgrFactory::instance(); // Reclaim the lease - depending on the configuration, set the // expired-reclaimed state or simply remove it. if (remove_lease) { lease_mgr.deleteLease(lease->addr_); - } else if (!lease_update_fun.empty()) { // Clear FQDN information as we have already sent the // name change request to remove the DNS record. @@ -2719,7 +2638,6 @@ void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease, lease->fqdn_rev_ = false; lease->state_ = Lease::STATE_EXPIRED_RECLAIMED; lease_update_fun(lease); - } else { return; } @@ -2730,16 +2648,14 @@ void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease, .arg(lease->addr_.toText()); } - -} // end of isc::dhcp namespace -} // end of isc namespace +} // namespace dhcp +} // namespace isc // ########################################################################## // # DHCPv4 lease allocation code starts here. // ########################################################################## namespace { - /// @brief Check if the specific address is reserved for another client. /// /// This function finds a host reservation for a given address and then @@ -2854,7 +2770,6 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease) // Iterate over the subnets within the shared network to see if any client's // lease belongs to them. while (subnet) { - // If client identifier has been supplied and the server wasn't // explicitly configured to ignore client identifiers for this subnet // check if there is a lease within this subnet. @@ -2878,7 +2793,6 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease) // If no lease found using the client identifier, try the lookup using // the HW address. if (!client_lease && ctx.hwaddr_) { - // Rewind to the first subnet. subnet = original_subnet; @@ -2931,8 +2845,8 @@ inAllowedPool(AllocEngine::ClientContext4& ctx, const IOAddress& address) { // If the subnet belongs to a shared network we will be iterating // over the subnets that belong to this shared network. Subnet4Ptr current_subnet = ctx.subnet_; - while (current_subnet) { + while (current_subnet) { if (current_subnet->inPool(Lease::TYPE_V4, address, ctx.query_->getClasses())) { // We found a subnet that this address belongs to, so it @@ -2949,11 +2863,10 @@ inAllowedPool(AllocEngine::ClientContext4& ctx, const IOAddress& address) { return (false); } -} // end of anonymous namespace +} // namespace namespace isc { namespace dhcp { - AllocEngine::ClientContext4::ClientContext4() : subnet_(), clientid_(), hwaddr_(), requested_address_(IOAddress::IPV4_ZERO_ADDRESS()), @@ -2977,7 +2890,6 @@ AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet, hostname_(hostname), callout_handle_(), fake_allocation_(fake_allocation), old_lease_(), new_lease_(), hosts_(), host_identifiers_() { - // Initialize host identifiers. if (hwaddr) { addHostIdentifier(Host::IDENT_HWADDR, hwaddr->hwaddr_); @@ -3027,11 +2939,9 @@ AllocEngine::allocateLease4(ClientContext4& ctx) { if (ctx.fake_allocation_) { return (discoverLease4(ctx)); - } else { ctx.new_lease_ = requestLease4(ctx); } - } catch (const isc::Exception& e) { // Some other error, return an empty lease. LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_ALLOC_ERROR) @@ -3099,7 +3009,6 @@ AllocEngine::findReservation(ClientContext4& ctx) { // We can only search for the reservation if a subnet has been selected. while (subnet) { - // Only makes sense to get reservations if the client has access // to the class. if (subnet->clientSupported(ctx.query_->getClasses()) && @@ -3112,7 +3021,6 @@ AllocEngine::findReservation(ClientContext4& ctx) { ctx.hosts_[subnet->getID()] = host_map[subnet->getID()]; break; } - } else { // Attempt to find a host using a specified identifier. ConstHostPtr host = HostMgr::instance().get4(subnet->getID(), @@ -3152,7 +3060,6 @@ AllocEngine::findGlobalReservation(ClientContext4& ctx) { return (host); } - Lease4Ptr AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { // Find an existing lease for this client. This function will return true @@ -3170,7 +3077,6 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { // Check if there is a reservation for the client. If there is, we want to // assign the reserved address, rather than any other one. if (hasAddressReservation(ctx)) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_DISCOVER_HR) .arg(ctx.query_->getLabel()) @@ -3196,7 +3102,6 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { .arg(ctx.conflicting_lease_ ? ctx.conflicting_lease_->toText() : "(no lease info)"); } - } else { new_lease = renewLease4(client_lease, ctx); } @@ -3213,7 +3118,6 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { // which the reservation has just been removed. if (!new_lease && client_lease && inAllowedPool(ctx, client_lease->addr_) && !addressReserved(client_lease->addr_, ctx)) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_OFFER_EXISTING_LEASE) .arg(ctx.query_->getLabel()); @@ -3231,7 +3135,6 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { if (!new_lease && !ctx.requested_address_.isV4Zero() && inAllowedPool(ctx, ctx.requested_address_) && !addressReserved(ctx.requested_address_, ctx)) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_OFFER_REQUESTED_LEASE) .arg(ctx.requested_address_.toText()) @@ -3245,7 +3148,6 @@ AllocEngine::discoverLease4(AllocEngine::ClientContext4& ctx) { // addresses. We will now use the allocator to pick the address // from the dynamic pool. if (!new_lease) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_OFFER_NEW_LEASE) .arg(ctx.query_->getLabel()); @@ -3272,9 +3174,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { Lease4Ptr client_lease; findClientLease(ctx, client_lease); - // Obtain the sole instance of the LeaseMgr. - LeaseMgr& lease_mgr = LeaseMgrFactory::instance(); - // When the client sends the DHCPREQUEST, it should always specify the // address which it is requesting or renewing. That is, the client should // either use the requested IP address option or set the ciaddr. However, @@ -3286,7 +3185,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { // is not reserved for another client. If it is, stop here because // we can't allocate this address. if (addressReserved(ctx.requested_address_, ctx)) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_ADDRESS_RESERVED) .arg(ctx.query_->getLabel()) @@ -3294,7 +3192,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { return (Lease4Ptr()); } - } else if (hasAddressReservation(ctx)) { // The client hasn't specified an address to allocate, so the // allocation engine needs to find an appropriate address. @@ -3319,7 +3216,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { if (existing && !existing->expired() && !existing->belongsToClient(ctx.hwaddr_, ctx.subnet_->getMatchClientId() ? ctx.clientid_ : ClientIdPtr())) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_IN_USE) .arg(ctx.query_->getLabel()) @@ -3341,7 +3237,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { // address, return NULL. The client should go back to the // DHCPDISCOVER and the reserved address will be offered. if (!existing || existing->expired()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_INVALID) .arg(ctx.query_->getLabel()) @@ -3358,7 +3253,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { if ((!hasAddressReservation(ctx) || (ctx.currentHost()->getIPv4Reservation() != ctx.requested_address_)) && !inAllowedPool(ctx, ctx.requested_address_)) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_OUT_OF_POOL) .arg(ctx.query_->getLabel()) @@ -3381,7 +3275,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { ctx.requested_address_.isV4Zero()) && (hasAddressReservation(ctx) || inAllowedPool(ctx, client_lease->addr_))) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_EXTEND_LEASE) .arg(ctx.query_->getLabel()) @@ -3398,7 +3291,6 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { // The client doesn't have the lease or it is requesting an address // which it doesn't have. Let's try to allocate the requested address. if (!ctx.requested_address_.isV4Zero()) { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_ALLOC_REQUESTED) .arg(ctx.query_->getLabel()) @@ -3412,9 +3304,7 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { CalloutHandle::CalloutNextStep callout_status = CalloutHandle::NEXT_STEP_CONTINUE; new_lease = allocateOrReuseLease4(ctx.requested_address_, ctx, callout_status); - } else { - LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, ALLOC_ENGINE_V4_REQUEST_PICK_ADDRESS) .arg(ctx.query_->getLabel()); @@ -3436,7 +3326,7 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) { .arg(ctx.query_->getLabel()) .arg(client_lease->addr_.toText()); - lease_mgr.deleteLease(client_lease->addr_); + LeaseMgrFactory::instance().deleteLease(client_lease->addr_); // Need to decrease statistic for assigned addresses. StatsMgr::instance().addValue( @@ -3481,7 +3371,6 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, // Let's execute all callouts registered for lease4_select if (ctx.callout_handle_ && HooksManager::getHooksManager().calloutsPresent(hook_index_lease4_select_)) { - // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -3529,8 +3418,8 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, if (!ctx.fake_allocation_) { // That is a real (REQUEST) allocation bool status = LeaseMgrFactory::instance().addLease(lease); - if (status) { + if (status) { // The lease insertion succeeded, let's bump up the statistic. StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), "assigned-addresses"), @@ -3581,7 +3470,6 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, // involves execution of hooks and DNS update. if (ctx.old_lease_->expired()) { reclaimExpiredLease(ctx.old_lease_, ctx.callout_handle_); - } lease->state_ = Lease::STATE_DEFAULT; @@ -3591,7 +3479,6 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, // Execute all callouts registered for lease4_renew. if (HooksManager::getHooksManager(). calloutsPresent(Hooks.hook_index_lease4_renew_)) { - // Use the RAII wrapper to make sure that the callout handle state is // reset when this object goes out of scope. All hook points must do // it to prevent possible circular dependency between the callout @@ -3648,6 +3535,7 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, static_cast(1)); } } + if (skip) { // Rollback changes (really useful only for memfile) /// @todo: remove this? @@ -3687,7 +3575,6 @@ AllocEngine::reuseExpiredLease4(Lease4Ptr& expired, // Let's execute all callouts registered for lease4_select if (ctx.callout_handle_ && HooksManager::getHooksManager() .calloutsPresent(hook_index_lease4_select_)) { - // Enable copying options from the packet within hook library. ScopedEnableOptionsCopy query4_options_copy(ctx.query_); @@ -3764,14 +3651,12 @@ AllocEngine::allocateOrReuseLease4(const IOAddress& candidate, ClientContext4& c if (exist_lease->expired()) { ctx.old_lease_ = Lease4Ptr(new Lease4(*exist_lease)); return (reuseExpiredLease4(exist_lease, ctx, callout_status)); - } else { // If there is a lease and it is not expired, pass this lease back // to the caller in the context. The caller may need to know // which lease we're conflicting with. ctx.conflicting_lease_ = exist_lease; } - } else { return (createLease4(ctx, candidate, callout_status)); } @@ -3807,8 +3692,8 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { Subnet4Ptr original_subnet = subnet; uint64_t total_attempts = 0; - while (subnet) { + while (subnet) { ClientIdPtr client_id; if (subnet->getMatchClientId()) { client_id = ctx.clientid_; @@ -3832,14 +3717,12 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { ctx.requested_address_); // If address is not reserved for another client, try to allocate it. if (!addressReserved(candidate, ctx)) { - // The call below will return the non-NULL pointer if we // successfully allocate this lease. This means that the // address is not in use by another client. new_lease = allocateOrReuseLease4(candidate, ctx, callout_status); if (new_lease) { return (new_lease); - } else if (ctx.callout_handle_ && (callout_status != CalloutHandle::NEXT_STEP_CONTINUE)) { // Don't retry when the callout status is not continue. @@ -3889,5 +3772,5 @@ AllocEngine::conditionalExtendLifetime(Lease& lease) const { return (true); } -}; // end of isc::dhcp namespace -}; // end of isc namespace +} // namespace dhcp +} // namespace isc diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index f3fb6760f6..74758d0187 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -55,14 +56,12 @@ public: /// @todo: Does not handle out of allocation attempts well class AllocEngine : public boost::noncopyable { protected: - /// @brief base class for all address/prefix allocation algorithms /// /// This is an abstract class that should not be used directly, but rather /// specialized implementations should be used instead. class Allocator { public: - /// @brief picks one address out of available pools in a given subnet /// /// This method returns one address from the available pools in the @@ -104,8 +103,8 @@ protected: /// @brief virtual destructor virtual ~Allocator() { } - protected: + protected: /// @brief defines pool type allocation Lease::Type pool_type_; }; @@ -121,7 +120,6 @@ protected: /// over). class IterativeAllocator : public Allocator { public: - /// @brief default constructor /// /// Does not do anything @@ -140,8 +138,8 @@ protected: const ClientClasses& client_classes, const DuidPtr& duid, const isc::asiolink::IOAddress& hint); - protected: + protected: /// @brief Returns the next prefix /// /// This method works for IPv6 addresses only. It increases the @@ -169,6 +167,8 @@ protected: increaseAddress(const isc::asiolink::IOAddress& address, bool prefix, const uint8_t prefix_len); + private: + std::mutex mutex_; }; /// @brief Address/prefix allocator that gets an address based on a hash @@ -176,7 +176,6 @@ protected: /// @todo: This is a skeleton class for now and is missing an implementation. class HashedAllocator : public Allocator { public: - /// @brief default constructor (does nothing) /// @param type - specifies allocation type HashedAllocator(Lease::Type type); @@ -202,7 +201,6 @@ protected: /// @todo: This is a skeleton class for now and is missing an implementation. class RandomAllocator : public Allocator { public: - /// @brief default constructor (does nothing) /// @param type - specifies allocation type RandomAllocator(Lease::Type type); @@ -224,7 +222,6 @@ protected: }; public: - /// @brief specifies allocation type typedef enum { ALLOC_ITERATIVE, // iterative - one address after another @@ -256,7 +253,6 @@ public: AllocatorPtr getAllocator(Lease::Type type); private: - /// @brief a pointer to currently used allocator /// /// For IPv4, there will be only one allocator: TYPE_V4 @@ -271,7 +267,6 @@ private: int hook_index_lease6_select_; ///< index for lease6_select hook public: - /// @brief Defines a single hint (an address + prefix-length). /// /// This is an entry that represents what the client had requested, @@ -314,7 +309,6 @@ public: /// information to the allocation engine methods is that adding /// new information doesn't modify the API of the allocation engine. struct ClientContext6 : public boost::noncopyable { - /// @name Parameters pertaining to DHCPv6 message //@{ @@ -379,7 +373,6 @@ public: /// @brief A collection of newly allocated leases. Lease6Collection new_leases_; - //@} /// @brief Parameters pertaining to individual IAs. @@ -791,7 +784,6 @@ public: } private: - /// @brief creates a lease and inserts it in LeaseMgr if necessary /// /// Creates a lease based on specified parameters and tries to insert it @@ -1116,7 +1108,6 @@ private: bool reclaimDeclined(const Lease6Ptr& lease); public: - /// @brief Context information for the DHCPv4 lease allocation. /// /// This structure holds a set of information provided by the DHCPv4 @@ -1374,7 +1365,6 @@ public: static ConstHostPtr findGlobalReservation(ClientContext4& ctx); private: - /// @brief Offers the lease. /// /// This method is called by the @c AllocEngine::allocateLease4 when @@ -1597,7 +1587,6 @@ private: bool conditionalExtendLifetime(Lease& lease) const; private: - /// @brief Number of consecutive DHCPv4 leases' reclamations after /// which there are still expired leases in the database. uint16_t incomplete_v4_reclamations_; @@ -1610,7 +1599,7 @@ private: /// @brief A pointer to the @c AllocEngine object. typedef boost::shared_ptr AllocEnginePtr; -}; // namespace isc::dhcp -}; // namespace isc +} // namespace dhcp +} // namespace isc #endif // ALLOC_ENGINE_H