mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 15:35:17 +00:00
[master] Merge branch 'trac5457'
# Conflicts: # src/bin/dhcp4/tests/callout_library_1.cc # src/bin/dhcp4/tests/callout_library_2.cc
This commit is contained in:
@@ -24,7 +24,6 @@
|
||||
#include <dhcp4/dhcp4_log.h>
|
||||
#include <dhcp4/dhcp4_srv.h>
|
||||
#include <dhcpsrv/addr_utilities.h>
|
||||
#include <dhcpsrv/callout_handle_store.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/cfg_host_operations.h>
|
||||
#include <dhcpsrv/cfg_iface.h>
|
||||
@@ -79,36 +78,43 @@ using namespace isc::log;
|
||||
using namespace isc::stats;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Structure that holds registered hook indexes
|
||||
struct Dhcp4Hooks {
|
||||
int hook_index_buffer4_receive_; ///< index for "buffer4_receive" hook point
|
||||
int hook_index_pkt4_receive_; ///< index for "pkt4_receive" hook point
|
||||
int hook_index_subnet4_select_; ///< index for "subnet4_select" hook point
|
||||
int hook_index_lease4_release_; ///< index for "lease4_release" hook point
|
||||
int hook_index_pkt4_send_; ///< index for "pkt4_send" hook point
|
||||
int hook_index_buffer4_send_; ///< index for "buffer4_send" hook point
|
||||
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_buffer4_receive_; ///< index for "buffer4_receive" hook point
|
||||
int hook_index_pkt4_receive_; ///< index for "pkt4_receive" hook point
|
||||
int hook_index_subnet4_select_; ///< index for "subnet4_select" hook point
|
||||
int hook_index_leases4_committed_; ///< index for "leases4_committed" hook point
|
||||
int hook_index_lease4_release_; ///< index for "lease4_release" hook point
|
||||
int hook_index_pkt4_send_; ///< index for "pkt4_send" hook point
|
||||
int hook_index_buffer4_send_; ///< index for "buffer4_send" hook point
|
||||
int hook_index_lease4_decline_; ///< index for "lease4_decline" hook point
|
||||
int hook_index_host4_identifier_; ///< index for "host4_identifier" hook point
|
||||
|
||||
/// Constructor that registers hook points for DHCPv4 engine
|
||||
Dhcp4Hooks() {
|
||||
hook_index_buffer4_receive_ = HooksManager::registerHook("buffer4_receive");
|
||||
hook_index_pkt4_receive_ = HooksManager::registerHook("pkt4_receive");
|
||||
hook_index_subnet4_select_ = HooksManager::registerHook("subnet4_select");
|
||||
hook_index_pkt4_send_ = HooksManager::registerHook("pkt4_send");
|
||||
hook_index_lease4_release_ = HooksManager::registerHook("lease4_release");
|
||||
hook_index_buffer4_send_ = HooksManager::registerHook("buffer4_send");
|
||||
hook_index_lease4_decline_ = HooksManager::registerHook("lease4_decline");
|
||||
hook_index_host4_identifier_ = HooksManager::registerHook("host4_identifier");
|
||||
hook_index_buffer4_receive_ = HooksManager::registerHook("buffer4_receive");
|
||||
hook_index_pkt4_receive_ = HooksManager::registerHook("pkt4_receive");
|
||||
hook_index_subnet4_select_ = HooksManager::registerHook("subnet4_select");
|
||||
hook_index_leases4_committed_ = HooksManager::registerHook("leases4_committed");
|
||||
hook_index_pkt4_send_ = HooksManager::registerHook("pkt4_send");
|
||||
hook_index_lease4_release_ = HooksManager::registerHook("lease4_release");
|
||||
hook_index_buffer4_send_ = HooksManager::registerHook("buffer4_send");
|
||||
hook_index_lease4_decline_ = HooksManager::registerHook("lease4_decline");
|
||||
hook_index_host4_identifier_ = HooksManager::registerHook("host4_identifier");
|
||||
}
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
// Declare a Hooks object. As this is outside any function or method, it
|
||||
// will be instantiated (and the constructor run) when the module is loaded.
|
||||
// As a result, the hook indexes will be defined before any method in this
|
||||
// module is called.
|
||||
Dhcp4Hooks Hooks;
|
||||
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
@@ -834,72 +840,12 @@ Dhcpv4Srv::run_one() {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Now all fields and options are constructed into output wire buffer.
|
||||
// Option objects modification does not make sense anymore. Hooks
|
||||
// can only manipulate wire buffer at this stage.
|
||||
// Let's execute all callouts registered for buffer4_send
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Enable copying options from the packet within hook library.
|
||||
ScopedEnableOptionsCopy<Pkt4> resp4_options_copy(rsp);
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
|
||||
*callout_handle);
|
||||
|
||||
// Callouts decided to skip the next processing step. The next
|
||||
// processing step would to parse the packet, so skip at this
|
||||
// stage means drop.
|
||||
if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
|
||||
(callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
callout_handle->getArgument("response4", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->getLocalAddr().isV4Zero() ? "*" : rsp->getLocalAddr().toText())
|
||||
.arg(rsp->getLocalPort())
|
||||
.arg(rsp->getRemoteAddr())
|
||||
.arg(rsp->getRemotePort())
|
||||
.arg(rsp->getIface().empty() ? "to be determined from routing" :
|
||||
rsp->getIface());
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
|
||||
DHCP4_RESPONSE_DATA)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->toText());
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
processPacketBufferSend(callout_handle, rsp);
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp, bool allow_packet_park) {
|
||||
// Log reception of the packet. We need to increase it early, as any
|
||||
// failures in unpacking will cause the packet to be dropped. We
|
||||
// will increase type specific statistic further down the road.
|
||||
@@ -1047,6 +993,8 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
callout_handle->getArgument("query4", query);
|
||||
}
|
||||
|
||||
AllocEngine::ClientContext4Ptr ctx;
|
||||
|
||||
try {
|
||||
switch (query->getType()) {
|
||||
case DHCPDISCOVER:
|
||||
@@ -1057,15 +1005,15 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
// Note that REQUEST is used for many things in DHCPv4: for
|
||||
// requesting new leases, renewing existing ones and even
|
||||
// for rebinding.
|
||||
rsp = processRequest(query);
|
||||
rsp = processRequest(query, ctx);
|
||||
break;
|
||||
|
||||
case DHCPRELEASE:
|
||||
processRelease(query);
|
||||
processRelease(query, ctx);
|
||||
break;
|
||||
|
||||
case DHCPDECLINE:
|
||||
processDecline(query);
|
||||
processDecline(query, ctx);
|
||||
break;
|
||||
|
||||
case DHCPINFORM:
|
||||
@@ -1097,6 +1045,84 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
static_cast<int64_t>(1));
|
||||
}
|
||||
|
||||
bool packet_park = false;
|
||||
|
||||
if (ctx && HooksManager::calloutsPresent(Hooks.hook_index_leases4_committed_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Clear skip flag if it was set in previous callouts
|
||||
callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
|
||||
|
||||
ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
|
||||
|
||||
// Also pass the corresponding query packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
Lease4CollectionPtr new_leases(new Lease4Collection());
|
||||
if (ctx->new_lease_) {
|
||||
new_leases->push_back(ctx->new_lease_);
|
||||
}
|
||||
callout_handle->setArgument("leases4", new_leases);
|
||||
|
||||
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);
|
||||
|
||||
// Call all installed callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_leases4_committed_,
|
||||
*callout_handle);
|
||||
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_LEASES4_COMMITTED_DROP)
|
||||
.arg(query->getLabel());
|
||||
rsp.reset();
|
||||
|
||||
} else if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK)
|
||||
&& allow_packet_park) {
|
||||
packet_park = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PARKING SPOT after leases4_committed hook point.
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
if (packet_park) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_LEASES4_COMMITTED_PARK)
|
||||
.arg(query->getLabel());
|
||||
|
||||
// Park the packet. The function we bind here will be executed when the hook
|
||||
// library unparks the packet.
|
||||
HooksManager::park("leases4_committed", query,
|
||||
[this, callout_handle, query, rsp]() mutable {
|
||||
processPacketPktSend(callout_handle, query, rsp);
|
||||
processPacketBufferSend(callout_handle, rsp);
|
||||
});
|
||||
|
||||
// If we have parked the packet, let's 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 {
|
||||
processPacketPktSend(callout_handle, query, rsp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processPacketPktSend(hooks::CalloutHandlePtr& callout_handle,
|
||||
Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
@@ -1106,7 +1132,6 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
|
||||
// Execute all callouts registered for pkt4_send
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_pkt4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
@@ -1153,6 +1178,76 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processPacketBufferSend(CalloutHandlePtr& callout_handle,
|
||||
Pkt4Ptr& rsp) {
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Now all fields and options are constructed into output wire buffer.
|
||||
// Option objects modification does not make sense anymore. Hooks
|
||||
// can only manipulate wire buffer at this stage.
|
||||
// Let's execute all callouts registered for buffer4_send
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Enable copying options from the packet within hook library.
|
||||
ScopedEnableOptionsCopy<Pkt4> resp4_options_copy(rsp);
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
|
||||
*callout_handle);
|
||||
|
||||
// Callouts decided to skip the next processing step. The next
|
||||
// processing step would to parse the packet, so skip at this
|
||||
// stage means drop.
|
||||
if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
|
||||
(callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
callout_handle->getArgument("response4", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->getLocalAddr().isV4Zero() ? "*" : rsp->getLocalAddr().toText())
|
||||
.arg(rsp->getLocalPort())
|
||||
.arg(rsp->getRemoteAddr())
|
||||
.arg(rsp->getRemotePort())
|
||||
.arg(rsp->getIface().empty() ? "to be determined from routing" :
|
||||
rsp->getIface());
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
|
||||
DHCP4_RESPONSE_DATA)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->toText());
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
|
||||
if (!srvid) {
|
||||
@@ -2440,7 +2535,7 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
|
||||
}
|
||||
|
||||
Pkt4Ptr
|
||||
Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
|
||||
Dhcpv4Srv::processRequest(Pkt4Ptr& request, AllocEngine::ClientContext4Ptr& context) {
|
||||
/// @todo Uncomment this (see ticket #3116)
|
||||
/// sanityCheck(request, MANDATORY);
|
||||
|
||||
@@ -2492,11 +2587,15 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
|
||||
|
||||
appendServerID(ex);
|
||||
|
||||
// Return the pointer to the context, which will be required by the
|
||||
// leases4_comitted callouts.
|
||||
context = ex.getContext();
|
||||
|
||||
return (ex.getResponse());
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
|
||||
Dhcpv4Srv::processRelease(Pkt4Ptr& release, AllocEngine::ClientContext4Ptr& context) {
|
||||
/// @todo Uncomment this (see ticket #3116)
|
||||
/// sanityCheck(release, MANDATORY);
|
||||
|
||||
@@ -2575,6 +2674,10 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
|
||||
bool success = LeaseMgrFactory::instance().deleteLease(lease->addr_);
|
||||
|
||||
if (success) {
|
||||
|
||||
context.reset(new AllocEngine::ClientContext4());
|
||||
context->old_lease_ = lease;
|
||||
|
||||
// Release successful
|
||||
LOG_INFO(lease4_logger, DHCP4_RELEASE)
|
||||
.arg(release->getLabel())
|
||||
@@ -2604,7 +2707,7 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
|
||||
Dhcpv4Srv::processDecline(Pkt4Ptr& decline, AllocEngine::ClientContext4Ptr& context) {
|
||||
|
||||
// Server-id is mandatory in DHCPDECLINE (see table 5, RFC2131)
|
||||
/// @todo Uncomment this (see ticket #3116)
|
||||
@@ -2674,11 +2777,12 @@ Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
|
||||
|
||||
// Ok, all is good. The client is reporting its own address. Let's
|
||||
// process it.
|
||||
declineLease(lease, decline);
|
||||
declineLease(lease, decline, context);
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
|
||||
Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline,
|
||||
AllocEngine::ClientContext4Ptr& context) {
|
||||
|
||||
// Let's check if there are hooks installed for decline4 hook point.
|
||||
// If they are, let's pass the lease and client's packet. If the hook
|
||||
@@ -2742,6 +2846,9 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
|
||||
|
||||
LeaseMgrFactory::instance().updateLease4(lease);
|
||||
|
||||
context.reset(new AllocEngine::ClientContext4());
|
||||
context->new_lease_ = lease;
|
||||
|
||||
LOG_INFO(lease4_logger, DHCP4_DECLINE_LEASE).arg(lease->addr_.toText())
|
||||
.arg(decline->getLabel()).arg(lease->valid_lft_);
|
||||
}
|
||||
|
Reference in New Issue
Block a user