]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3038] init of new hook point lease4_offer
authorPiotrek Zadroga <piotrek@isc.org>
Tue, 5 Sep 2023 18:51:57 +0000 (20:51 +0200)
committerPiotrek Zadroga <piotrek@isc.org>
Mon, 18 Sep 2023 17:19:45 +0000 (19:19 +0200)
src/bin/dhcp4/dhcp4_messages.cc
src/bin/dhcp4/dhcp4_messages.h
src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.cc

index 0f3369089187b0144584968214e94f4fa115e060..0d37e69aaf4340cc5dc82fc14dcec4355049cac6 100644 (file)
@@ -82,10 +82,13 @@ extern const isc::log::MessageID DHCP4_HOOK_BUFFER_RCVD_SKIP = "DHCP4_HOOK_BUFFE
 extern const isc::log::MessageID DHCP4_HOOK_BUFFER_SEND_SKIP = "DHCP4_HOOK_BUFFER_SEND_SKIP";
 extern const isc::log::MessageID DHCP4_HOOK_DDNS_UPDATE = "DHCP4_HOOK_DDNS_UPDATE";
 extern const isc::log::MessageID DHCP4_HOOK_DECLINE_SKIP = "DHCP4_HOOK_DECLINE_SKIP";
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_DROP = "DHCP4_HOOK_LEASE4_OFFER_DROP";
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_PARK = "DHCP4_HOOK_LEASE4_OFFER_PARK";
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL = "DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL";
 extern const isc::log::MessageID DHCP4_HOOK_LEASE4_RELEASE_SKIP = "DHCP4_HOOK_LEASE4_RELEASE_SKIP";
 extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_DROP = "DHCP4_HOOK_LEASES4_COMMITTED_DROP";
 extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_PARK = "DHCP4_HOOK_LEASES4_COMMITTED_PARK";
-extern const isc::log::MessageID DHCP4_HOOK_LEASES4_PARKING_LOT_FULL = "DHCP4_HOOK_LEASES4_PARKING_LOT_FULL";
+extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL = "DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL";
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_RCVD_SKIP = "DHCP4_HOOK_PACKET_RCVD_SKIP";
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_SEND_DROP = "DHCP4_HOOK_PACKET_SEND_DROP";
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_SEND_SKIP = "DHCP4_HOOK_PACKET_SEND_SKIP";
@@ -255,10 +258,13 @@ const char* values[] = {
     "DHCP4_HOOK_BUFFER_SEND_SKIP", "%1: prepared response is dropped because a callout set the next step to SKIP.",
     "DHCP4_HOOK_DDNS_UPDATE", "A hook has updated the DDNS parameters: hostname %1=>%2, forward update %3=>%4, reverse update %5=>%6",
     "DHCP4_HOOK_DECLINE_SKIP", "Decline4 hook callouts set status to DROP, ignoring packet.",
+    "DHCP4_HOOK_LEASE4_OFFER_DROP", "%1: packet is dropped, because a callout set the next step to DROP",
+    "DHCP4_HOOK_LEASE4_OFFER_PARK", "%1: packet is parked, because a callout set the next step to PARK",
+    "DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL", "The parked-packet-limit %1, has been reached, dropping query: %2",
     "DHCP4_HOOK_LEASE4_RELEASE_SKIP", "%1: lease was not released because a callout set the next step to SKIP",
     "DHCP4_HOOK_LEASES4_COMMITTED_DROP", "%1: packet is dropped, because a callout set the next step to DROP",
     "DHCP4_HOOK_LEASES4_COMMITTED_PARK", "%1: packet is parked, because a callout set the next step to PARK",
-    "DHCP4_HOOK_LEASES4_PARKING_LOT_FULL", "The parked-packet-limit %1, has been reached, dropping query: %2",
+    "DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL", "The parked-packet-limit %1, has been reached, dropping query: %2",
     "DHCP4_HOOK_PACKET_RCVD_SKIP", "%1: packet is dropped, because a callout set the next step to SKIP",
     "DHCP4_HOOK_PACKET_SEND_DROP", "%1: prepared DHCPv4 response was not sent because a callout set the next ste to DROP",
     "DHCP4_HOOK_PACKET_SEND_SKIP", "%1: prepared response is not sent, because a callout set the next stp to SKIP",
index 5c3ec57a6d0ecc5ad35c0bf3efbbdca899ff81e0..785fccb21c2efdf6447e2ff08e28ffe10b680142 100644 (file)
@@ -83,10 +83,13 @@ extern const isc::log::MessageID DHCP4_HOOK_BUFFER_RCVD_SKIP;
 extern const isc::log::MessageID DHCP4_HOOK_BUFFER_SEND_SKIP;
 extern const isc::log::MessageID DHCP4_HOOK_DDNS_UPDATE;
 extern const isc::log::MessageID DHCP4_HOOK_DECLINE_SKIP;
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_DROP;
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_PARK;
+extern const isc::log::MessageID DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL;
 extern const isc::log::MessageID DHCP4_HOOK_LEASE4_RELEASE_SKIP;
 extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_DROP;
 extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_PARK;
-extern const isc::log::MessageID DHCP4_HOOK_LEASES4_PARKING_LOT_FULL;
+extern const isc::log::MessageID DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL;
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_RCVD_SKIP;
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_SEND_DROP;
 extern const isc::log::MessageID DHCP4_HOOK_PACKET_SEND_SKIP;
index 71d12e10a44fefb74eeb736d649542b5c85359e3..f432c06c8086e7f11c5e429e7f3b7eb67bdb972f 100644 (file)
@@ -444,6 +444,22 @@ for decline4 hook point and one of the callouts set next step status to DROP.
 The server will now abort processing of the packet as if it was never
 received. The lease will continue to be assigned to this client.
 
+% DHCP4_HOOK_LEASE4_OFFER_DROP %1: packet is dropped, because a callout set the next step to DROP
+This debug message is printed when a callout installed on the lease4_offer
+hook point sets the next step to DROP.
+
+% DHCP4_HOOK_LEASE4_OFFER_PARK %1: packet is parked, because a callout set the next step to PARK
+This debug message is printed when a callout installed on the lease4_offer
+hook point sets the next step to PARK.
+
+% DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL The parked-packet-limit %1, has been reached, dropping query: %2
+This debug message occurs when the parking lot used to hold client queries
+while hook library work for them completes has reached or exceeded the
+limit set by the parked-packet-limit global parameter. This can occur when
+kea-dhcp4 is using hook libraries (e.g. ping-check) that implement the
+"lease4-offer" callout and client queries are arriving faster than
+those callouts can fulfill them.
+
 % DHCP4_HOOK_LEASE4_RELEASE_SKIP %1: lease was not released because a callout set the next step to SKIP
 This debug message is printed when a callout installed on lease4_release
 hook point set the next step status to SKIP. For this particular hook point, the
@@ -457,7 +473,7 @@ hook point sets the next step to DROP.
 This debug message is printed when a callout installed on the leases4_committed
 hook point sets the next step to PARK.
 
-% DHCP4_HOOK_LEASES4_PARKING_LOT_FULL The parked-packet-limit %1, has been reached, dropping query: %2
+% DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL The parked-packet-limit %1, has been reached, dropping query: %2
 This debug message occurs when the parking lot used to hold client queries
 while hook library work for them completes has reached or exceeded the
 limit set by the parked-packet-limit global parameter. This can occur when
index 775985df87344f3777f75f3d54b054b57fdb38f7..4d02661bbc9b3e465f64164b9978e3bcd97cc4ae 100644 (file)
@@ -96,6 +96,7 @@ struct Dhcp4Hooks {
     int hook_index_lease4_decline_;    ///< index for "lease4_decline" hook point
     int hook_index_host4_identifier_;  ///< index for "host4_identifier" hook point
     int hook_index_ddns4_update_;      ///< index for "ddns4_update" hook point
+    int hook_index_lease4_offer_;      ///< index for "lease4_offer" hook point
 
     /// Constructor that registers hook points for DHCPv4 engine
     Dhcp4Hooks() {
@@ -109,6 +110,7 @@ struct Dhcp4Hooks {
         hook_index_lease4_decline_    = HooksManager::registerHook("lease4_decline");
         hook_index_host4_identifier_  = HooksManager::registerHook("host4_identifier");
         hook_index_ddns4_update_      = HooksManager::registerHook("ddns4_update");
+        hook_index_lease4_offer_      = HooksManager::registerHook("lease4_offer");
     }
 };
 
@@ -1408,129 +1410,143 @@ Dhcpv4Srv::processDhcp4Query(Pkt4Ptr& query, Pkt4Ptr& rsp,
     }
 
     CalloutHandlePtr callout_handle = getCalloutHandle(query);
-    if (ctx && HooksManager::calloutsPresent(Hooks.hook_index_leases4_committed_)) {
-        // The ScopedCalloutHandleState class which guarantees that the task
-        // is added to the thread pool after the response is reset (if needed)
-        // and CalloutHandle state is reset. In ST it does nothing.
-        // A smart pointer is used to store the ScopedCalloutHandleState so that
-        // a copy of the pointer is created by the lambda and only on the
-        // destruction of the last reference the task is added.
-        // In MT there are 2 cases:
-        // 1. packet is unparked before current thread smart pointer to
-        //    ScopedCalloutHandleState is destroyed:
-        //  - the lambda uses the smart pointer to set the callout which adds the
-        //    task, but the task is added after ScopedCalloutHandleState is
-        //    destroyed, on the destruction of the last reference which is held
-        //    by the current thread.
-        // 2. packet is unparked after the current thread smart pointer to
-        //    ScopedCalloutHandleState is destroyed:
-        //  - the current thread reference to ScopedCalloutHandleState is
-        //    destroyed, but the reference in the lambda keeps it alive until
-        //    the lambda is called and the last reference is released, at which
-        //    time the task is actually added.
-        // 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
-        // handle and its arguments.
-        std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
-                std::make_shared<ScopedCalloutHandleState>(callout_handle);
+    if (ctx) {
+        int hook_idx = Hooks.hook_index_leases4_committed_;
+        std::string hook_label = "leases4_committed";
+        MessageID pkt_park_msg = DHCP4_HOOK_LEASES4_COMMITTED_PARK;
+        MessageID pkt_drop_msg = DHCP4_HOOK_LEASES4_COMMITTED_DROP;
+        MessageID parking_lot_full_msg = DHCP4_HOOK_LEASES4_COMMITTED_PARKING_LOT_FULL;
+        if (ctx->fake_allocation_) {
+            hook_idx = Hooks.hook_index_lease4_offer_;
+            hook_label = "lease4_offer";
+            pkt_park_msg = DHCP4_HOOK_LEASE4_OFFER_PARK;
+            pkt_drop_msg = DHCP4_HOOK_LEASE4_OFFER_DROP;
+            parking_lot_full_msg = DHCP4_HOOK_LEASE4_OFFER_PARKING_LOT_FULL;
+        }
 
-        ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+        if (HooksManager::calloutsPresent(hook_idx)) {
+            // The ScopedCalloutHandleState class which guarantees that the task
+            // is added to the thread pool after the response is reset (if needed)
+            // and CalloutHandle state is reset. In ST it does nothing.
+            // A smart pointer is used to store the ScopedCalloutHandleState so that
+            // a copy of the pointer is created by the lambda and only on the
+            // destruction of the last reference the task is added.
+            // In MT there are 2 cases:
+            // 1. packet is unparked before current thread smart pointer to
+            //    ScopedCalloutHandleState is destroyed:
+            //  - the lambda uses the smart pointer to set the callout which adds the
+            //    task, but the task is added after ScopedCalloutHandleState is
+            //    destroyed, on the destruction of the last reference which is held
+            //    by the current thread.
+            // 2. packet is unparked after the current thread smart pointer to
+            //    ScopedCalloutHandleState is destroyed:
+            //  - the current thread reference to ScopedCalloutHandleState is
+            //    destroyed, but the reference in the lambda keeps it alive until
+            //    the lambda is called and the last reference is released, at which
+            //    time the task is actually added.
+            // 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
+            // handle and its arguments.
+            std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
+                std::make_shared<ScopedCalloutHandleState>(callout_handle);
 
-        // Also pass the corresponding query packet as argument
-        callout_handle->setArgument("query4", query);
+            ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
 
-        Lease4CollectionPtr new_leases(new Lease4Collection());
-        // Filter out the new lease if it was reused so not committed.
-        if (ctx->new_lease_ && (ctx->new_lease_->reuseable_valid_lft_ == 0)) {
-            new_leases->push_back(ctx->new_lease_);
-        }
-        callout_handle->setArgument("leases4", new_leases);
+            // Also pass the corresponding query packet as argument
+            callout_handle->setArgument("query4", query);
 
-        Lease4CollectionPtr deleted_leases(new Lease4Collection());
-        if (ctx->old_lease_) {
-            if ((!ctx->new_lease_) || (ctx->new_lease_->addr_ != ctx->old_lease_->addr_)) {
-                deleted_leases->push_back(ctx->old_lease_);
-            }
-        }
-        callout_handle->setArgument("deleted_leases4", deleted_leases);
-
-        if (allow_packet_park) {
-            // Get the parking limit. Parsing should ensure the value is present.
-            uint32_t parked_packet_limit = 0;
-            data::ConstElementPtr ppl = CfgMgr::instance().getCurrentCfg()->
-                getConfiguredGlobal(CfgGlobals::PARKED_PACKET_LIMIT);
-            if (ppl) {
-                parked_packet_limit = ppl->intValue();
+            Lease4CollectionPtr new_leases(new Lease4Collection());
+            // Filter out the new lease if it was reused so not committed.
+            if (ctx->new_lease_ && (ctx->new_lease_->reuseable_valid_lft_ == 0)) {
+                new_leases->push_back(ctx->new_lease_);
             }
+            callout_handle->setArgument("leases4", new_leases);
 
-            if (parked_packet_limit) {
-                const auto& parking_lot = ServerHooks::getServerHooks().
-                    getParkingLotPtr("leases4_committed");
-
-                if (parking_lot && (parking_lot->size() >= parked_packet_limit)) {
-                    // We can't park it so we're going to throw it on the floor.
-                    LOG_DEBUG(packet4_logger, DBGLVL_PKT_HANDLING,
-                              DHCP4_HOOK_LEASES4_PARKING_LOT_FULL)
-                              .arg(parked_packet_limit)
-                              .arg(query->getLabel());
-                    isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
-                                                              static_cast<int64_t>(1));
-                    rsp.reset();
-                    return;
+            Lease4CollectionPtr deleted_leases(new Lease4Collection());
+            if (ctx->old_lease_) {
+                if ((!ctx->new_lease_) || (ctx->new_lease_->addr_ != ctx->old_lease_->addr_)) {
+                    deleted_leases->push_back(ctx->old_lease_);
                 }
             }
+            callout_handle->setArgument("deleted_leases4", deleted_leases);
 
-            // We proactively park the packet. We'll unpark it without invoking
-            // the callback (i.e. drop) unless the callout status is set to
-            // NEXT_STEP_PARK.  Otherwise the callback we bind here will be
-            // executed when the hook library unparks the packet.
-            HooksManager::park("leases4_committed", query,
-            [this, callout_handle, query, rsp, callout_handle_state]() mutable {
-                if (MultiThreadingMgr::instance().getMode()) {
-                    typedef function<void()> CallBack;
-                    boost::shared_ptr<CallBack> call_back =
-                        boost::make_shared<CallBack>(std::bind(&Dhcpv4Srv::sendResponseNoThrow,
-                                                               this, callout_handle, query, rsp));
-                    callout_handle_state->on_completion_ = [call_back]() {
-                        MultiThreadingMgr::instance().getThreadPool().add(call_back);
-                    };
-                } else {
-                    processPacketPktSend(callout_handle, query, rsp);
-                    processPacketBufferSend(callout_handle, rsp);
+            if (allow_packet_park) {
+                // Get the parking limit. Parsing should ensure the value is present.
+                uint32_t parked_packet_limit = 0;
+                data::ConstElementPtr ppl = CfgMgr::instance().getCurrentCfg()->
+                    getConfiguredGlobal(CfgGlobals::PARKED_PACKET_LIMIT);
+                if (ppl) {
+                    parked_packet_limit = ppl->intValue();
                 }
-            });
-        }
 
-        try {
-            // Call all installed callouts
-            HooksManager::callCallouts(Hooks.hook_index_leases4_committed_,
-                                       *callout_handle);
-        } catch (...) {
-            // Make sure we don't orphan a parked packet.
-            if (allow_packet_park) {
-                HooksManager::drop("leases4_committed", query);
+                if (parked_packet_limit) {
+                    const auto& parking_lot =
+                        ServerHooks::getServerHooks().getParkingLotPtr(hook_label);
+
+                    if (parking_lot && (parking_lot->size() >= parked_packet_limit)) {
+                        // We can't park it so we're going to throw it on the floor.
+                        LOG_DEBUG(packet4_logger, DBGLVL_PKT_HANDLING, parking_lot_full_msg)
+                            .arg(parked_packet_limit)
+                            .arg(query->getLabel());
+                        isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+                                                                  static_cast<int64_t>(1));
+                        rsp.reset();
+                        return;
+                    }
+                }
+
+                // We proactively park the packet. We'll unpark it without invoking
+                // the callback (i.e. drop) unless the callout status is set to
+                // NEXT_STEP_PARK.  Otherwise the callback we bind here will be
+                // executed when the hook library unparks the packet.
+                HooksManager::park(
+                    hook_label, query,
+                    [this, callout_handle, query, rsp, callout_handle_state]() mutable {
+                        if (MultiThreadingMgr::instance().getMode()) {
+                            typedef function<void()> CallBack;
+                            boost::shared_ptr<CallBack> call_back = boost::make_shared<CallBack>(
+                                std::bind(&Dhcpv4Srv::sendResponseNoThrow, this, callout_handle,
+                                          query, rsp));
+                            callout_handle_state->on_completion_ = [call_back]() {
+                                MultiThreadingMgr::instance().getThreadPool().add(call_back);
+                            };
+                        } else {
+                            processPacketPktSend(callout_handle, query, rsp);
+                            processPacketBufferSend(callout_handle, rsp);
+                        }
+                    });
             }
 
-            throw;
-        }
+            try {
+                // Call all installed callouts
+                HooksManager::callCallouts(hook_idx, *callout_handle);
+            } catch (...) {
+                // Make sure we don't orphan a parked packet.
+                if (allow_packet_park) {
+                    HooksManager::drop(hook_label, query);
+                }
 
-        if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK)
-            && allow_packet_park) {
-            LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS, DHCP4_HOOK_LEASES4_COMMITTED_PARK)
-                      .arg(query->getLabel());
-            // Since the hook library(ies) are going to do the unparking, then
-            // reset the pointer to the response to indicate to the caller that
-            // it should return, as the packet processing will continue via
-            // the callback.
-            rsp.reset();
-        } else {
-            // Drop the park job on the packet, it isn't needed.
-            HooksManager::drop("leases4_committed", query);
-            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
-                LOG_DEBUG(hooks_logger, DBGLVL_PKT_HANDLING, DHCP4_HOOK_LEASES4_COMMITTED_DROP)
-                          .arg(query->getLabel());
+                throw;
+            }
+
+            if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) &&
+                allow_packet_park) {
+                LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS, pkt_park_msg)
+                    .arg(query->getLabel());
+                // Since the hook library(ies) are going to do the unparking, then
+                // reset the pointer to the response to indicate to the caller that
+                // it should return, as the packet processing will continue via
+                // the callback.
                 rsp.reset();
+            } else {
+                // Drop the park job on the packet, it isn't needed.
+                HooksManager::drop(hook_label, query);
+                if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
+                    LOG_DEBUG(hooks_logger, DBGLVL_PKT_HANDLING, pkt_drop_msg)
+                        .arg(query->getLabel());
+                    rsp.reset();
+                }
             }
         }
     }