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;
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
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;
// 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);
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
}
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.
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;
}
}
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;
(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());
}
(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());
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;
}
}
}
+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");
}
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()->
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);
}
}
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
}
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)) {
}
bool
-Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
+Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) {
// Accept all relayed messages.
if (pkt->isRelayed()) {
return (true);
/// 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.
///
/// 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.
///
/// 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.
///
/// 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;
///
/// @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.
///
/// @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.
/// @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.
///
/// @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
///