]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1147] Checkpoint: todo lease commands
authorFrancis Dupont <fdupont@isc.org>
Thu, 14 May 2020 16:36:33 +0000 (18:36 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 26 May 2020 09:51:57 +0000 (11:51 +0200)
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/alloc_engine.h

index 2b5008b59abd0549df8eacc5edd47472bb9d42a2..0af7d0320fbf04cef8f1da2e1f71e487437ee3cd 100644 (file)
@@ -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) {
index 2bfeba1f9b77f790e0c58e2b20cb8b5645978aee..7188a23df652b1ba000a7f4b8a79a0ecb1f1ec18 100644 (file)
@@ -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);
index 873aef3a5fa3a5c6c5db808886c4721ad94a0d32..273bddacd98eefcb29df99c36195f4d13a31167d 100644 (file)
@@ -20,6 +20,7 @@
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/ncr_generator.h>
 #include <dhcpsrv/network.h>
+#include <dhcpsrv/resource_handler.h>
 #include <dhcpsrv/shared_network.h>
 #include <hooks/callout_handle.h>
 #include <hooks/hooks_manager.h>
@@ -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);
                 }
index 3fdcbe46bd07814f748d8a4d8d287356723f78f2..54816a5a94b352e3f8ecfda81d10b9440c9e3bd4 100644 (file)
@@ -23,6 +23,7 @@
 #include <dhcpsrv/srv_config.h>
 #include <hooks/callout_handle.h>
 #include <util/multi_threading_mgr.h>
+#include <util/readwrite_mutex.h>
 
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
@@ -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.