// Copyright (C) 2018-2023 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 // file, You can obtain one at http://mozilla.org/MPL/2.0/. /** @page libdhcp_stat_cmds Kea Stat Commands Hooks Library @section libdhcp_stat_cmdsIntro Introduction Welcome to Kea Stat Commands Hooks Library. This documentation is addressed to developers who are interested in the internal operation of the Stat Commands library. This file provides information needed to understand and perhaps extend this library. This documentation is stand-alone: you should have read and understood the Kea Developer's Guide and in particular its section about hooks. @section stat_cmds Stat Commands Overview Stat Commands (or stat_cmds) is a Hook library that can be loaded by either kea-dhcp4 and kea-dhcp6 servers to extend them with additional statistics mechanisms. The initial purpose of this library is provide supplemental commands for obtaining accurate lease statistics in deployments that share lease storage between multiple Kea DHCP servers. It is likely that additional statistics related commands will be added to this library in future releases as use cases for them arise. The library is structured around command handlers. When the library is loaded it registers handlers for new commands. When a command is issued (be it directly via control channel or indirectly via REST interface from control agent), the code receives a JSON command with parameters. The command is routed the appropriate handler, its parameters are parsed and command executed accordingly. Lastly, a response is constructed and shipped back to the client. This lease statistics commands interact with both the isc::dhcp::StatsMgr and the isc::dhcp::LeaseMgr instance. At the time of writing this text (May, 2018), Kea supports four types of lease managers: memfile, MySQL or PostgreSQL. The lease statistics commands provided by this library provide a unified interface supported by all four of these backends. As with other hooks, this one keeps its code in a separate namespace which corresponds to the file name of the library: isc::stat_cmds. For background on the design and design choices please refer to: Shared Lease Stats Design @section stat_cmdsCode Stat Commands Code Overview Library operation starts with Kea calling the load() function (file stat_cmds_callouts.cc). This function registers the command callout functions for each of the libraries commands. For a list, see @ref isc::stat_cmds::StatCmds class documentation. This class uses the Pimpl design pattern, and thus the actual implementation is hidden in @ref isc::stat_cmds::LeaseStatCmdsImpl. Unlike similar libraries, the Pimpl class is differentiated from the the StatCmds class by the prefix "Lease" and it is instantiated in the outer handler (e.g. @ref isc::stat_cmds::StatCmds::statLease4GetHandler) rather than the StatCmds constructor. This was done in the event that commands, unrelated to lease statistics, are added to this library and that would be better served by Pimpl derivations specific to them. @subsection stat_cmdsLeaseStatCode Lease Stat Commands Code Overview There are two shared lease statistic commands, "stat-lease4-get" and "stat-lease6-get". Both of these support the same input parameters and have their own command handlers: - @ref isc::stat_cmds::LeaseStatCmdsImpl::statLease4GetHandler (stat-lease4-get) - @ref isc::stat_cmds::LeaseStatCmdsImpl::statLease6GetHandler (stat-lease6-get) Briefly, the commands are intended to fetch the lease statistics per subnet for the range of subnets described by the input parameters. JSON text structure of the commands is as follows: DHCPv4 command: @code { "command": "stat-lease4-get", "arguments": { "subnet-id": x "subnet-range": { "first-subnet-id": x, "last-subnet-id": y } } } where subnet-id and subnet-range are optional and mutually exclusive @endcode DHCPv6 command: @code { "command": "stat-lease6-get", "arguments": { "subnet-id": x "subnet-range": { "first-subnet-id": x, "last-subnet-id": y } } } where subnet-id and subnet-range are optional and mutually exclusive @endcode Command handling for both commands is symmetrical consists of the following steps: -# The input parameters (if any) are parsed. Invalid values or combinations if detected result in generating a CONTROL_RESULT_ERROR response to the client. (See @ref isc::stat_cmds::LeaseStatCmdsImpl::getParameters and @ref isc::stat_cmds::LeaseStatCmdsImpl::Parameters) -# The parameters are used to identify the range of configured subnets to include in the response. This is done by querying subnet configuration housed by @ref isc::dhcp::CfgMgr. If the range contains no known subnets then a CONTROL_RESULT_EMPTY response is sent back to the client. -# The initial result-set response is constructed. Essentially this is an @ref isc::data::Element tree, which converted to JSON would appear as follows: @code "result-set": { "timestamp": "2018-03-22 09:43:30.815371", "columns": [", , ... ], "rows": [] } @endcode -# The actual lease statistics are then retrieved from @ref isc::dhcp::LeaseMgr instance by invoking of the three functions based on the input parameters: DHCPv4 functions: - @ref isc::dhcp::LeaseMgr::startLeaseStatsQuery4 - @ref isc::dhcp::LeaseMgr::startSubnetLeaseStatsQuery4 - @ref isc::dhcp::LeaseMgr::startSubnetRangeLeaseStatsQuery4 DHCPv6 functions: - @ref isc::dhcp::LeaseMgr::startLeaseStatsQuery6 - @ref isc::dhcp::LeaseMgr::startSubnetLeaseStatsQuery6 - @ref isc::dhcp::LeaseMgr::startSubnetRangeLeaseStatsQuery6 -# Iterate over the range of qualifying subnets adding a row of statistics for each subnet to the result-set. Each row combines the subnet total(s) from isc::dhcp::StatsMgr with the type and state counts from the lease query results. For subnets with no query data (i.e. no leases), their rows have non-zero values for totals only. -# Finally, a CONTROL_RESULT_SUCCESS response is generated containing the populated result-set. A DHCPv4 response might look like this: @code { "result-set\": { "columns\": [ "subnet-id", "total-addresses", "cumulative-assigned-addresses", "assigned-addresses", "declined-addresses" ], "rows\": [ [ 30, 256, 300, 100, 2 ], [ 40, 16, 5, 0, 0 ], [ 50, 256, 100, 35, 0 ] ], timestamp\": \"2018-05-04 15:03:37.000000\" } } @endcode and DHCPv6 response might look like this: @code { "result-set": { "columns": [ "subnet-id", "total-nas", "cumulative-assigned-nas", "assigned-nas", "declined-addresses", "total-pds", "cumulative-assigned-pds", "assigned-pds" ], "rows": [ [ 30, 16, 20, 6, 0, 65536, 1000, 400 ], [ 40, 16777216, 1100000, 989837, 0, 0, 0, 0 ] ], "timestamp": "2018-05-04 15:03:37.000000" } } @endcode @section stat_cmdsMTCompatibility Multi-Threading Compatibility The Stat Commands Hook library is compatible with multi-threading. All commands are executed inside a critical section, i.e. with threads stopped. It makes sense to not have lease state changes when retrieving lease counts. */