2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-22 01:49:48 +00:00

[#3683] Checkpoint (2)

This commit is contained in:
Francis Dupont 2025-02-23 02:03:18 +01:00
parent 97338aa578
commit 6fa6476543
6 changed files with 128 additions and 23 deletions

View File

@ -345,6 +345,23 @@ called before "subnet6_select".
- <b>Next step status</b>: Not applicable, its value will be ignored.
@subsection dhcpv6HookRegister6 register6
- @b Arguments:
- name: @b query6, type: isc::dhcp::Pkt6Ptr, direction: <b>in</b>
- name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: <b>in</b>
- name: @b address6, type: isc::asiolink::IOAddress, direction: <b>in</b>
- name: @b old_lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in</b>
- name: @b new_lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out<b>
- @b Description: this callout is executed when an addr-reg-inform was
received and successfully processed. When the new_lease is cleared
this instructs the server to make stateless registration i.e. address
registration is used only for side effects and does not maintain state.
- <b>Next step status</b>: If any callout sets the status to SKIP or DROP,
the server will cancel current packet processing.
@subsection dhcpv6Leases6Committed leases6_committed
- @b Arguments:

View File

@ -13,6 +13,8 @@ extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_RESULT = "DHCP6_ADD
extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_NO_TEST = "DHCP6_ADDITIONAL_CLASS_NO_TEST";
extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_UNDEFINED = "DHCP6_ADDITIONAL_CLASS_UNDEFINED";
extern const isc::log::MessageID DHCP6_ADD_GLOBAL_STATUS_CODE = "DHCP6_ADD_GLOBAL_STATUS_CODE";
extern const isc::log::MessageID DHCP6_ADD_REG_INFORM_CLIENT_CHANGE = "DHCP6_ADD_REG_INFORM_CLIENT_CHANGE";
extern const isc::log::MessageID DHCP6_ADD_REG_INFORM_FAIL = "DHCP6_ADD_REG_INFORM_FAIL";
extern const isc::log::MessageID DHCP6_ADD_STATUS_CODE_FOR_IA = "DHCP6_ADD_STATUS_CODE_FOR_IA";
extern const isc::log::MessageID DHCP6_ALREADY_RUNNING = "DHCP6_ALREADY_RUNNING";
extern const isc::log::MessageID DHCP6_BUFFER_RECEIVED = "DHCP6_BUFFER_RECEIVED";
@ -77,6 +79,7 @@ extern const isc::log::MessageID DHCP6_HOOK_LEASES6_PARKING_LOT_FULL = "DHCP6_HO
extern const isc::log::MessageID DHCP6_HOOK_PACKET_RCVD_SKIP = "DHCP6_HOOK_PACKET_RCVD_SKIP";
extern const isc::log::MessageID DHCP6_HOOK_PACKET_SEND_DROP = "DHCP6_HOOK_PACKET_SEND_DROP";
extern const isc::log::MessageID DHCP6_HOOK_PACKET_SEND_SKIP = "DHCP6_HOOK_PACKET_SEND_SKIP";
extern const isc::log::MessageID DHCP6_HOOK_REGISTER6_SKIP = "DHCP6_HOOK_REGISTER6_SKIP";
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_DROP = "DHCP6_HOOK_SUBNET6_SELECT_DROP";
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_PARK = "DHCP6_HOOK_SUBNET6_SELECT_PARK";
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_SKIP = "DHCP6_HOOK_SUBNET6_SELECT_SKIP";
@ -180,6 +183,8 @@ const char* values[] = {
"DHCP6_ADDITIONAL_CLASS_NO_TEST", "additional class %1 has no test expression, adding it to client's classes unconditionally",
"DHCP6_ADDITIONAL_CLASS_UNDEFINED", "additional class %1 has no definition",
"DHCP6_ADD_GLOBAL_STATUS_CODE", "%1: adding Status Code to DHCPv6 packet: %2",
"DHCP6_ADD_REG_INFORM_CLIENT_CHANGE", "received an add-reg-inform for %1 from client '%2' but the address was registered by another client '%3'",
"DHCP6_ADD_REG_INFORM_FAIL", "error on add-reg-inform from client %1: %2",
"DHCP6_ADD_STATUS_CODE_FOR_IA", "%1: adding Status Code to IA with iaid=%2: %3",
"DHCP6_ALREADY_RUNNING", "%1 already running? %2",
"DHCP6_BUFFER_RECEIVED", "received buffer from %1:%2 to %3:%4 over interface %5",
@ -244,6 +249,7 @@ const char* values[] = {
"DHCP6_HOOK_PACKET_RCVD_SKIP", "%1: packet is dropped, because a callout set the next step to SKIP",
"DHCP6_HOOK_PACKET_SEND_DROP", "%1: prepared DHCPv6 response was not sent because a callout set the next ste to DROP",
"DHCP6_HOOK_PACKET_SEND_SKIP", "%1: prepared DHCPv6 response is not built because a callout set the next step to SKIP",
"DHCP6_HOOK_REGISTER6_SKIP", "%1: add-reg-inform for %2 is dropped, because a callout set the next step to SKIP",
"DHCP6_HOOK_SUBNET6_SELECT_DROP", "%1: packet was dropped because a callout set the drop flag",
"DHCP6_HOOK_SUBNET6_SELECT_PARK", "%1: packet was parked",
"DHCP6_HOOK_SUBNET6_SELECT_SKIP", "%1: no subnet was selected because a callout set the next step to SKIP",

View File

@ -14,6 +14,8 @@ extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_RESULT;
extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_NO_TEST;
extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_UNDEFINED;
extern const isc::log::MessageID DHCP6_ADD_GLOBAL_STATUS_CODE;
extern const isc::log::MessageID DHCP6_ADD_REG_INFORM_CLIENT_CHANGE;
extern const isc::log::MessageID DHCP6_ADD_REG_INFORM_FAIL;
extern const isc::log::MessageID DHCP6_ADD_STATUS_CODE_FOR_IA;
extern const isc::log::MessageID DHCP6_ALREADY_RUNNING;
extern const isc::log::MessageID DHCP6_BUFFER_RECEIVED;
@ -78,6 +80,7 @@ extern const isc::log::MessageID DHCP6_HOOK_LEASES6_PARKING_LOT_FULL;
extern const isc::log::MessageID DHCP6_HOOK_PACKET_RCVD_SKIP;
extern const isc::log::MessageID DHCP6_HOOK_PACKET_SEND_DROP;
extern const isc::log::MessageID DHCP6_HOOK_PACKET_SEND_SKIP;
extern const isc::log::MessageID DHCP6_HOOK_REGISTER6_SKIP;
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_DROP;
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_PARK;
extern const isc::log::MessageID DHCP6_HOOK_SUBNET6_SELECT_SKIP;

View File

@ -44,6 +44,16 @@ Status Code option. The first argument includes the client and the
transaction identification information. The second argument includes
the details of the status code.
% DHCP6_ADD_REG_INFORM_FAIL error on add-reg-inform from client %1: %2
This information message is issued when the processing of an add-reg-inform
message failed. The address of the client, usually also the address to
register, and the description of the problem are printed.
% DHCP6_ADD_REG_INFORM_CLIENT_CHANGE received an add-reg-inform for %1 from client '%2' but the address was registered by another client '%3'
This information message is issued when a lease for another client already
exists for an address being registered. The address, the new client and
previous client identifiers are printed.
% DHCP6_ADD_STATUS_CODE_FOR_IA %1: adding Status Code to IA with iaid=%2: %3
Logged at debug log level 50.
This message is logged when the server is adding the Status Code
@ -484,6 +494,13 @@ not build the wire data (pack) because it was already done by the
book. The argument specifies the client and transaction identification
information.
% DHCP6_HOOK_REGISTER6_SKIP %1: add-reg-inform for %2 is dropped, because a callout set the next step to SKIP
Logged at debug log level 40.
This debug message is printed when a callout installed on the register6
hook point sets the next step to SKIP. For this particular hook point, the
value setting instructs the server to cancel the address registration and
drop the packet.
% DHCP6_HOOK_SUBNET6_SELECT_DROP %1: packet was dropped because a callout set the drop flag
Logged at debug log level 40.
This debug message is printed when a callout installed on the

View File

@ -145,6 +145,7 @@ struct Dhcp6Hooks {
int hook_index_lease6_decline_; ///< index for "lease6_decline" hook point
int hook_index_host6_identifier_; ///< index for "host6_identifier" hook point
int hook_index_ddns6_update_; ///< index for "ddns6_update" hook point
int hook_index_register6_; ///< index for "register6" hook point
/// Constructor that registers hook points for DHCPv6 engine
Dhcp6Hooks() {
@ -158,6 +159,7 @@ struct Dhcp6Hooks {
hook_index_lease6_decline_ = HooksManager::registerHook("lease6_decline");
hook_index_host6_identifier_ = HooksManager::registerHook("host6_identifier");
hook_index_ddns6_update_ = HooksManager::registerHook("ddns6_update");
hook_index_register6_ = HooksManager::registerHook("register6");
}
};
@ -4513,6 +4515,7 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
ctx.createIAContext();
ctx.currentIA().type_ = Lease::TYPE_NA;
ctx.currentIA().iaid_ = ia->getIAID();
ctx.currentIA().ia_rsp_ = ia;
// Get IAADDR from the IA_NA. There must be the only option.
OptionCollection iaaddrs = ia->getOptions();
@ -4524,7 +4527,6 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
if (!iaaddr) {
isc_throw(RFCViolation, "Can't get the IAADDR sub-option");
}
ctx.currentIA().addHint(iaaddr);
// Client and IADDR addresses must match.
if (addr != iaaddr->getAddress()) {
@ -4554,13 +4556,27 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
isc_throw(RFCViolation, "Address " << addr << " is reserved");
}
} catch (const std::exception &ex) {
// log
// Incoming processing failed.
LOG_INFO(packet6_logger, DHCP6_ADD_REG_INFORM_FAIL)
.arg(addr)
.arg(ex.what());
return (Pkt6Ptr());
}
// Record if it is a registration renewal.
bool renewal = !!old_lease;
// Check if the client is the same.
if (old_lease && old_lease->duid_ && *ctx.duid_ != *(old_lease->duid_)) {
// log
if (old_lease) {
if (old_lease->duid_ && (*ctx.duid_ != *(old_lease->duid_))) {
LOG_INFO(packet6_logger, DHCP6_ADD_REG_INFORM_CLIENT_CHANGE)
.arg(addr)
.arg(ctx.duid_->toText())
.arg(old_lease->duid_->toText());
}
if (old_lease->subnet_id_ != subnet->getID()) {
renewal = false;
}
}
// Build response.
@ -4597,37 +4613,83 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
appendRequestedOptions(add_reg_inf, add_reg_rep, co_list);
appendRequestedVendorOptions(add_reg_inf, add_reg_rep, ctx, co_list);
// call the new callout
// Handle the "register6" callout point.
if (HooksManager::calloutsPresent(Hooks.hook_index_register6_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(add_reg_inf);
ScopedCalloutHandleState callout_handle_state(callout_handle);
// Add stats
if (old_lease) {
// Save the old lease for the lease6_committed callout.
ctx.currentIA().old_leases_.push_back(old_lease);
if (!lease) {
if (!LeaseMgrFactory::instance().deleteLease(old_lease)) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
}
} else {
// Pass the query6 argument.
ScopedEnableOptionsCopy<Pkt6> query6_options_copy(add_reg_inf);
callout_handle->setArgument("query6", add_reg_inf);
// Pass the response6 argument.
ScopedEnableOptionsCopy<Pkt6> rsp6_options_copy(add_reg_rep);
callout_handle->setArgument("response6", add_reg_rep);
// Pass the address6 argument.
callout_handle->setArgument("address6", addr);
// Pass the old_lease argument.
callout_handle->setArgument("old_lease6", old_lease);
// Pass the new_lease argument.
callout_handle->setArgument("new_lease6", lease);
// Call callouts
HooksManager::callCallouts(Hooks.hook_index_register6_, *callout_handle);
// Callouts decided to skip the next processing step. This means
// cancel processing so drop.
if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
(callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_REGISTER6_SKIP)
.arg(add_reg_inf->getLabel())
.arg(addr);
return (Pkt6Ptr());
}
Lease6Ptr new_lease;
callout_handle->getArgument("new_lease6", new_lease);
if (!new_lease) {
// Stateless registration: skip lease code.
lease.reset();
}
}
if (lease) {
// Statefull registration.
if (old_lease) {
try {
LeaseMgrFactory::instance().updateLease6(lease);
} catch (const std::exception&) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
}
// Save the old lease for the lease6_committed callout.
ctx.currentIA().old_leases_.push_back(old_lease);
if (!renewal) {
// -1 on stats.
} else {
// Save the old lease for the DNS update.
ctx.currentIA().changed_leases_.push_back(old_lease);
}
} else {
if (!LeaseMgrFactory::instance().addLease(lease)) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
}
}
} else if (lease) {
if (!LeaseMgrFactory::instance().addLease(lease)) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
}
}
if (lease) {
// Save the new lease for the lease6_committed callout.
ctx.new_leases_.push_back(lease);
if (!renewal) {
// +1 on stats
}
}
// Deal with FQDN.
updateReservedFqdn(ctx, add_reg_rep);
generateFqdn(add_reg_rep, ctx);
createNameChangeRequests(add_reg_rep, ctx);
return (add_reg_rep);
}

View File

@ -8,7 +8,7 @@
% DHCP4_CLASS_ASSIGNED: 3
% DHCP4_PACKET_QUEUE_FULL: 2
% DHCP4_CONFIG_RECEIVED: 2
% DHCP6_CLASSES_ASSIGNED: 8
% DHCP6_CLASSES_ASSIGNED: 9
% DHCP6_CLASS_ASSIGNED: 3
% DHCP6_PACKET_QUEUE_FULL: 2
% DHCP6_CONFIG_RECEIVED: 2