2
0
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:
Marcin Siodelski
2018-03-06 19:19:19 +01:00
35 changed files with 1979 additions and 155 deletions

View File

@@ -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_);
}