2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-22 09:57:41 +00:00

[#3683] Checkpoint: UTs to do

This commit is contained in:
Francis Dupont 2025-02-23 23:03:25 +01:00
parent 6fa6476543
commit 7a90a14a1b
21 changed files with 520 additions and 128 deletions

View File

@ -6846,6 +6846,29 @@ confusion, ISC decided not to decrease ``assigned-nas`` immediately after
receiving DHCPDECLINE, but to do it later when Kea recovers the address
back to the available pool.
.. _dhcp6-address-registration:
Address Registration (RFC 9686 Support)
=======================================
Kea version 2.7.7 introduces the support of self-generated address registration
as defined in `RFC 9686 <https://tools.ietf.org/html/rfc9686>`__ i.e.
when a valid ADDR-REG-INFORM (36) message in received a registered lease is
added or updated and a ADDR-REG-REPLY (37) is sent back to the client.
.. note::
Even if they share a common lease database with leases in other states,
registered leases are independent: when a lease in another state already
exists for an address this address in considered as in use and can't be
registered. In the other way a registered lease can't change to another
state, e.g. reclaimation of expired registered leases removes them.
.. note::
Kea accepts and handles the Option Request option in the ADDR-REG-INFORM
message (the RFC specifies the client MUST NOT put such option in it).
.. _dhcp6-stats:
Statistics in the DHCPv6 Server
@ -7011,6 +7034,26 @@ The DHCPv6 server supports the following statistics:
| | | the server rather than back to the |
| | | clients. |
+---------------------------------------------------+----------------+------------------------------------+
| pkt6-addr-reg-inform-received | integer | Number of ADDR-REG-INFORM packets |
| | | received. This statistic is |
| | | expected to grow if there are |
| | | devices that are using address |
| | | registration. |
+---------------------------------------------------+----------------+------------------------------------+
| pkt6-addr-reg-reply-received | integer | Number of ADDR-REG-REPLY packets |
| | | received. This statistic is |
| | | expected to remain zero at all |
| | | times, as ADDR-REG-REPLY packets |
| | | are sent by the server and the |
| | | server is never expected to |
| | | receive them. A non-zero value |
| | | indicates an error. One likely |
| | | cause would be a misbehaving relay |
| | | agent that incorrectly forwards |
| | | ADDR-REG-REPLY message towards the |
| | | server rather than back to the |
| | | clients. |
+---------------------------------------------------+----------------+------------------------------------+
| pkt6-unknown-received | integer | Number of packets received of an |
| | | unknown type. A non-zero value of |
| | | this statistic indicates that the |
@ -7058,6 +7101,13 @@ The DHCPv6 server supports the following statistics:
| | | are certain cases where there is |
| | | no response. |
+---------------------------------------------------+----------------+------------------------------------+
| pkt6-addr-reg-reply-sent | integer | Number of ADDR-REG-REPLY packets |
| | | sent. This statistic is expected |
| | | to grow in most cases after a |
| | | ADDR-REG-INFORM is processed. |
| | | There are certain cases where |
| | | there is n response. |
+---------------------------------------------------+----------------+------------------------------------+
| subnet[id].total-nas | big integer | Total number of NA addresses |
| | | available for DHCPv6 management |
| | | for a given subnet; in other |
@ -7527,6 +7577,38 @@ The DHCPv6 server supports the following statistics:
| | | basis. The *id* is the subnet ID |
| | | of a given subnet. |
+---------------------------------------------------+----------------+------------------------------------+
| cumulative-registered | integer | Cumulative number of NA addresses |
| | | that have been registered since |
| | | server startup. It is incremented |
| | | each time a NA address is |
| | | registered and is not reset when |
| | | the server is reconfigured. |
+---------------------------------------------------+----------------+------------------------------------+
| subnet[id].cumulative-registered | integer | Cumulative number of NA addresses |
| | | in a given subnet that were |
| | | registered. It increases every |
| | | a new address is registered (as a |
| | | result of receiving an |
| | | ADDR-REG-INFORM message) and is |
| | | never decreased. The *id* is the |
| | | subnet ID of a given subnet. This |
| | | statistic is exposed for each |
| | | subnet separately, and is reset |
| | | during a reconfiguration event. |
+---------------------------------------------------+----------------+------------------------------------+
| subnet[id].registered | integer | Number of NA addresses in a given |
| | | subnet that are registered. It |
| | | increases every time a new address |
| | | registered (as a result of |
| | | receiving an ADDR-REG-INFORM |
| | | message) and is decreased every |
| | | time a registration expires. The |
| | | *id* is the the subnet ID of a |
| | | given subnet. This statistic is |
| | | exposed for each subnet |
| | | separately, and is reset during a |
| | | reconfiguration event. |
+---------------------------------------------------+----------------+------------------------------------+
.. note::
@ -8015,6 +8097,9 @@ The following standards are currently supported in Kea:
Resolvers (DNR)*, `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The Kea server
supports the DNR option.
- *Registering Self-Generated IPv6 Addresses Using DHCPv6*, `RFC 9686 <https://tools.ietf.org/html/rfc9686>`__. The Kea server supports self-generated address registration. See :ref:`dhcp6-address-registration` for details.
.. _dhcp6-limit:
DHCPv6 Server Limitations

View File

@ -74,6 +74,7 @@ The dhcpv6 hook points:
leases6_committed
lease6_release
lease6_decline
addr6_register
Each hook point extracts the Kea internal data and exports it as string
environment variables. These parameters are shared with the target script
@ -145,6 +146,10 @@ An example of a script implementing all hook points is presented below:
...
}
addr6_register () {
...
}
case "$1" in
"lease4_renew")
lease4_renew
@ -185,6 +190,9 @@ An example of a script implementing all hook points is presented below:
"lease6_decline")
lease6_decline
;;
"addr6_register")
addr6_register
;;
*)
unknown_handle "${@}"
;;
@ -626,6 +634,52 @@ at 0.
LEASE6_PREFIX_LEN
LEASE6_TYPE
``addr6_register``
::
QUERY6_TYPE
QUERY6_TXID
QUERY6_LOCAL_ADDR
QUERY6_LOCAL_PORT
QUERY6_REMOTE_ADDR
QUERY6_REMOTE_PORT
QUERY6_IFACE_INDEX
QUERY6_IFACE_NAME
QUERY6_REMOTE_HWADDR
QUERY6_REMOTE_HWADDR_TYPE
QUERY6_PROTO
QUERY6_CLIENT_ID
ADDRESS6
OLD_LEASE6_ADDRESS
OLD_LEASE6_CLTT
OLD_LEASE6_HOSTNAME
OLD_LEASE6_HWADDR
OLD_LEASE6_HWADDR_TYPE
OLD_LEASE6_STATE
OLD_LEASE6_SUBNET_ID
OLD_LEASE6_VALID_LIFETIME
OLD_LEASE6_DUID
OLD_LEASE6_IAID
OLD_LEASE6_PREFERRED_LIFETIME
OLD_LEASE6_PREFIX_LEN
OLD_LEASE6_TYPE
NEW_LEASE6_ADDRESS
NEW_LEASE6_CLTT
NEW_LEASE6_HOSTNAME
NEW_LEASE6_HWADDR
NEW_LEASE6_HWADDR_TYPE
NEW_LEASE6_STATE
NEW_LEASE6_SUBNET_ID
NEW_LEASE6_VALID_LIFETIME
NEW_LEASE6_DUID
NEW_LEASE6_IAID
NEW_LEASE6_PREFERRED_LIFETIME
NEW_LEASE6_PREFIX_LEN
NEW_LEASE6_TYPE
The OLD_LEASE6 do not always exists.
The leases4_committed hook point needs for loops to handle the list of addresses.
This can be achived in the following way:

View File

@ -499,12 +499,36 @@ or
"2023-06-13 21:28:57.196758"
]
],
"cumulative-registered": [
[
0,
"2023-06-13 21:28:57.196758"
]
],
"declined-addresses": [
[
0,
"2023-06-13 21:28:57.196754"
]
],
"pkt6-addr-reg-inform-received": [
[
0,
"2023-06-13 21:28:57.177731"
]
],
"pkt6-addr-reg-reply-received": [
[
0,
"2023-06-13 21:28:57.177731"
]
],
"pkt6-addr-reg-reply-sent": [
[
0,
"2023-06-13 21:28:57.177731"
]
],
"pkt6-advertise-received": [
[
0,
@ -655,6 +679,12 @@ or
"2023-06-13 21:28:57.196729"
]
],
"subnet[1].cumulative-registered": [
[
0,
"2023-06-13 21:28:57.196727"
]
],
"subnet[1].declined-addresses": [
[
0,
@ -733,6 +763,12 @@ or
"2023-06-13 21:28:57.196770"
]
],
"subnet[1].registered": [
[
0,
"2023-06-13 21:28:57.196727"
]
],
"subnet[1].total-nas": [
[
281474976710656,

View File

@ -345,7 +345,7 @@ called before "subnet6_select".
- <b>Next step status</b>: Not applicable, its value will be ignored.
@subsection dhcpv6HookRegister6 register6
@subsection dhcpv6HookAddr6Register addr6_register
- @b Arguments:
- name: @b query6, type: isc::dhcp::Pkt6Ptr, direction: <b>in</b>

View File

@ -12,9 +12,9 @@ extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_ERROR = "DHCP6_ADDI
extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_RESULT = "DHCP6_ADDITIONAL_CLASS_EVAL_RESULT";
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_ADDR_REG_INFORM_CLIENT_CHANGE = "DHCP6_ADDR_REG_INFORM_CLIENT_CHANGE";
extern const isc::log::MessageID DHCP6_ADDR_REG_INFORM_FAIL = "DHCP6_ADDR_REG_INFORM_FAIL";
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";
@ -65,6 +65,7 @@ extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION = "DHCP6_DYNAMIC_
extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_FAIL = "DHCP6_DYNAMIC_RECONFIGURATION_FAIL";
extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS = "DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS";
extern const isc::log::MessageID DHCP6_FLEX_ID = "DHCP6_FLEX_ID";
extern const isc::log::MessageID DHCP6_HOOK_ADDR6_REGISTER_SKIP = "DHCP6_HOOK_ADDR6_REGISTER_SKIP";
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_RCVD_DROP = "DHCP6_HOOK_BUFFER_RCVD_DROP";
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_RCVD_SKIP = "DHCP6_HOOK_BUFFER_RCVD_SKIP";
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_SEND_SKIP = "DHCP6_HOOK_BUFFER_SEND_SKIP";
@ -79,7 +80,6 @@ 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";
@ -140,6 +140,8 @@ extern const isc::log::MessageID DHCP6_QUERY_DATA = "DHCP6_QUERY_DATA";
extern const isc::log::MessageID DHCP6_QUERY_LABEL = "DHCP6_QUERY_LABEL";
extern const isc::log::MessageID DHCP6_RAPID_COMMIT = "DHCP6_RAPID_COMMIT";
extern const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL = "DHCP6_RECLAIM_EXPIRED_LEASES_FAIL";
extern const isc::log::MessageID DHCP6_REGISTERED_LEASE_ADD_FAIL = "DHCP6_REGISTERED_LEASE_ADD_FAIL";
extern const isc::log::MessageID DHCP6_REGISTERED_LEASE_UPDATE_FAIL = "DHCP6_REGISTERED_LEASE_UPDATE_FAIL";
extern const isc::log::MessageID DHCP6_RELEASE_NA = "DHCP6_RELEASE_NA";
extern const isc::log::MessageID DHCP6_RELEASE_NA_DELETED = "DHCP6_RELEASE_NA_DELETED";
extern const isc::log::MessageID DHCP6_RELEASE_NA_EXPIRED = "DHCP6_RELEASE_NA_EXPIRED";
@ -182,9 +184,9 @@ const char* values[] = {
"DHCP6_ADDITIONAL_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
"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_ADDR_REG_INFORM_CLIENT_CHANGE", "received an addr-reg-inform for %1 from client '%2' but the address was registered by another client '%3'",
"DHCP6_ADDR_REG_INFORM_FAIL", "error on addr-reg-inform from client %1: %2",
"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",
@ -235,6 +237,7 @@ const char* values[] = {
"DHCP6_DYNAMIC_RECONFIGURATION_FAIL", "dynamic server reconfiguration failed with file: %1",
"DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS", "dynamic server reconfiguration succeeded with file: %1",
"DHCP6_FLEX_ID", "%1: flexible identifier generated for incoming packet: %2",
"DHCP6_HOOK_ADDR6_REGISTER_SKIP", "%1: addr-reg-inform for %2 is dropped, because a callout set the next step to SKIP",
"DHCP6_HOOK_BUFFER_RCVD_DROP", "received buffer from %1 to %2 over interface %3 was dropped because a callout set the drop flag",
"DHCP6_HOOK_BUFFER_RCVD_SKIP", "received buffer from %1 to %2 over interface %3 is not parsed because a callout set the next step to SKIP",
"DHCP6_HOOK_BUFFER_SEND_SKIP", "%1: prepared DHCPv6 response was dropped because a callout set the next step to SKIP",
@ -249,7 +252,6 @@ 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",
@ -310,6 +312,8 @@ const char* values[] = {
"DHCP6_QUERY_LABEL", "received query: %1",
"DHCP6_RAPID_COMMIT", "%1: Rapid Commit option received, following 2-way exchange",
"DHCP6_RECLAIM_EXPIRED_LEASES_FAIL", "failed to reclaim expired leases: %1",
"DHCP6_REGISTERED_LEASE_ADD_FAIL", "error in registered lease add for %1",
"DHCP6_REGISTERED_LEASE_UPDATE_FAIL", "error in registered lease update for %1: %2",
"DHCP6_RELEASE_NA", "%1: binding for address %2 and iaid=%3 was released properly",
"DHCP6_RELEASE_NA_DELETED", "%1: binding for address %2 and iaid=%3 was deleted on release",
"DHCP6_RELEASE_NA_EXPIRED", "%1: binding for address %2 and iaid=%3 expired on release",

View File

@ -13,9 +13,9 @@ extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_ERROR;
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_ADDR_REG_INFORM_CLIENT_CHANGE;
extern const isc::log::MessageID DHCP6_ADDR_REG_INFORM_FAIL;
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;
@ -66,6 +66,7 @@ extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION;
extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_FAIL;
extern const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS;
extern const isc::log::MessageID DHCP6_FLEX_ID;
extern const isc::log::MessageID DHCP6_HOOK_ADDR6_REGISTER_SKIP;
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_RCVD_DROP;
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_RCVD_SKIP;
extern const isc::log::MessageID DHCP6_HOOK_BUFFER_SEND_SKIP;
@ -80,7 +81,6 @@ 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;
@ -141,6 +141,8 @@ extern const isc::log::MessageID DHCP6_QUERY_DATA;
extern const isc::log::MessageID DHCP6_QUERY_LABEL;
extern const isc::log::MessageID DHCP6_RAPID_COMMIT;
extern const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL;
extern const isc::log::MessageID DHCP6_REGISTERED_LEASE_ADD_FAIL;
extern const isc::log::MessageID DHCP6_REGISTERED_LEASE_UPDATE_FAIL;
extern const isc::log::MessageID DHCP6_RELEASE_NA;
extern const isc::log::MessageID DHCP6_RELEASE_NA_DELETED;
extern const isc::log::MessageID DHCP6_RELEASE_NA_EXPIRED;

View File

@ -44,16 +44,6 @@ 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
@ -61,6 +51,16 @@ option to an IA. The first argument includes the client and the
transaction identification information. The second argument specifies
the IAID. The third argument includes the details of the status code.
% DHCP6_ADDR_REG_INFORM_FAIL error on addr-reg-inform from client %1: %2
This information message is issued when the processing of an addr-reg-inform
message failed. The address of the client, usually also the address to
register, and the description of the problem are printed.
% DHCP6_ADDR_REG_INFORM_CLIENT_CHANGE received an addr-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_ALREADY_RUNNING %1 already running? %2
This is an error message that occurs when the DHCPv6 server encounters
a pre-existing PID file which contains the PID of a running process.
@ -380,6 +380,13 @@ and the expression specified in its configuration generated (was evaluated to)
an identifier for incoming packet. This debug message is mainly intended as a
debugging assistance for flexible identifier.
% DHCP6_HOOK_ADDR6_REGISTER_SKIP %1: addr-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 addr6_register
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_BUFFER_RCVD_DROP received buffer from %1 to %2 over interface %3 was dropped because a callout set the drop flag
Logged at debug log level 15.
This debug message is printed when a callout installed on buffer6_receive
@ -494,13 +501,6 @@ 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
@ -921,6 +921,14 @@ specifies the client and transaction identification information.
This error message indicates that the reclaim expired leases operation failed
and provides the cause of failure.
% DHCP6_REGISTERED_LEASE_ADD_FAIL error in registered lease add for %1
This error message indicates that the registered lease add failed and
provides the address being registered.
% DHCP6_REGISTERED_LEASE_UPDATE_FAIL error in registered lease update for %1: %2
This error message indicates that the registered lease update failed and
provides the registered address and the cause of failure.
% DHCP6_RELEASE_NA %1: binding for address %2 and iaid=%3 was released properly
This informational message indicates that an address was released properly. It
is a normal operation during client shutdown. The first argument includes

View File

@ -145,7 +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
int hook_index_addr6_register_; ///< index for "addr6_register" hook point
/// Constructor that registers hook points for DHCPv6 engine
Dhcp6Hooks() {
@ -159,7 +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");
hook_index_addr6_register_ = HooksManager::registerHook("addr6_register");
}
};
@ -1035,7 +1035,7 @@ Dhcpv6Srv::processDhcp6Query(Pkt6Ptr query) {
(query->getType() == DHCPV6_REBIND) ||
(query->getType() == DHCPV6_RELEASE) ||
(query->getType() == DHCPV6_DECLINE) ||
(query->getType() == DHCPV6_ADD_REG_INFORM))) {
(query->getType() == DHCPV6_ADDR_REG_INFORM))) {
ContinuationPtr cont =
makeContinuation(std::bind(&Dhcpv6Srv::processDhcp6QueryAndSendResponse,
this, query));
@ -1152,8 +1152,8 @@ Dhcpv6Srv::processLocalizedQuery6(AllocEngine::ClientContext6& ctx) {
rsp = processInfRequest(ctx);
break;
case DHCPV6_ADD_REG_INFORM:
rsp = processAddRegInform(ctx);
case DHCPV6_ADDR_REG_INFORM:
rsp = processAddrRegInform(ctx);
break;
default:
@ -1985,7 +1985,7 @@ Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt) {
case DHCPV6_SOLICIT:
case DHCPV6_REBIND:
case DHCPV6_CONFIRM:
case DHCPV6_ADD_REG_INFORM:
case DHCPV6_ADDR_REG_INFORM:
sanityCheck(pkt, MANDATORY, FORBIDDEN);
return (true);
@ -4474,7 +4474,7 @@ Dhcpv6Srv::processDhcp4Query(const Pkt6Ptr& dhcp4_query) {
}
Pkt6Ptr
Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
Dhcpv6Srv::processAddrRegInform(AllocEngine::ClientContext6& ctx) {
ConstSubnetPtr subnet = ctx.subnet_;
// Silently ignore message which can't be localized
@ -4482,15 +4482,15 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
return (Pkt6Ptr());
}
Pkt6Ptr add_reg_inf = ctx.query_;
Pkt6Ptr addr_reg_inf = ctx.query_;
// Get the client source address.
IOAddress addr = add_reg_inf->getRemoteAddr();
IOAddress addr = addr_reg_inf->getRemoteAddr();
// If there are some relays get the peer address of the closest relay
// to the client.
size_t relay_level = add_reg_inf->relay_info_.size();
size_t relay_level = addr_reg_inf->relay_info_.size();
if (relay_level > 0) {
addr = add_reg_inf->getRelay6LinkAddress(relay_level - 1);
addr = addr_reg_inf->getRelay6LinkAddress(relay_level - 1);
}
Option6IAPtr ia;
@ -4501,7 +4501,7 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
try {
// Get IA_NA from the Address registration inform.
// There must be one.
OptionCollection ias = add_reg_inf->getOptions(D6O_IA_NA);
OptionCollection ias = addr_reg_inf->getOptions(D6O_IA_NA);
if (ias.size() != 1) {
isc_throw(RFCViolation, "Exactly 1 IA_NA option expected, but "
<< ias.size() << " received");
@ -4557,35 +4557,29 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
}
} catch (const std::exception &ex) {
// Incoming processing failed.
LOG_INFO(packet6_logger, DHCP6_ADD_REG_INFORM_FAIL)
LOG_INFO(packet6_logger, DHCP6_ADDR_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) {
if (old_lease->duid_ && (*ctx.duid_ != *(old_lease->duid_))) {
LOG_INFO(packet6_logger, DHCP6_ADD_REG_INFORM_CLIENT_CHANGE)
LOG_INFO(packet6_logger, DHCP6_ADDR_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.
Pkt6Ptr add_reg_rep(new Pkt6(DHCPV6_ADD_REG_REPLY,
add_reg_inf->getTransid()));
add_reg_rep->addOption(ia);
Pkt6Ptr addr_reg_rep(new Pkt6(DHCPV6_ADDR_REG_REPLY,
addr_reg_inf->getTransid()));
addr_reg_rep->addOption(ia);
// Process FQDN.
processClientFqdn(add_reg_inf, add_reg_rep, ctx);
processClientFqdn(addr_reg_inf, addr_reg_rep, ctx);
Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, ctx.duid_,
ia->getIAID(), iaaddr->getPreferred(),
@ -4596,35 +4590,35 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
lease->fqdn_rev_ = ctx.rev_dns_update_;
lease->hostname_ = ctx.hostname_;
conditionallySetReservedClientClasses(add_reg_inf, ctx);
conditionallySetReservedClientClasses(addr_reg_inf, ctx);
// Evaluate additional classes.
evaluateAdditionalClasses(add_reg_inf, ctx);
evaluateAdditionalClasses(addr_reg_inf, ctx);
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASSES_ASSIGNED)
.arg(add_reg_inf->getLabel())
.arg(add_reg_inf->getName())
.arg(add_reg_inf->getClasses().toText());
.arg(addr_reg_inf->getLabel())
.arg(addr_reg_inf->getName())
.arg(addr_reg_inf->getClasses().toText());
copyClientOptions(add_reg_inf, add_reg_rep);
copyClientOptions(addr_reg_inf, addr_reg_rep);
CfgOptionList co_list;
buildCfgOptionList(add_reg_inf, ctx, co_list);
buildCfgOptionList(addr_reg_inf, ctx, co_list);
// The RFC says to not do that...
appendDefaultOptions(add_reg_inf, add_reg_rep, co_list);
appendRequestedOptions(add_reg_inf, add_reg_rep, co_list);
appendRequestedVendorOptions(add_reg_inf, add_reg_rep, ctx, co_list);
appendDefaultOptions(addr_reg_inf, addr_reg_rep, co_list);
appendRequestedOptions(addr_reg_inf, addr_reg_rep, co_list);
appendRequestedVendorOptions(addr_reg_inf, addr_reg_rep, ctx, co_list);
// Handle the "register6" callout point.
if (HooksManager::calloutsPresent(Hooks.hook_index_register6_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(add_reg_inf);
// Handle the "addr6_register" callout point.
if (HooksManager::calloutsPresent(Hooks.hook_index_addr6_register_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(addr_reg_inf);
ScopedCalloutHandleState callout_handle_state(callout_handle);
// Pass the query6 argument.
ScopedEnableOptionsCopy<Pkt6> query6_options_copy(add_reg_inf);
callout_handle->setArgument("query6", add_reg_inf);
ScopedEnableOptionsCopy<Pkt6> query6_options_copy(addr_reg_inf);
callout_handle->setArgument("query6", addr_reg_inf);
// Pass the response6 argument.
ScopedEnableOptionsCopy<Pkt6> rsp6_options_copy(add_reg_rep);
callout_handle->setArgument("response6", add_reg_rep);
ScopedEnableOptionsCopy<Pkt6> rsp6_options_copy(addr_reg_rep);
callout_handle->setArgument("response6", addr_reg_rep);
// Pass the address6 argument.
callout_handle->setArgument("address6", addr);
@ -4636,14 +4630,15 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
callout_handle->setArgument("new_lease6", lease);
// Call callouts
HooksManager::callCallouts(Hooks.hook_index_register6_, *callout_handle);
HooksManager::callCallouts(Hooks.hook_index_addr6_register_, *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())
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS,
DHCP6_HOOK_ADDR6_REGISTER_SKIP)
.arg(addr_reg_inf->getLabel())
.arg(addr);
return (Pkt6Ptr());
}
@ -4661,37 +4656,61 @@ Dhcpv6Srv::processAddRegInform(AllocEngine::ClientContext6& ctx) {
if (old_lease) {
try {
LeaseMgrFactory::instance().updateLease6(lease);
} catch (const std::exception&) {
} catch (const std::exception& ex) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
LOG_ERROR(dhcp6_logger, DHCP6_REGISTERED_LEASE_UPDATE_FAIL)
.arg(addr)
.arg(ex.what());
return (Pkt6Ptr());
}
// 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);
// Update stats when the subnet changed.
if (old_lease->subnet_id_ != lease->subnet_id_) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", old_lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(-1));
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(1));
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"cumulative-registered-nas"),
static_cast<int64_t>(1));
}
} else {
if (!LeaseMgrFactory::instance().addLease(lease)) {
// Assume that stats and DNS were handled by someone else.
return (add_reg_rep);
LOG_ERROR(dhcp6_logger, DHCP6_REGISTERED_LEASE_ADD_FAIL)
.arg(addr);
return (Pkt6Ptr());
}
// Update stats.
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(1));
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"cumulative-registered-nas"),
static_cast<int64_t>(1));
StatsMgr::instance().addValue("cumulative-registered-nas",
static_cast<int64_t>(1));
}
// 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);
updateReservedFqdn(ctx, addr_reg_rep);
generateFqdn(addr_reg_rep, ctx);
createNameChangeRequests(addr_reg_rep, ctx);
return (add_reg_rep);
return (addr_reg_rep);
}
void Dhcpv6Srv::classifyByVendor(const Pkt6Ptr& pkt) {
@ -5158,12 +5177,12 @@ void Dhcpv6Srv::processStatsReceived(const Pkt6Ptr& query) {
// Should not happen, but let's keep a counter for it
stat_name = "pkt6-dhcpv4-response-received";
break;
case DHCPV6_ADD_REG_INFORM:
stat_name = "pkt6-add-reg-inform-received";
case DHCPV6_ADDR_REG_INFORM:
stat_name = "pkt6-addr-reg-inform-received";
break;
case DHCPV6_ADD_REG_REPLY:
case DHCPV6_ADDR_REG_REPLY:
// Should not happen, but let's keep a counter for it
stat_name = "pkt6-add-reg-reply-received";
stat_name = "pkt6-addr-reg-reply-received";
break;
default:
; // do nothing
@ -5188,8 +5207,8 @@ void Dhcpv6Srv::processStatsSent(const Pkt6Ptr& response) {
case DHCPV6_DHCPV4_RESPONSE:
stat_name = "pkt6-dhcpv4-response-sent";
break;
case DHCPV6_ADD_REG_REPLY:
stat_name = "pkt6-add-reg-reply-sent";
case DHCPV6_ADDR_REG_REPLY:
stat_name = "pkt6-addr-reg-reply-sent";
break;
default:
// That should never happen

View File

@ -480,12 +480,12 @@ protected:
/// Does not throw
void processDhcp4Query(const Pkt6Ptr& dhcp4_query);
/// @brief Processes incoming Add-reg-inform message.
/// @brief Processes incoming Addr-reg-inform message.
///
/// @param ctx Reference to client context
///
/// @return Add-reg-reply message to be sent to the client.
Pkt6Ptr processAddRegInform(AllocEngine::ClientContext6& ctx);
/// @return Addr-reg-reply message to be sent to the client.
Pkt6Ptr processAddrRegInform(AllocEngine::ClientContext6& ctx);
/// @brief Selects a subnet for a given client's packet.
///

View File

@ -560,7 +560,11 @@ LeaseCmdsImpl::updateStatsOnAdd(const Lease4Ptr& lease) {
void
LeaseCmdsImpl::updateStatsOnAdd(const Lease6Ptr& lease) {
if (!lease->stateExpiredReclaimed()) {
if (lease->stateRegistered()) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_, "registered-nas"),
static_cast<int64_t>(1));
} else if (!lease->stateExpiredReclaimed()) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
lease->type_ == Lease::TYPE_NA ?
@ -733,7 +737,19 @@ LeaseCmdsImpl::updateStatsOnUpdate(const Lease4Ptr& existing,
void
LeaseCmdsImpl::updateStatsOnUpdate(const Lease6Ptr& existing,
const Lease6Ptr& lease) {
if (!existing->stateExpiredReclaimed()) {
// Does not cover registered <-> not registered transition.
if (existing->stateRegistered()) {
if (existing->subnet_id_ != lease->subnet_id_) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", existing->subnet_id_,
"registered-nas"),
static_cast<int64_t>(-1));
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(1));
}
} else if (!existing->stateExpiredReclaimed()) {
ConstSubnet6Ptr subnet;
PoolPtr pool;
@ -910,7 +926,12 @@ LeaseCmdsImpl::updateStatsOnDelete(const Lease4Ptr& lease) {
void
LeaseCmdsImpl::updateStatsOnDelete(const Lease6Ptr& lease) {
if (!lease->stateExpiredReclaimed()) {
if (lease->stateRegistered()) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(-1));
} else if (!lease->stateExpiredReclaimed()) {
StatsMgr::instance().addValue(
StatsMgr::generateName("subnet", lease->subnet_id_,
lease->type_ == Lease::TYPE_NA ?
@ -996,6 +1017,15 @@ LeaseCmdsImpl::addOrUpdate6(Lease6Ptr lease, bool force_create) {
return (true);
}
if (existing) {
// Refuse used <-> registered transitions.
if (existing->stateRegistered() && !lease->stateRegistered()) {
isc_throw(BadValue, "illegal reuse of registered address "
<< lease->addr_);
} else if (!existing->stateRegistered() && lease->stateRegistered()) {
isc_throw(BadValue, "address in use: " << lease->addr_
<< " can't be registered");
}
// Update lease current expiration time with value received from the
// database. Some database backends reject operations on the lease if
// the current expiration time value does not match what is stored.
@ -2410,6 +2440,10 @@ LeaseCmdsImpl::lease6WipeHandler(CalloutHandle& handle) {
StatsMgr::generateName("subnet", id, "declined-addresses"),
static_cast<int64_t>(0));
StatsMgr::instance().setValue(
StatsMgr::generateName("subnet", id, "registered-nas"),
static_cast<int64_t>(0));
auto const& sub = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(id);
if (sub) {
for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
@ -2461,6 +2495,10 @@ LeaseCmdsImpl::lease6WipeHandler(CalloutHandle& handle) {
StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
static_cast<int64_t>(0));
StatsMgr::instance().setValue(
StatsMgr::generateName("subnet", sub->getID(), "registered-nas"),
static_cast<int64_t>(0));
for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
const std::string& name_anas(StatsMgr::generateName("subnet", sub->getID(),
StatsMgr::generateName("pool", pool->getID(),

View File

@ -1,4 +1,4 @@
// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2021-2025 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
@ -89,8 +89,8 @@ point names. This library has several such functions: @ref lease4_renew,
@ref lease4_expire, @ref lease4_recover, @ref leases4_committed,
@ref lease4_release, @ref lease4_decline, @ref lease6_renew,
@ref lease6_rebind, @ref lease6_expire, @ref lease6_recover,
@ref leases6_committed, @ref lease6_release, @ref lease6_decline located
in run_script_callouts.cc.
@ref leases6_committed, @ref lease6_release, @ref lease6_decline,
@ref addr6_register located in run_script_callouts.cc.
Each hook point extracts the Kea internal data and exports it as string
environment variables. These parameters are shared with the target script
@ -160,6 +160,10 @@ lease6_decline () {
...
}
addr6_register() {
...
}
case "$1" in
"lease4_renew")
lease4_renew
@ -200,6 +204,9 @@ case "$1" in
"lease6_decline")
lease6_decline
;;
"addr6_register")
addr6_register
;;
*)
unknown_handle "${@}"
;;
@ -666,6 +673,52 @@ LEASE6_TYPE
@endcode
addr6_register
@code
QUERY6_TYPE
QUERY6_TXID
QUERY6_LOCAL_ADDR
QUERY6_LOCAL_PORT
QUERY6_REMOTE_ADDR
QUERY6_REMOTE_PORT
QUERY6_IFACE_INDEX
QUERY6_IFACE_NAME
QUERY6_REMOTE_HWADDR
QUERY6_REMOTE_HWADDR_TYPE
QUERY6_PROTO
QUERY6_CLIENT_ID
ADDRESS6
OLD_LEASE6_ADDRESS
OLD_LEASE6_CLTT
OLD_LEASE6_HOSTNAME
OLD_LEASE6_HWADDR
OLD_LEASE6_HWADDR_TYPE
OLD_LEASE6_STATE
OLD_LEASE6_SUBNET_ID
OLD_LEASE6_VALID_LIFETIME
OLD_LEASE6_DUID
OLD_LEASE6_IAID
OLD_LEASE6_PREFERRED_LIFETIME
OLD_LEASE6_PREFIX_LEN
OLD_LEASE6_TYPE
NEW_LEASE6_ADDRESS
NEW_LEASE6_CLTT
NEW_LEASE6_HOSTNAME
NEW_LEASE6_HWADDR
NEW_LEASE6_HWADDR_TYPE
NEW_LEASE6_STATE
NEW_LEASE6_SUBNET_ID
NEW_LEASE6_VALID_LIFETIME
NEW_LEASE6_DUID
NEW_LEASE6_IAID
NEW_LEASE6_PREFERRED_LIFETIME
NEW_LEASE6_PREFIX_LEN
NEW_LEASE6_TYPE
@endcode
The leases4_committed hook point needs for loops to handle the list of addresses.
This can be achived in the following way:

View File

@ -1,4 +1,4 @@
// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2021-2025 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
@ -6,6 +6,7 @@
#include <config.h>
#include <asiolink/io_address.h>
#include <asiolink/io_service_mgr.h>
#include <cc/command_interpreter.h>
#include <hooks/hooks.h>
@ -408,6 +409,36 @@ int lease6_decline(CalloutHandle& handle) {
return (0);
}
/// @brief handle @ref addr6_register hook and set environment parameters for
/// the script.
/// IN: query6 address6 old_lease6 new_lease6
/// OUT: next_step
int addr6_register(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP ||
status == CalloutHandle::NEXT_STEP_SKIP) {
return (0);
}
ProcessEnvVars vars;
Pkt6Ptr pkt6;
handle.getArgument("query6", pkt6);
RunScriptImpl::extractPkt6(vars, pkt6, "QUERY6");
IOAddress addr = IOAddress::IPV6_ZERO_ADDRESS();
handle.getArgument("address6", addr);
RunScriptImpl::extractString(vars, addr.toText(), "ADDRESS6");
Lease6Ptr lease6;
handle.getArgument("old_lease6", lease6);
if (lease6) {
RunScriptImpl::extractLease6(vars, lease6, "OLD_LEASE6");
}
handle.getArgument("new_lease6", lease6);
RunScriptImpl::extractLease6(vars, lease6, "NEW_LEASE6");
ProcessArgs args;
args.push_back("addr6_register");
impl->runScript(args, vars);
return (0);
}
/// @brief This function is called to retrieve the multi-threading compatibility.
///
/// @return 1 which means compatible with multi-threading.

View File

@ -246,8 +246,8 @@ enum DHCPv6MessageType {
DHCPV6_DISCONNECT = 33,
DHCPV6_STATE = 34,
DHCPV6_CONTACT = 35,
DHCPV6_ADD_REG_INFORM = 36,
DHCPV6_ADD_REG_REPLY = 37,
DHCPV6_ADDR_REG_INFORM = 36,
DHCPV6_ADDR_REG_REPLY = 37,
DHCPV6_TYPES_EOF
};

View File

@ -488,8 +488,8 @@ Pkt6::unpackUDP() {
case DHCPV6_INFORMATION_REQUEST:
case DHCPV6_DHCPV4_QUERY:
case DHCPV6_DHCPV4_RESPONSE:
case DHCPV6_ADD_REG_INFORM:
case DHCPV6_ADD_REG_REPLY:
case DHCPV6_ADDR_REG_INFORM:
case DHCPV6_ADDR_REG_REPLY:
default: // assume that unknown messages are not using relay format
{
return (unpackMsg(data_.begin(), data_.end()));
@ -801,8 +801,8 @@ Pkt6::getName(const uint8_t type) {
static const char* SOLICIT = "SOLICIT";
static const char* DHCPV4_QUERY = "DHCPV4_QUERY";
static const char* DHCPV4_RESPONSE = "DHCPV4_RESPONSE";
static const char* ADD_REG_INFORM = "ADD_REG_INFORM";
static const char* ADD_REG_REPLY = "ADD_REG_REPLY";
static const char* ADDR_REG_INFORM = "ADDR_REG_INFORM";
static const char* ADDR_REG_REPLY = "ADDR_REG_REPLY";
static const char* UNKNOWN = "UNKNOWN";
switch (type) {
@ -863,11 +863,11 @@ Pkt6::getName(const uint8_t type) {
case DHCPV6_DHCPV4_RESPONSE:
return (DHCPV4_RESPONSE);
case DHCPV6_ADD_REG_INFORM:
return (ADD_REG_INFORM);
case DHCPV6_ADDR_REG_INFORM:
return (ADDR_REG_INFORM);
case DHCPV6_ADD_REG_REPLY:
return (ADD_REG_REPLY);
case DHCPV6_ADDR_REG_REPLY:
return (ADDR_REG_REPLY);
default:
;

View File

@ -682,12 +682,12 @@ TEST_F(Pkt6Test, getName) {
EXPECT_STREQ("SOLICIT", Pkt6::getName(type));
break;
case DHCPV6_ADD_REG_INFORM:
EXPECT_STREQ("ADD_REG_INFORM", Pkt6::getName(type));
case DHCPV6_ADDR_REG_INFORM:
EXPECT_STREQ("ADDR_REG_INFORM", Pkt6::getName(type));
break;
case DHCPV6_ADD_REG_REPLY:
EXPECT_STREQ("ADD_REG_REPLY", Pkt6::getName(type));
case DHCPV6_ADDR_REG_REPLY:
EXPECT_STREQ("ADDR_REG_REPLY", Pkt6::getName(type));
break;
default:

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2025 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
@ -904,7 +904,8 @@ AllocEngine::allocateBestMatch(ClientContext6& ctx,
.arg(hint.toText());
}
} else if (usable_hint_lease->expired()) {
} else if (usable_hint_lease->expired() &&
(usable_hint_lease->state_ != Lease::STATE_REGISTERED)) {
// If the lease is expired, we may likely reuse it, but...
ConstHostCollection hosts;
@ -1103,7 +1104,8 @@ AllocEngine::allocateBestMatch(ClientContext6& ctx,
// Although the address was free just microseconds ago, it may have
// been taken just now. If the lease insertion fails, we continue
// allocation attempts.
} else if (existing->expired()) {
} else if (existing->expired() &&
(existing->state_ != Lease::STATE_REGISTERED)) {
// Make sure it's not reserved.
if (!check_reservation_first && in_subnet && !out_of_pool) {
auto hosts = getIPv6Resrv(subnet->getID(), candidate);
@ -1733,6 +1735,10 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
isc_throw(BadValue, "Attempt to recycle lease that is still valid");
}
if (expired->state_ == Lease::STATE_REGISTERED) {
isc_throw(BadValue, "Attempt to recycle registered address");
}
if (expired->type_ != Lease::TYPE_PD) {
prefix_len = 128; // non-PD lease types must be always /128
}
@ -2903,6 +2909,12 @@ AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease,
// identifying information anymore. So we'll flag it for
// removal unless the hook has set the skip flag.
remove_lease = reclaimDeclined(lease);
} else if (lease->state_ == Lease::STATE_REGISTERED) {
if (reclaim_mode == DB_RECLAIM_LEAVE_UNCHANGED) {
isc_throw(Unexpected, "attempt to reuse a registered lease");
}
// Remove (vs reclaim) expired registered leases.
remove_lease = true;
}
if (reclaim_mode != DB_RECLAIM_LEAVE_UNCHANGED) {
@ -2931,8 +2943,13 @@ AllocEngine::reclaimExpiredLease(const Lease6Ptr& lease,
return;
}
// Decrease number of assigned leases.
if (lease->type_ == Lease::TYPE_NA) {
// Decrease number of registered or assigned leases.
if (lease->state_ == Lease::STATE_REGISTERED) {
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
lease->subnet_id_,
"registered-nas"),
static_cast<int64_t>(-1));
} else if (lease->type_ == Lease::TYPE_NA) {
// IA_NA
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
lease->subnet_id_,

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2025 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
@ -427,6 +427,12 @@ CfgSubnets6::removeStatistics() {
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
"reclaimed-leases"));
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
"cumulative-registered-nas"));
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
"registered-nas"));
for (auto const& pool : subnet6->getPools(Lease::TYPE_NA)) {
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
StatsMgr::generateName("pool", pool->getID(),
@ -514,6 +520,13 @@ CfgSubnets6::updateStatistics() {
stats_mgr.setValue(name_ia_pd_reuses, int64_t(0));
}
string const& name_registered(StatsMgr::generateName("subnet", subnet_id,
"cumulative-registered-nas"));
if (!stats_mgr.getObservation(name_registered)) {
stats_mgr.setValue(name_registered, static_cast<int64_t>(0));
}
for (auto const& pool : subnet6->getPools(Lease::TYPE_NA)) {
const std::string& name_total_nas(StatsMgr::generateName("subnet", subnet_id,
StatsMgr::generateName("pool", pool->getID(),

View File

@ -127,6 +127,11 @@ Lease::stateDeclined() const {
return (state_ == STATE_DECLINED);
}
bool
Lease::stateRegistered() const {
return (state_ == STATE_REGISTERED);
}
int64_t
Lease::getExpirationTime() const {
return (static_cast<int64_t>(cltt_) + valid_lft_);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2013-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013-2025 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
@ -215,6 +215,11 @@ struct Lease : public isc::data::UserContext, public isc::data::CfgToElement {
/// @return true if the lease is in the "declined" state, false otherwise.
bool stateDeclined() const;
/// @brief Indicates if the lease is in the "registered" state.
///
/// @return true if the lease is in the "registered" state, false otherwise.
bool stateRegistered() const;
/// @brief Returns true if the other lease has equal FQDN data.
///
/// The comparison of the hostname is case insensitive.

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2025 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
@ -292,7 +292,8 @@ LeaseMgr::recountLeaseStats6() {
// Zero out the global stats.
// Cumulative counters ("reclaimed-declined-addresses", "reclaimed-leases",
// "cumulative-assigned-nas", "cumulative-assigned-pds") never get zeroed.
// "cumulative-assigned-nas", "cumulative-assigned-pds",
// "cumulative-registered-nas")) never get zeroed.
int64_t zero = 0;
stats_mgr.setValue("declined-addresses", zero);
@ -314,6 +315,11 @@ LeaseMgr::recountLeaseStats6() {
stats_mgr.setValue("cumulative-assigned-pds", zero);
}
// Create if it does not exit cumulative registered nas global stats.
if (!stats_mgr.getObservation("cumulative-registered-nas")) {
stats_mgr.setValue("cumulative-registered-nas", zero);
}
// Clear subnet level stats. This ensures we don't end up with corner
// cases that leave stale values in place.
const Subnet6Collection* subnets =
@ -351,6 +357,15 @@ LeaseMgr::recountLeaseStats6() {
zero);
}
if (!stats_mgr.getObservation(
StatsMgr::generateName("subnet", subnet_id,
"registered-nas"))) {
stats_mgr.setValue(
StatsMgr::generateName("subnet", subnet_id,
"registered-nas"),
zero);
}
for (auto const& pool : subnet->getPools(Lease::TYPE_NA)) {
const std::string& name_anas(StatsMgr::generateName("subnet", subnet_id,
StatsMgr::generateName("pool", pool->getID(),
@ -423,6 +438,11 @@ LeaseMgr::recountLeaseStats6() {
stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_,
"assigned-nas"),
row.state_count_);
} else if (row.lease_state_ == Lease::STATE_REGISTERED) {
// Add to subnet level value
stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_,
"registered-nas"),
row.state_count_);
}
break;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2025 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
@ -681,10 +681,12 @@ public:
/// - assigned-nas
/// - declined-addresses
/// - assigned-pds
/// - registered
/// global:
/// - assigned-nas
/// - declined-addresses
/// - assigned-pds
/// - registered
///
/// It invokes the virtual method, startLeaseStatsQuery6(), which
/// returns an instance of an LeaseStatsQuery. The query contains