summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2024-02-21 22:48:41 +0100
committerFrancis Dupont <fdupont@isc.org>2024-02-23 10:54:45 +0100
commit8f254fbc065a70d646b6f1e3e7c70425c33773e3 (patch)
treeb87c14da01596acdba3fe9ae84fd72c64e34a2bc
parent[#2022] Checkpoint: added methods (diff)
downloadkea-8f254fbc065a70d646b6f1e3e7c70425c33773e3.tar.xz
kea-8f254fbc065a70d646b6f1e3e7c70425c33773e3.zip
[#2022] Added parking points
-rw-r--r--src/bin/dhcp4/dhcp4_messages.cc2
-rw-r--r--src/bin/dhcp4/dhcp4_messages.h1
-rw-r--r--src/bin/dhcp4/dhcp4_messages.mes7
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc118
-rw-r--r--src/bin/dhcp4/dhcp4_srv.h45
5 files changed, 135 insertions, 38 deletions
diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc
index 5e7f9bf8c1..b31f22c7d2 100644
--- a/src/bin/dhcp4/dhcp4_messages.cc
+++ b/src/bin/dhcp4/dhcp4_messages.cc
@@ -95,6 +95,7 @@ extern const isc::log::MessageID DHCP4_HOOK_PACKET_RCVD_SKIP = "DHCP4_HOOK_PACKE
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";
extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_DROP = "DHCP4_HOOK_SUBNET4_SELECT_DROP";
+extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_PARK = "DHCP4_HOOK_SUBNET4_SELECT_PARK";
extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_SKIP = "DHCP4_HOOK_SUBNET4_SELECT_SKIP";
extern const isc::log::MessageID DHCP4_INFORM_DIRECT_REPLY = "DHCP4_INFORM_DIRECT_REPLY";
extern const isc::log::MessageID DHCP4_INIT_FAIL = "DHCP4_INIT_FAIL";
@@ -279,6 +280,7 @@ const char* values[] = {
"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",
"DHCP4_HOOK_SUBNET4_SELECT_DROP", "%1: packet was dropped, because a callout set the next step to 'drop'",
+ "DHCP4_HOOK_SUBNET4_SELECT_PARK", "%1: packet was parked",
"DHCP4_HOOK_SUBNET4_SELECT_SKIP", "%1: no subnet was selected, because a callout set the next skip flag",
"DHCP4_INFORM_DIRECT_REPLY", "%1: DHCPACK in reply to the DHCPINFORM will be sent directly to %2 over %3",
"DHCP4_INIT_FAIL", "failed to initialize Kea server: %1",
diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h
index a5baf1e75f..8427698ed1 100644
--- a/src/bin/dhcp4/dhcp4_messages.h
+++ b/src/bin/dhcp4/dhcp4_messages.h
@@ -96,6 +96,7 @@ 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;
extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_DROP;
+extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_PARK;
extern const isc::log::MessageID DHCP4_HOOK_SUBNET4_SELECT_SKIP;
extern const isc::log::MessageID DHCP4_INFORM_DIRECT_REPLY;
extern const isc::log::MessageID DHCP4_INIT_FAIL;
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index 5818788a2f..a439bbdb32 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2023 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -523,6 +523,11 @@ point, the setting to that value instructs the server to drop the received
packet. The argument specifies the client and transaction identification
information.
+% DHCP4_HOOK_SUBNET4_SELECT_PARK %1: packet was parked
+This debug message is printed when a callout installed on the
+subnet4_select hook point set the park flag. The argument holds the
+client and transaction identification information.
+
% DHCP4_HOOK_SUBNET4_SELECT_SKIP %1: no subnet was selected, because a callout set the next skip flag
This debug message is printed when a callout installed on the
subnet4_select hook point sets the next step to SKIP value. For this particular hook
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 30c26bfb6b..5359f44cb4 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -715,11 +715,11 @@ Dhcpv4Srv::shutdown() {
isc::dhcp::Subnet4Ptr
Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query, bool& drop,
- bool sanity_only) const {
+ bool sanity_only, bool allow_answer_park) {
// DHCPv4-over-DHCPv6 is a special (and complex) case
if (query->isDhcp4o6()) {
- return (selectSubnet4o6(query, drop, sanity_only));
+ return (selectSubnet4o6(query, drop, sanity_only, allow_answer_park));
}
Subnet4Ptr subnet;
@@ -751,9 +751,34 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query, bool& drop,
cfgmgr.getCurrentCfg()->
getCfgSubnets4()->getAll());
+ // We proactively park the packet.
+ HooksManager::park("subnet4_select", query,
+ [this, query, allow_answer_park] () {
+ processLocalizedQuery4AndSendResponse(query,
+ allow_answer_park);
+ });
+
// Call user (and server-side) callouts
- HooksManager::callCallouts(Hooks.hook_index_subnet4_select_,
- *callout_handle);
+ try {
+ HooksManager::callCallouts(Hooks.hook_index_subnet4_select_,
+ *callout_handle);
+ } catch (...) {
+ // Make sure we don't orphan a parked packet.
+ HooksManager::drop("subnet4_select", query);
+ throw;
+ }
+
+ // Callouts parked the packet. Same as drop but callouts will resume
+ // processing or drop the packet later.
+ if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) {
+ LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
+ DHCP4_HOOK_SUBNET4_SELECT_PARK)
+ .arg(query->getLabel());
+ drop = true;
+ return (Subnet4Ptr());
+ } else {
+ HooksManager::drop("subnet4_select", query);
+ }
// Callouts decided to skip this step. This means that no subnet
// will be selected. Packet processing will continue, but it will
@@ -801,7 +826,7 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query, bool& drop,
isc::dhcp::Subnet4Ptr
Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query, bool& drop,
- bool sanity_only) const {
+ bool sanity_only, bool allow_answer_park) {
Subnet4Ptr subnet;
SubnetSelector selector;
@@ -861,6 +886,9 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query, bool& drop,
// handle and its arguments.
ScopedCalloutHandleState callout_handle_state(callout_handle);
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
// Set new arguments
callout_handle->setArgument("query4", query);
callout_handle->setArgument("subnet4", subnet);
@@ -868,9 +896,34 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query, bool& drop,
cfgmgr.getCurrentCfg()->
getCfgSubnets4()->getAll());
+ // We proactively park the packet.
+ HooksManager::park("subnet4_select", query,
+ [this, query, allow_answer_park] () {
+ processLocalizedQuery4AndSendResponse(query,
+ allow_answer_park);
+ });
+
// Call user (and server-side) callouts
- HooksManager::callCallouts(Hooks.hook_index_subnet4_select_,
- *callout_handle);
+ try {
+ HooksManager::callCallouts(Hooks.hook_index_subnet4_select_,
+ *callout_handle);
+ } catch (...) {
+ // Make sure we don't orphan a parked packet.
+ HooksManager::drop("subnet4_select", query);
+ throw;
+ }
+
+ // Callouts parked the packet. Same as drop but callouts will resume
+ // processing or drop the packet later.
+ if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) {
+ LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
+ DHCP4_HOOK_SUBNET4_SELECT_PARK)
+ .arg(query->getLabel());
+ drop = true;
+ return (Subnet4Ptr());
+ } else {
+ HooksManager::drop("subnet4_select", query);
+ }
// Callouts decided to skip this step. This means that no subnet
// will be selected. Packet processing will continue, but it will
@@ -1147,7 +1200,7 @@ Dhcpv4Srv::processPacketAndSendResponse(Pkt4Ptr query) {
}
Pkt4Ptr
-Dhcpv4Srv::processPacket(Pkt4Ptr query, bool allow_packet_park) {
+Dhcpv4Srv::processPacket(Pkt4Ptr query, bool allow_answer_park) {
query->addPktEvent("process_started");
// All packets belong to ALL.
@@ -1326,14 +1379,14 @@ Dhcpv4Srv::processPacket(Pkt4Ptr query, bool allow_packet_park) {
return (Pkt4Ptr());
}
- return (processDhcp4Query(query, allow_packet_park));
+ return (processDhcp4Query(query, allow_answer_park));
}
void
Dhcpv4Srv::processDhcp4QueryAndSendResponse(Pkt4Ptr query,
- bool allow_packet_park) {
+ bool allow_answer_park) {
try {
- Pkt4Ptr rsp = processDhcp4Query(query, allow_packet_park);
+ Pkt4Ptr rsp = processDhcp4Query(query, allow_answer_park);
if (!rsp) {
return;
}
@@ -1349,7 +1402,7 @@ Dhcpv4Srv::processDhcp4QueryAndSendResponse(Pkt4Ptr query,
}
Pkt4Ptr
-Dhcpv4Srv::processDhcp4Query(Pkt4Ptr query, bool allow_packet_park) {
+Dhcpv4Srv::processDhcp4Query(Pkt4Ptr query, bool allow_answer_park) {
// Create a client race avoidance RAII handler.
ClientHandler client_handler;
@@ -1361,7 +1414,7 @@ Dhcpv4Srv::processDhcp4Query(Pkt4Ptr query, bool allow_packet_park) {
(query->getType() == DHCPDECLINE))) {
ContinuationPtr cont =
makeContinuation(std::bind(&Dhcpv4Srv::processDhcp4QueryAndSendResponse,
- this, query, allow_packet_park));
+ this, query, allow_answer_park));
if (!client_handler.tryLock(query, cont)) {
return (Pkt4Ptr());
}
@@ -1378,7 +1431,7 @@ Dhcpv4Srv::processDhcp4Query(Pkt4Ptr query, bool allow_packet_park) {
(query->getType() == DHCPREQUEST) ||
(query->getType() == DHCPINFORM)) {
bool drop = false;
- ctx->subnet_ = selectSubnet(query, drop);
+ ctx->subnet_ = selectSubnet(query, drop, false, allow_answer_park);
// Stop here if selectSubnet decided to drop the packet
if (drop) {
return (Pkt4Ptr());
@@ -1402,14 +1455,15 @@ Dhcpv4Srv::processDhcp4Query(Pkt4Ptr query, bool allow_packet_park) {
static_cast<int64_t>(1));
}
- return (processLocalizedQuery4(ctx, allow_packet_park));
+ return (processLocalizedQuery4(ctx, allow_answer_park));
}
void
Dhcpv4Srv::processLocalizedQuery4AndSendResponse(Pkt4Ptr query,
- AllocEngine::ClientContext4Ptr& ctx) {
+ AllocEngine::ClientContext4Ptr& ctx,
+ bool allow_answer_park) {
try {
- Pkt4Ptr rsp = processLocalizedQuery4(ctx, true);
+ Pkt4Ptr rsp = processLocalizedQuery4(ctx, allow_answer_park);
if (!rsp) {
return;
}
@@ -1425,9 +1479,27 @@ Dhcpv4Srv::processLocalizedQuery4AndSendResponse(Pkt4Ptr query,
}
}
+void
+Dhcpv4Srv::processLocalizedQuery4AndSendResponse(Pkt4Ptr query,
+ bool allow_answer_park) {
+ // Initialize context.
+ AllocEngine::ClientContext4Ptr ctx(new AllocEngine::ClientContext4());
+ initContext0(query, ctx);
+
+ // Subnet is cached in the callout context associated to the query.
+ try {
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
+ callout_handle->getContext("subnet4", ctx->subnet_);
+ } catch (const Exception&) {
+ // No subnet, leave it to null...
+ }
+
+ processLocalizedQuery4AndSendResponse(query, ctx, allow_answer_park);
+}
+
Pkt4Ptr
Dhcpv4Srv::processLocalizedQuery4(AllocEngine::ClientContext4Ptr& ctx,
- bool allow_packet_park) {
+ bool allow_answer_park) {
if (!ctx) {
isc_throw(Unexpected, "null context");
}
@@ -1553,7 +1625,7 @@ Dhcpv4Srv::processLocalizedQuery4(AllocEngine::ClientContext4Ptr& ctx,
callout_handle->setArgument("deleted_leases4", deleted_leases);
}
- if (allow_packet_park) {
+ if (allow_answer_park) {
// Get the parking limit. Parsing should ensure the value is present.
uint32_t parked_packet_limit = 0;
data::ConstElementPtr ppl = CfgMgr::instance().getCurrentCfg()->
@@ -1636,7 +1708,7 @@ Dhcpv4Srv::processLocalizedQuery4(AllocEngine::ClientContext4Ptr& ctx,
HooksManager::callCallouts(hook_idx, *callout_handle);
} catch (...) {
// Make sure we don't orphan a parked packet.
- if (allow_packet_park) {
+ if (allow_answer_park) {
HooksManager::drop(hook_label, query);
}
@@ -1644,7 +1716,7 @@ Dhcpv4Srv::processLocalizedQuery4(AllocEngine::ClientContext4Ptr& ctx,
}
if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) &&
- allow_packet_park) {
+ allow_answer_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
@@ -4172,7 +4244,7 @@ Dhcpv4Srv::processInform(Pkt4Ptr& inform, AllocEngine::ClientContext4Ptr& contex
}
bool
-Dhcpv4Srv::accept(const Pkt4Ptr& query) const {
+Dhcpv4Srv::accept(const Pkt4Ptr& query) {
// Check that the message type is accepted by the server. We rely on the
// function called to log a message if needed.
if (!acceptMessageType(query)) {
@@ -4200,7 +4272,7 @@ Dhcpv4Srv::accept(const Pkt4Ptr& query) const {
}
bool
-Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
+Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) {
// Accept all relayed messages.
if (pkt->isRelayed()) {
return (true);
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index a38c152866..eb530280ec 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -369,9 +369,9 @@ public:
/// methods, generates appropriate answer.
///
/// @param query A pointer to the packet to be processed.
- /// @param allow_packet_park Indicates if parking a packet is allowed.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
/// @return A pointer to the response.
- Pkt4Ptr processPacket(Pkt4Ptr query, bool allow_packet_park = true);
+ Pkt4Ptr processPacket(Pkt4Ptr query, bool allow_answer_park = true);
/// @brief Process a single incoming DHCPv4 query.
///
@@ -379,9 +379,9 @@ public:
/// generates appropriate answer.
///
/// @param query A pointer to the packet to be processed.
- /// @param allow_packet_park Indicates if parking a packet is allowed.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
/// @return A pointer to the response.
- Pkt4Ptr processDhcp4Query(Pkt4Ptr query, bool allow_packet_park);
+ Pkt4Ptr processDhcp4Query(Pkt4Ptr query, bool allow_answer_park);
/// @brief Process a single incoming DHCPv4 query.
///
@@ -389,19 +389,32 @@ public:
/// generates appropriate answer, sends the answer to the client.
///
/// @param query A pointer to the packet to be processed.
- /// @param allow_packet_park Indicates if parking a packet is allowed.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
void processDhcp4QueryAndSendResponse(Pkt4Ptr query,
- bool allow_packet_park);
+ bool allow_answer_park);
/// @brief Process a localized incoming DHCPv4 query.
///
/// It calls per-type processXXX methods, generates appropriate answer.
///
/// @param ctx Pointer to The client context.
- /// @param allow_packet_park Indicates if parking a packet is allowed.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
/// @return A pointer to the response.
Pkt4Ptr processLocalizedQuery4(AllocEngine::ClientContext4Ptr& ctx,
- bool allow_packet_park);
+ bool allow_answer_park);
+
+ /// @brief Process a localized incoming DHCPv4 query.
+ ///
+ /// It calls per-type processXXX methods, generates appropriate answer,
+ /// sends the answer to the client.
+ ///
+ /// @param query A pointer to the unparked packet.
+ /// @param ctx Pointer to The client context.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
+ /// @return A pointer to the response.
+ void processLocalizedQuery4AndSendResponse(Pkt4Ptr query,
+ AllocEngine::ClientContext4Ptr& ctx,
+ bool allow_answer_park);
/// @brief Process a localized incoming DHCPv4 query.
///
@@ -409,10 +422,10 @@ public:
/// for packets parked in the subnet4_select callout.
///
/// @param query A pointer to the unparked packet.
- /// @param ctx Pointer to The client context.
+ /// @param allow_answer_park Indicates if parking a packet is allowed.
/// @return A pointer to the response.
void processLocalizedQuery4AndSendResponse(Pkt4Ptr query,
- AllocEngine::ClientContext4Ptr& ctx);
+ bool allow_answer_park);
/// @brief Instructs the server to shut down.
void shutdown() override;
@@ -531,7 +544,7 @@ protected:
///
/// @return true if the message should be further processed, or false if
/// the message should be discarded.
- bool accept(const Pkt4Ptr& query) const;
+ bool accept(const Pkt4Ptr& query);
/// @brief Check if a message sent by directly connected client should be
/// accepted or discarded.
@@ -560,7 +573,7 @@ protected:
///
/// @return true if message is accepted for further processing, false
/// otherwise.
- bool acceptDirectRequest(const Pkt4Ptr& query) const;
+ bool acceptDirectRequest(const Pkt4Ptr& query);
/// @brief Check if received message type is valid for the server to
/// process.
@@ -1079,10 +1092,12 @@ protected:
/// @param query client's message
/// @param drop if it is true the packet will be dropped
/// @param sanity_only if it is true the callout won't be called
+ /// @param allow_answer_park Indicates if parking a packet is allowed
/// @return selected subnet (or NULL if no suitable subnet was found)
isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query,
bool& drop,
- bool sanity_only = false) const;
+ bool sanity_only = false,
+ bool allow_answer_park = true);
/// @brief Selects a subnet for a given client's DHCP4o6 packet.
///
@@ -1094,10 +1109,12 @@ protected:
/// @param query client's message
/// @param drop if it is true the packet will be dropped
/// @param sanity_only if it is true the callout won't be called
+ /// @param allow_answer_park Indicates if parking a packet is allowed
/// @return selected subnet (or NULL if no suitable subnet was found)
isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr& query,
bool& drop,
- bool sanity_only = false) const;
+ bool sanity_only = false,
+ bool allow_answer_park = true);
/// @brief dummy wrapper around IfaceMgr::receive4
///