From: Francis Dupont Date: Thu, 14 May 2020 16:36:33 +0000 (+0200) Subject: [#1147] Checkpoint: todo lease commands X-Git-Tag: Kea-1.7.9~130 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee5c75639a855a7ebc22cb801926c34e70bec9ca;p=thirdparty%2Fkea.git [#1147] Checkpoint: todo lease commands --- diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 2b5008b59a..0af7d0320f 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -2940,7 +2940,14 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) { // updating DNS when the client sends DHCPREQUEST message. processClientName(ex); - assignLease(ex); + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + assignLease(ex); + } else { + assignLease(ex); + } if (!ex.getResponse()) { // The offer is empty so return it *now*! @@ -3006,7 +3013,14 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request, AllocEngine::ClientContext4Ptr& cont // Note that we treat REQUEST message uniformly, regardless if this is a // first request (requesting for new address), renewing existing address // or even rebinding. - assignLease(ex); + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + assignLease(ex); + } else { + assignLease(ex); + } Pkt4Ptr response = ex.getResponse(); if (!response) { diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 2bfeba1f9b..7188a23df6 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -3049,7 +3049,15 @@ Dhcpv6Srv::processSolicit(AllocEngine::ClientContext6& ctx) { ctx.fake_allocation_ = (response->getType() != DHCPV6_REPLY); processClientFqdn(solicit, response, ctx); - assignLeases(solicit, response, ctx); + + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + assignLeases(solicit, response, ctx); + } else { + assignLeases(solicit, response, ctx); + } conditionallySetReservedClientClasses(solicit, ctx); requiredClassify(solicit, ctx); @@ -3079,7 +3087,15 @@ Dhcpv6Srv::processRequest(AllocEngine::ClientContext6& ctx) { Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid())); processClientFqdn(request, reply, ctx); - assignLeases(request, reply, ctx); + + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + assignLeases(request, reply, ctx); + } else { + assignLeases(request, reply, ctx); + } conditionallySetReservedClientClasses(request, ctx); requiredClassify(request, ctx); @@ -3105,7 +3121,15 @@ Dhcpv6Srv::processRenew(AllocEngine::ClientContext6& ctx) { Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid())); processClientFqdn(renew, reply, ctx); - extendLeases(renew, reply, ctx); + + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + extendLeases(renew, reply, ctx); + } else { + extendLeases(renew, reply, ctx); + } conditionallySetReservedClientClasses(renew, ctx); requiredClassify(renew, ctx); @@ -3131,7 +3155,15 @@ Dhcpv6Srv::processRebind(AllocEngine::ClientContext6& ctx) { Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid())); processClientFqdn(rebind, reply, ctx); - extendLeases(rebind, reply, ctx); + + if (MultiThreadingMgr::instance().getMode()) { + // The lease reclamation cannot run at the same time. + ReadLockGuard share(alloc_engine_->getReadWriteMutex()); + + extendLeases(rebind, reply, ctx); + } else { + extendLeases(rebind, reply, ctx); + } conditionallySetReservedClientClasses(rebind, ctx); requiredClassify(rebind, ctx); diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 873aef3a5f..273bddacd9 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -961,6 +962,11 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } } + // We have the choice in the order checking the lease and + // the reservation. The default is to begin by the lease + // if the multi-threading is disabled. + bool check_reservation_first = MultiThreadingMgr::instance().getMode(); + uint64_t total_attempts = 0; // Need to check if the subnet belongs to a shared network. If so, @@ -1035,6 +1041,23 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { } } + // First check for reservation when it is the choice. + if (check_reservation_first && (hr_mode == Network::HR_ALL) && + HostMgr::instance().get6(subnet->getID(), candidate)) { + // Don't allocate. + continue; + } + + // Check if the resource is busy i.e. can be being allocated + // by another thread to another client. + ResourceHandler resource_handler; + if (MultiThreadingMgr::instance().getMode() && + !MultiThreadingMgr::instance().isInCriticalSection() && + !resource_handler.tryLock(ctx.currentIA().type_, candidate)) { + // Don't allocate. + continue; + } + // Look for an existing lease for the candidate. Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, candidate); @@ -1043,7 +1066,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { /// 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. - if (hr_mode == Network::HR_ALL && + if (!check_reservation_first && (hr_mode == Network::HR_ALL) && HostMgr::instance().get6(subnet->getID(), candidate)) { // Don't allocate. @@ -1075,7 +1098,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // allocation attempts. } else if (existing->expired()) { // Make sure it's not reserved. - if (hr_mode == Network::HR_ALL && + if (!check_reservation_first && (hr_mode == Network::HR_ALL) && HostMgr::instance().get6(subnet->getID(), candidate)) { // Don't allocate. continue; @@ -2276,8 +2299,17 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo try { // Reclaim the lease. - reclaimExpiredLease(lease, remove_lease, callout_handle); - ++leases_processed; + if (MultiThreadingMgr::instance().getMode() && + !MultiThreadingMgr::instance().isInCriticalSection()) { + // The reclamation is exclusive of packet processing. + WriteLockGuard exclusive(rw_mutex_); + + reclaimExpiredLease(lease, remove_lease, callout_handle); + ++leases_processed; + } else { + reclaimExpiredLease(lease, remove_lease, callout_handle); + ++leases_processed; + } } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED) @@ -2414,8 +2446,17 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo try { // Reclaim the lease. - reclaimExpiredLease(lease, remove_lease, callout_handle); - ++leases_processed; + if (MultiThreadingMgr::instance().getMode() && + !MultiThreadingMgr::instance().isInCriticalSection()) { + // The reclamation is exclusive of packet processing. + WriteLockGuard exclusive(rw_mutex_); + + reclaimExpiredLease(lease, remove_lease, callout_handle); + ++leases_processed; + } else { + reclaimExpiredLease(lease, remove_lease, callout_handle); + ++leases_processed; + } } catch (const std::exception& ex) { LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED) @@ -3976,6 +4017,11 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { ctx.subnet_ = subnet = network->getPreferredSubnet(ctx.subnet_); } + // We have the choice in the order checking the lease and + // the reservation. The default is to begin by the lease + // if the multi-threading is disabled. + bool check_reservation_first = MultiThreadingMgr::instance().getMode(); + Subnet4Ptr original_subnet = subnet; uint64_t total_attempts = 0; @@ -4005,17 +4051,34 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { ctx.query_->getClasses(), client_id, ctx.requested_address_); + // First check for reservation when it is the choice. + if (check_reservation_first && addressReserved(candidate, ctx)) { + // Don't allocate. + continue; + } + + // Check if the resource is busy i.e. can be being allocated + // by another thread to another client. + ResourceHandler4 resource_handler; + if (MultiThreadingMgr::instance().getMode() && + !MultiThreadingMgr::instance().isInCriticalSection() && + !resource_handler.tryLock4(candidate)) { + // Don't allocate. + continue; + } + // Check for an existing lease for the candidate address. Lease4Ptr exist_lease = LeaseMgrFactory::instance().getLease4(candidate); if (!exist_lease) { // No existing lease, is it reserved? - if (!addressReserved(candidate, ctx)) { + if (check_reservation_first || !addressReserved(candidate, ctx)) { // Not reserved use it. new_lease = createLease4(ctx, candidate, callout_status); } } else { // An lease exists, is expired, and not reserved use it. - if (exist_lease->expired() && (!addressReserved(candidate, ctx))) { + if (exist_lease->expired() && + (check_reservation_first || !addressReserved(candidate, ctx))) { ctx.old_lease_ = Lease4Ptr(new Lease4(*exist_lease)); new_lease = reuseExpiredLease4(exist_lease, ctx, callout_status); } diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index 3fdcbe46bd..54816a5a94 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1851,6 +1852,20 @@ private: /// @brief Number of consecutive DHCPv6 leases' reclamations after /// which there are still expired leases in the database. uint16_t incomplete_v6_reclamations_; + +public: + + /// @brief Get the read-write mutex. + /// + /// This read-write mutex is used to make reclamation exclusive + /// of multi-threaded packet processing. + /// @return A reference to the read-write mutex. + isc::util::ReadWriteMutex& getReadWriteMutex() { + return (rw_mutex_); + } + + /// @brief The read-write mutex. + isc::util::ReadWriteMutex rw_mutex_; }; /// @brief A pointer to the @c AllocEngine object.