summaryrefslogtreecommitdiffstats
path: root/doc/sphinx/arm
diff options
context:
space:
mode:
Diffstat (limited to 'doc/sphinx/arm')
-rw-r--r--doc/sphinx/arm/acknowledgments.rst29
-rw-r--r--doc/sphinx/arm/admin.rst678
-rw-r--r--doc/sphinx/arm/agent.rst314
-rw-r--r--doc/sphinx/arm/classify.rst1265
-rw-r--r--doc/sphinx/arm/config-backend.rst327
-rw-r--r--doc/sphinx/arm/config-templates.rst74
-rw-r--r--doc/sphinx/arm/config.rst339
-rw-r--r--doc/sphinx/arm/congestion-handling.rst129
-rw-r--r--doc/sphinx/arm/ctrl-channel.rst906
-rw-r--r--doc/sphinx/arm/database-connectivity.rst104
-rw-r--r--doc/sphinx/arm/ddns.rst1027
-rw-r--r--doc/sphinx/arm/dhcp4-srv.rst8455
-rw-r--r--doc/sphinx/arm/dhcp6-srv.rst8184
-rw-r--r--doc/sphinx/arm/ext-gss-tsig.rst1303
-rw-r--r--doc/sphinx/arm/ext-netconf.rst1159
-rw-r--r--doc/sphinx/arm/ext-radius.rst559
-rw-r--r--doc/sphinx/arm/hammer.rst137
-rw-r--r--doc/sphinx/arm/hooks-bootp.rst91
-rw-r--r--doc/sphinx/arm/hooks-cb-cmds.rst2248
-rw-r--r--doc/sphinx/arm/hooks-cb-mysql.rst18
-rw-r--r--doc/sphinx/arm/hooks-cb-pgsql.rst18
-rw-r--r--doc/sphinx/arm/hooks-class-cmds.rst255
-rw-r--r--doc/sphinx/arm/hooks-ddns-tuning.rst217
-rw-r--r--doc/sphinx/arm/hooks-flex-id.rst286
-rw-r--r--doc/sphinx/arm/hooks-flex-option.rst196
-rw-r--r--doc/sphinx/arm/hooks-gss-tsig.rst15
-rw-r--r--doc/sphinx/arm/hooks-ha.rst2662
-rw-r--r--doc/sphinx/arm/hooks-host-cache.rst324
-rw-r--r--doc/sphinx/arm/hooks-host-cmds.rst1212
-rw-r--r--doc/sphinx/arm/hooks-lease-cmds.rst1073
-rw-r--r--doc/sphinx/arm/hooks-lease-query.rst675
-rw-r--r--doc/sphinx/arm/hooks-legal-log.rst1094
-rw-r--r--doc/sphinx/arm/hooks-limits.rst211
-rw-r--r--doc/sphinx/arm/hooks-perfmon.rst39
-rw-r--r--doc/sphinx/arm/hooks-ping-check.rst169
-rw-r--r--doc/sphinx/arm/hooks-radius.rst16
-rw-r--r--doc/sphinx/arm/hooks-rbac.rst587
-rw-r--r--doc/sphinx/arm/hooks-run-script.rst626
-rw-r--r--doc/sphinx/arm/hooks-stat-cmds.rst252
-rw-r--r--doc/sphinx/arm/hooks-subnet-cmds.rst1326
-rw-r--r--doc/sphinx/arm/hooks-user-chk.rst83
-rw-r--r--doc/sphinx/arm/hooks.rst626
-rw-r--r--doc/sphinx/arm/install.rst633
-rw-r--r--doc/sphinx/arm/integrations.rst11
-rw-r--r--doc/sphinx/arm/intro.rst64
-rw-r--r--doc/sphinx/arm/keactrl.rst364
-rw-r--r--doc/sphinx/arm/lease-expiration.rst328
-rw-r--r--doc/sphinx/arm/lfc.rst73
-rw-r--r--doc/sphinx/arm/logging.rst1077
-rw-r--r--doc/sphinx/arm/quickstart.rst382
-rw-r--r--doc/sphinx/arm/rst_arm_sources.mk54
-rw-r--r--doc/sphinx/arm/security.rst445
-rw-r--r--doc/sphinx/arm/shell.rst165
-rw-r--r--doc/sphinx/arm/stats.rst1043
-rw-r--r--doc/sphinx/arm/stork.rst50
55 files changed, 43997 insertions, 0 deletions
diff --git a/doc/sphinx/arm/acknowledgments.rst b/doc/sphinx/arm/acknowledgments.rst
new file mode 100644
index 0000000..0df58dd
--- /dev/null
+++ b/doc/sphinx/arm/acknowledgments.rst
@@ -0,0 +1,29 @@
+Acknowledgments
+===============
+
+Kea is an open source project designed, developed, and maintained by
+Internet Systems Consortium, Inc, a 501(c)3 non-profit organization. ISC
+is primarily funded by revenues from support subscriptions for our open
+source, and we encourage all professional users to consider this option.
+To learn more, see \ https://www.isc.org/support/.
+
+We thank all the organizations and individuals who have helped to make
+Kea possible. `Comcast <https://www.comcast.com/>`__ and the Comcast
+Innovation Fund provided major support for the development of Kea's
+DHCPv4, DHCPv6, and DDNS modules. Mozilla funded initial work on the
+RESTful API via a MOSS award.
+
+Kea was initially implemented as a collection of applications within the
+BIND 10 framework. We thank the founding sponsors of the BIND 10
+project: `Afilias <https://www.afilias.info/>`__,
+`IIS.SE <https://www.iis.se/>`__,
+`Nominet <https://www.nominet.uk/>`__,
+`SIDN <https://www.sidn.nl/>`__, `JPRS <https://jprs.co.jp/>`__,
+and `CIRA <https://cira.ca/>`__; and additional sponsors
+`AFNIC <https://www.afnic.fr/>`__,
+`CNNIC <https://www.cnnic.net.cn/>`__, `CZ.NIC <https://www.nic.cz/>`__,
+`DENIC eG <https://www.denic.de/>`__,
+`Google <https://www.google.com/>`__, `RIPE
+NCC <https://www.ripe.net/>`__, `Registro.br <https://registro.br/>`__,
+`.nz Registry Services <https://nzrs.net.nz/>`__, and `Technical Center
+of Internet <https://www.tcinet.ru/>`__.
diff --git a/doc/sphinx/arm/admin.rst b/doc/sphinx/arm/admin.rst
new file mode 100644
index 0000000..aac1b81
--- /dev/null
+++ b/doc/sphinx/arm/admin.rst
@@ -0,0 +1,678 @@
+.. _admin:
+
+***************************
+Kea Database Administration
+***************************
+
+.. _kea-database-version:
+
+Databases and Schema Versions
+=============================
+
+Kea may be configured to use a database as storage for leases or as a
+source of servers' configurations and host reservations (i.e. static
+assignments of addresses, prefixes, options, etc.). As Kea is
+updated, new database schemas are introduced to facilitate new
+features and correct discovered issues with the existing schemas.
+
+Each version of Kea expects a particular schema structure and checks for this by
+examining the version of the database it is using. Separate version numbers are
+maintained for the schemas, independent of the version of Kea itself. It is
+possible that the schema version will stay the same through several Kea
+revisions; similarly, it is possible that the version of the schema may go up
+several revisions during a single Kea version upgrade. Versions for each backend
+type are also independent, so an increment in the MySQL backend version does not
+imply an increment in that of PostgreSQL.
+
+Schema versions are specified in a major.minor format. For the most recent
+versions, the minor version is always zero and only the major version is
+incremented.
+
+Historically, the minor version used to be incremented when backward-compatible
+changes were introduced to the schema: for example - when a new index is added.
+This was opposed to incrementing the major version which implied an incompatible
+schema change: for example - changing the type of an existing column. If Kea
+attempts to run on a schema that is too old, as indicated by a mismatched schema
+version, it will fail; administrative action is required to upgrade the schema.
+
+.. _kea-admin:
+
+The :iscman:`kea-admin` Tool
+============================
+
+To manage the databases, Kea provides the :iscman:`kea-admin` tool. It can
+initialize a new backend, check its version number, perform a backend
+upgrade, and dump lease data to a text file.
+
+:iscman:`kea-admin` takes two mandatory parameters: ``command`` and
+``backend``. Additional, non-mandatory options may be specified. The
+currently supported commands are:
+
+- ``db-init`` — initializes a new database schema. This is useful
+ during a new Kea installation. The database is initialized to the
+ latest version supported by the version of the software being installed.
+ Called automatically on startup or reconfiguration of Kea DHCP servers if
+ required.
+
+- ``db-version`` — reports the database backend version number. This
+ is not necessarily equal to the Kea version number, as each backend
+ has its own versioning scheme.
+
+- ``db-upgrade`` — conducts a database schema upgrade. This is
+ useful when upgrading Kea.
+
+- ``lease-dump`` — dumps the contents of the lease database (for MySQL or
+ PostgreSQL backends) to a CSV (comma-separated values) text file.
+
+ The first line of the file contains the column names. This can be used
+ as a way to switch from a database backend to a memfile backend.
+ Alternatively, it can be used as a diagnostic tool, so it provides a portable
+ form of the lease data.
+
+- ``lease-upload`` — uploads leases from a CSV (comma-separated values) text
+ file to a MySQL or a PostgreSQL lease database. The CSV file needs to be in
+ memfile format.
+
+``backend`` specifies the type of backend database. The currently
+supported types are:
+
+- ``memfile`` — lease information is stored on disk in a text file.
+
+- ``mysql`` — information is stored in a MySQL relational database.
+
+- ``pgsql`` — information is stored in a PostgreSQL relational
+ database.
+
+Additional parameters may be needed, depending on the setup and
+specific operation: username, password, and database name or the
+directory where specific files are located. See the appropriate manual
+page for details (``man 8 kea-admin``).
+
+.. _supported-databases:
+
+Supported Backends
+==================
+
+The following table presents the capabilities of available backends.
+Please refer to the specific sections dedicated to each backend to
+better understand their capabilities and limitations. Choosing the right
+backend is essential for the success of the deployment.
+
+.. table:: List of available backends
+
+ +---------------+----------------+----------------+---------------+
+ | Feature | Memfile | MySQL | PostgreSQL |
+ | | | | |
+ +===============+================+================+===============+
+ | Status | Stable | Stable | Stable |
+ | | | | |
+ +---------------+----------------+----------------+---------------+
+ | Data format | CSV file | SQL RMDB | SQL RMDB |
+ | | | | |
+ | | | | |
+ +---------------+----------------+----------------+---------------+
+ | Leases | yes | yes | yes |
+ +---------------+----------------+----------------+---------------+
+ | Host | no | yes | yes |
+ | reservations | | | |
+ | | | | |
+ +---------------+----------------+----------------+---------------+
+ | Options | no | yes | yes |
+ | defined on | | | |
+ | per host | | | |
+ | basis | | | |
+ +---------------+----------------+----------------+---------------+
+ | Configuration | no | yes | yes |
+ | backend | | | |
+ | | | | |
+ +---------------+----------------+----------------+---------------+
+
+Memfile
+-------
+
+The memfile backend is able to store lease information, but cannot
+store host reservation details; these must be stored in the
+configuration file. (There are no plans to add a host reservations
+storage capability to this backend.)
+
+No special initialization steps are necessary for the memfile backend.
+During the first run, both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` create
+an empty lease file if one is not present. Necessary disk-write
+permission is required.
+
+.. _memfile-upgrade:
+
+Upgrading Memfile Lease Files From an Earlier Version of Kea
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are no special steps required to upgrade memfile lease files
+between versions of Kea. During startup, the
+servers check the schema version of the lease files against their
+own. If there is a mismatch, the servers automatically launch the
+LFC process to convert the files to the server's schema version. While
+this mechanism is primarily meant to ease the process of upgrading to
+newer versions of Kea, it can also be used for downgrading should the
+need arise. When upgrading, any values not present in the original lease
+files are assigned appropriate default values. When downgrading, any
+data present in the files but not in the server's schema are
+dropped. To convert the files manually prior to starting the
+servers, run the lease file cleanup (LFC) process. See :ref:`kea-lfc` for more information.
+
+.. _mysql-database:
+
+MySQL
+-----
+
+MySQL is able to store leases, host reservations, options defined on a
+per-host basis, and a subset of the server configuration parameters
+(serving as a configuration backend).
+
+.. _mysql-database-engine:
+
+MySQL 5.7 vs MySQL 8 vs MariaDB 10 and 11
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In our Kea performance testing, MySQL 8 shows a 60-90% drop in speed
+in comparison with MySQL 5.7.
+Due to the upcoming MySQL 5.7 EOL, we recommend using MariaDB instead of MySQL 8.
+
+MySQL 5.7, MySQL 8, MariaDB 10, and MariaDB 11 are fully compatible,
+interchangeable, and tested with Kea.
+
+.. _mysql-database-create:
+
+First-Time Creation of the MySQL Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before preparing any Kea-specific database and tables, the MySQL database
+must be configured to use the system timezone. It is recommended to use UTC
+as the timezone for both the system and the MySQL database.
+
+To check the system timezone:
+
+ .. code-block:: console
+
+ date +%Z
+
+To check the MySQL timezone:
+
+ .. code-block:: mysql
+
+ mysql> SELECT @@system_time_zone;
+ mysql> SELECT @@global.time_zone;
+ mysql> SELECT @@session.time_zone;
+
+To configure the MySQL timezone for a specific server, please refer to the
+installed version documentation.
+
+Usually the setting is configured in the [mysqld] section in ``/etc/mysql/my.cnf``,
+``/etc/mysql/mysql.cnf``, ``/etc/mysql/mysqld.cnf``, or
+``/etc/mysql/mysql.conf.d/mysqld.cnf``.
+
+ .. code-block:: ini
+
+ [mysqld]
+ # using default-time-zone
+ default-time-zone='+00:00'
+
+ # or using timezone
+ timezone='UTC'
+
+When setting up the MySQL database for the first time, the
+database area must be created within MySQL, and the MySQL user ID under
+which Kea will access the database must be set up. This needs to be done manually,
+rather than via :iscman:`kea-admin`.
+
+To create the database:
+
+1. Log into MySQL as "root":
+
+ .. code-block:: console
+
+ $ mysql -u root -p
+ Enter password:
+ mysql>
+
+2. Create the MySQL database:
+
+ .. code-block:: mysql
+
+ mysql> CREATE DATABASE database_name;
+
+ (``database_name`` is the name chosen for the database.)
+
+3. Create the user under which Kea will access the database (and give it
+ a password), then grant it access to the database tables:
+
+ .. code-block:: mysql
+
+ mysql> CREATE USER 'user-name'@'localhost' IDENTIFIED BY 'password';
+ mysql> GRANT ALL ON database-name.* TO 'user-name'@'localhost';
+
+ (``user-name`` and ``password`` are the user ID and password used to
+ allow Kea access to the MySQL instance. All apostrophes in the
+ command lines above are required.)
+
+4. Create the database.
+
+ Exit the MySQL client
+
+ .. code-block:: mysql
+
+ mysql> quit
+ Bye
+
+ Then use the :iscman:`kea-admin` tool to create the database.
+
+ .. code-block:: console
+
+ $ kea-admin db-init mysql -u database-user -p database-password -n database-name
+
+ While it is possible to create the database from within the MySQL client, we recommend
+ using the :iscman:`kea-admin` tool as it performs some necessary validations to ensure Kea can
+ access the database at runtime. Among those checks is verification that the schema does not contain
+ any pre-existing tables; any pre-existing tables must be removed
+ manually. An additional check examines the user's ability to create functions and
+ triggers. The following error indicates that the user does not have the necessary
+ permissions to create functions or triggers:
+
+ .. code-block:: console
+
+ ERROR 1419 (HY000) at line 1: You do not have the SUPER privilege and binary logging is
+ enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
+ ERROR/kea-admin: mysql_can_create cannot trigger, check user permissions, mysql status = 1
+ mysql: [Warning] Using a password on the command line interface can be insecure.
+ ERROR/kea-admin: Create failed, the user, keatest, has insufficient privileges.
+
+ The simplest way around this is to set the global MySQL variable,
+ ``log_bin_trust_function_creators``, to 1 via the MySQL client.
+ Note this must be done as a user with SUPER privileges:
+
+ .. code-block:: mysql
+
+ mysql> set @@global.log_bin_trust_function_creators = 1;
+ Query OK, 0 rows affected (0.00 sec)
+
+ To create the database with MySQL directly, follow these steps:
+
+ .. code-block:: mysql
+
+ mysql> CONNECT database-name;
+ mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_create.mysql
+
+ (where ``path-to-kea`` is the location where Kea is installed.)
+
+ The database may also be dropped manually as follows:
+
+ .. code-block:: mysql
+
+ mysql> CONNECT database-name;
+ mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_drop.mysql
+
+ (where ``path-to-kea`` is the location where Kea is installed.)
+
+.. warning::
+
+ Dropping the database results in the unrecoverable loss of any data it contains.
+
+
+5. Exit MySQL:
+
+ .. code-block:: mysql
+
+ mysql> quit
+ Bye
+
+If the tables were not created in Step 4, run the :iscman:`kea-admin` tool
+to create them now:
+
+.. code-block:: console
+
+ $ kea-admin db-init mysql -u database-user -p database-password -n database-name
+
+Do not do this if the tables were created in Step 4. :iscman:`kea-admin`
+implements rudimentary checks; it will refuse to initialize a database
+that contains any existing tables. To start from scratch,
+all data must be removed manually. (This process is a manual operation
+on purpose, to avoid accidentally irretrievable mistakes by :iscman:`kea-admin`.)
+
+.. _mysql-upgrade:
+
+Upgrading a MySQL Database From an Earlier Version of Kea
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes a new Kea version uses a newer database schema, so the
+existing database needs to be upgraded. This can be done using the
+``kea-admin db-upgrade`` command.
+
+To check the current version of the database, use the following command:
+
+.. code-block:: console
+
+ $ kea-admin db-version mysql -u database-user -p database-password -n database-name
+
+(See :ref:`kea-database-version`
+for a discussion about versioning.) If the version does not match the
+minimum required for the new version of Kea (as described in the release
+notes), the database needs to be upgraded.
+
+Before upgrading, please make sure that the database is backed up. The
+upgrade process does not discard any data, but depending on the nature
+of the changes, it may be impossible to subsequently downgrade to an
+earlier version.
+
+To perform an upgrade, issue the following command:
+
+.. code-block:: console
+
+ $ kea-admin db-upgrade mysql -u database-user -p database-password -n database-name
+
+.. note::
+
+ To search host reservations by hostname, it is critical that the collation of
+ the hostname column in the host table be case-insensitive. Fortunately, that
+ is the default in MySQL, but it can be verified via this command:
+
+ .. code-block:: mysql
+
+ mysql> SELECT COLLATION('');
+ +-----------------+
+ | COLLATION('') |
+ +-----------------+
+ | utf8_general_ci |
+ +-----------------+
+
+ According to mysql's naming convention, when the name ends in ``_ci``,
+ the collation is case-insensitive.
+
+.. _mysql-performance:
+
+Improved Performance With MySQL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Changing the MySQL internal value ``innodb_flush_log_at_trx_commit`` from the default value
+of 1 to 2 can result in a huge gain in Kea performance. In some deployments, the
+gain was over 1000% (10 times faster when set to 2, compared to the default value of 1).
+It can be set per-session for testing:
+
+.. code-block:: mysql
+
+ mysql> SET GLOBAL innodb_flush_log_at_trx_commit=2;
+ mysql> SHOW SESSION VARIABLES LIKE 'innodb_flush_log%';
+
+or permanently in ``/etc/mysql/my.cnf``:
+
+.. code-block:: ini
+
+ [mysqld]
+ innodb_flush_log_at_trx_commit=2
+
+Be aware that changing this value can cause problems during data recovery
+after a crash, so we recommend checking the `MySQL documentation
+<https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit>`__.
+With the default value of 1, MySQL writes changes to disk after every INSERT or UPDATE query
+(in Kea terms, every time a client gets a new lease or renews an existing lease). When
+``innodb_flush_log_at_trx_commit`` is set to 2, MySQL writes the changes at intervals
+no longer than 1 second. Batching writes gives a substantial performance boost. The trade-off,
+however, is that in the worst-case scenario, all changes in the last second before crash
+could be lost. Given the fact that Kea is stable software and crashes very rarely,
+most deployments find it a beneficial trade-off.
+
+.. _pgsql-database:
+
+PostgreSQL
+----------
+
+PostgreSQL can store leases, host reservations, and options
+defined on a per-host basis.
+
+.. _pgsql-database-create:
+
+First-Time Creation of the PostgreSQL Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before preparing any Kea-specific database and tables, the PostgreSQL database
+must be configured to use the system timezone. It is recommended to use UTC
+as the timezone for both the system and the PostgreSQL database.
+
+To check the system timezone:
+
+ .. code-block:: console
+
+ date +%Z
+
+To check the PostgreSQL timezone:
+
+ .. code-block:: psql
+
+ postgres=# show timezone;
+ postgres=# SELECT * FROM pg_timezone_names WHERE name = current_setting('TIMEZONE');
+
+To configure the PostgreSQL timezone for a specific server, please refer to the
+installed version documentation.
+
+Usually the setting is configured in the ``postgresql.conf`` with the varying
+version path ``/etc/postgresql/<version>/main/postgresql.conf``, but on some systems
+the files may be located in ``/var/lib/pgsql/data``.
+
+ .. code-block:: ini
+
+ timezone = 'UTC'
+
+The first task is to create both the database and the user under
+which the servers will access it. A number of steps are required:
+
+1. Log into PostgreSQL as "root":
+
+ .. code-block:: console
+
+ $ sudo -u postgres psql postgres
+ Enter password:
+ postgres=#
+
+2. Create the database:
+
+ .. code-block:: psql
+
+ postgres=# CREATE DATABASE database-name;
+ CREATE DATABASE
+ postgres=#
+
+ (``database-name`` is the name chosen for the database.)
+
+3. Create the user under which Kea will access the database (and give it
+ a password), then grant it access to the database:
+
+ .. code-block:: psql
+
+ postgres=# CREATE USER user-name WITH PASSWORD 'password';
+ CREATE ROLE
+ postgres=# GRANT ALL PRIVILEGES ON DATABASE database-name TO user-name;
+ GRANT
+ postgres=#
+
+4. Exit PostgreSQL:
+
+ .. code-block:: psql
+
+ postgres=# \q
+ Bye
+ $
+
+5. At this point, create the database tables either
+ using the :iscman:`kea-admin` tool, as explained in the next section
+ (recommended), or manually. To create the tables manually, enter the
+ following command. PostgreSQL will prompt the administrator to enter the
+ new user's password that was specified in Step 3. When the command
+ completes, Kea will return to the shell prompt. The
+ output should be similar to the following:
+
+ .. code-block:: console
+
+ $ psql -d database-name -U user-name -f path-to-kea/share/kea/scripts/pgsql/dhcpdb_create.pgsql
+ Password for user user-name:
+ CREATE TABLE
+ CREATE INDEX
+ CREATE INDEX
+ CREATE TABLE
+ CREATE INDEX
+ CREATE TABLE
+ START TRANSACTION
+ INSERT 0 1
+ INSERT 0 1
+ INSERT 0 1
+ COMMIT
+ CREATE TABLE
+ START TRANSACTION
+ INSERT 0 1
+ COMMIT
+ $
+
+ (``path-to-kea`` is the location where Kea is installed.)
+
+ If instead an error is encountered, such as:
+
+ ::
+
+ psql: FATAL: no pg_hba.conf entry for host "[local]", user "user-name", database "database-name", SSL off
+
+ ... the PostgreSQL configuration will need to be altered. Kea uses
+ password authentication when connecting to the database and must have
+ the appropriate entries added to PostgreSQL's pg_hba.conf file. This
+ file is normally located in the primary data directory for the
+ PostgreSQL server. The precise path may vary depending on the
+ operating system and version, but the default location for PostgreSQL is
+ ``/etc/postgresql/*/main/postgresql.conf``. However, on some systems, the
+ file may reside in ``/var/lib/pgsql/data``.
+
+ Assuming Kea is running on the same host as PostgreSQL, adding lines
+ similar to the following should be sufficient to provide
+ password-authenticated access to Kea's database:
+
+ ::
+
+ local database-name user-name password
+ host database-name user-name 127.0.0.1/32 password
+ host database-name user-name ::1/128 password
+
+ These edits are primarily intended as a starting point, and are not a
+ definitive reference on PostgreSQL administration or database
+ security. Please consult the PostgreSQL user manual before making
+ these changes, as they may expose other databases that are running. It
+ may be necessary to restart PostgreSQL for the changes to
+ take effect.
+
+Initialize the PostgreSQL Database Using :iscman:`kea-admin`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the tables were not created manually, do so now by
+running the :iscman:`kea-admin` tool:
+
+.. code-block:: console
+
+ $ kea-admin db-init pgsql -u database-user -p database-password -n database-name
+
+Do not do this if the tables were already created manually. :iscman:`kea-admin`
+implements rudimentary checks; it will refuse to initialize a database
+that contains any existing tables. To start from scratch,
+all data must be removed manually. (This process is a manual operation
+on purpose, to avoid accidentally irretrievable mistakes by :iscman:`kea-admin`.)
+
+.. _pgsql-upgrade:
+
+Upgrading a PostgreSQL Database From an Earlier Version of Kea
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The PostgreSQL database schema can be upgraded using the same tool and
+commands as described in :ref:`mysql-upgrade`, with the exception that the "pgsql"
+database backend type must be used in the commands.
+
+Use the following command to check the current schema version:
+
+.. code-block:: console
+
+ $ kea-admin db-version pgsql -u database-user -p database-password -n database-name
+
+Use the following command to perform an upgrade:
+
+.. code-block:: console
+
+ $ kea-admin db-upgrade pgsql -u database-user -p database-password -n database-name
+
+.. _pgsl-ssl:
+
+PostgreSQL without OpenSSL support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Usually the PostgreSQL database client library is built with the OpenSSL
+support but Kea can be configured to handle the case where it is not
+supported:
+
+.. code-block:: console
+
+ $ ./configure [other-options] --disable-pgsql-ssl
+
+.. _pgsql-performance:
+
+Improved Performance With PostgreSQL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Changing the PostgreSQL internal value ``synchronous_commit`` from the default value
+of ON to OFF can result in significant gains in Kea performance; on slow systems, the gain
+can be over 1000%. It can be set per-session for testing:
+
+.. code-block:: psql
+
+ postgres=# SET synchronous_commit = OFF;
+
+or permanently via command (preferred method):
+
+.. code-block:: psql
+
+ postgres=# ALTER SYSTEM SET synchronous_commit=OFF;
+
+or permanently in ``/etc/postgresql/[version]/main/postgresql.conf``:
+
+.. code-block:: ini
+
+ synchronous_commit = off
+
+Changing this value can cause problems during data recovery
+after a crash, so we recommend a careful read of the `PostgreSQL documentation
+<https://www.postgresql.org/docs/current/wal-async-commit.html>`__.
+With the default value of ON, PostgreSQL writes changes to disk after every INSERT or UPDATE query
+(in Kea terms, every time a client gets a new lease or renews an existing lease). When
+``synchronous_commit`` is set to OFF, PostgreSQL adds some delay before writing the changes.
+Batching writes gives a substantial performance boost,
+but in the worst-case scenario, all changes in the last moment before a crash
+could be lost. Since Kea is stable software and crashes very rarely,
+most deployments find the performance benefits outweigh the potential risks.
+
+Using Read-Only Databases With Host Reservations
+------------------------------------------------
+
+If a read-only database is used for storing host reservations, Kea must
+be explicitly configured to operate on the database in read-only mode.
+Sections :ref:`read-only-database-configuration4` and
+:ref:`read-only-database-configuration6` describe when such
+a configuration may be required, and how to configure Kea to operate in
+this way for both DHCPv4 and DHCPv6.
+
+Limitations Related to the Use of SQL Databases
+-----------------------------------------------
+
+Year 2038 Issue
+~~~~~~~~~~~~~~~
+
+The lease expiration time in Kea is stored in the SQL database for each lease
+as a timestamp value. Kea developers have observed that the MySQL database
+does not accept timestamps beyond 2147483647 seconds (the maximum signed
+32-bit number) from the beginning of the UNIX epoch (00:00:00 on 1
+January 1970). Some versions of PostgreSQL do accept greater values, but
+the value is altered when it is read back. For this reason, the lease
+database backends put a restriction on the maximum timestamp to be
+stored in the database, which is equal to the maximum signed 32-bit
+number. This effectively means that the current Kea version cannot store
+leases whose expiration time is later than 2147483647 seconds since the
+beginning of the epoch (around the year 2038). This will be fixed when
+database support for longer timestamps is available.
diff --git a/doc/sphinx/arm/agent.rst b/doc/sphinx/arm/agent.rst
new file mode 100644
index 0000000..328c03a
--- /dev/null
+++ b/doc/sphinx/arm/agent.rst
@@ -0,0 +1,314 @@
+.. _kea-ctrl-agent:
+
+*********************
+The Kea Control Agent
+*********************
+
+.. _agent-overview:
+
+Overview of the Kea Control Agent
+=================================
+
+The Kea Control Agent (CA) is a daemon which exposes a RESTful control
+interface for managing Kea servers. The daemon can receive control
+commands over HTTP and either forward these commands to the respective
+Kea servers or handle these commands on its own. The determination
+whether the command should be handled by the CA or forwarded is made by
+checking the value of the ``service`` parameter, which may be included in
+the command from the controlling client. The details of the supported
+commands, as well as their structures, are provided in
+:ref:`ctrl-channel`.
+
+The CA can use hook libraries to provide support for additional commands
+or to program custom behavior of existing commands. Such hook libraries must
+implement callouts for the ``control_command_receive`` hook point. Details
+about creating new hook libraries and supported hook points can be found
+in the `Kea Developer's
+Guide <https://reports.kea.isc.org/dev_guide/>`__.
+
+The CA processes received commands according to the following algorithm:
+
+- Pass command into any installed hooks (regardless of service
+ value(s)). If the command is handled by a hook, return the response.
+
+- If the service specifies one or more services, forward the command to
+ the specified services and return the accumulated responses.
+
+- If the service is not specified or is an empty list, handle the
+ command if the CA supports it.
+
+.. _agent-configuration:
+
+Configuration
+=============
+
+The following example demonstrates the basic CA configuration.
+
+.. code-block:: json
+
+ {
+ "Control-agent": {
+ "http-host": "10.20.30.40",
+ "http-port": 8000,
+ "trust-anchor": "/path/to/the/ca-cert.pem",
+ "cert-file": "/path/to/the/agent-cert.pem",
+ "key-file": "/path/to/the/agent-key.pem",
+ "cert-required": true,
+ "authentication": {
+ "type": "basic",
+ "realm": "kea-control-agent",
+ "clients": [
+ {
+ "user": "admin",
+ "password": "1234"
+ } ]
+ },
+
+ "control-sockets": {
+ "dhcp4": {
+ "comment": "main server",
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket-v4"
+ },
+ "dhcp6": {
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket-v6",
+ "user-context": { "version": 3 }
+ },
+ "d2": {
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket-d2"
+ }
+ },
+
+ "hooks-libraries": [
+ {
+ "library": "/opt/local/custom_hooks_example.so",
+ "parameters": {
+ "param1": "foo"
+ }
+ } ],
+
+ "loggers": [ {
+ "name": "kea-ctrl-agent",
+ "severity": "INFO"
+ } ]
+ }
+ }
+
+The ``http-host`` and ``http-port`` parameters specify an IP address and
+port to which HTTP service will be bound. In the example configuration
+provided above, the RESTful service will be available at the URL
+``https://10.20.30.40:8000/``. If these parameters are not specified, the
+default URL is ``http://127.0.0.1:8000/``.
+
+When using Kea's HA hook library with multi-threading,
+the address:port combination used for CA must be
+different from the HA peer URLs, which are strictly
+for internal HA traffic between the peers. User commands should
+still be sent via the CA.
+
+The ``trust-anchor``, ``cert-file``, ``key-file``, and ``cert-required``
+parameters specify the TLS setup for HTTP, i.e. HTTPS. If these parameters
+are not specified, HTTP is used. The TLS/HTTPS support in Kea is
+described in :ref:`tls`.
+
+As mentioned in :ref:`agent-overview`, the CA can forward
+received commands to the Kea servers for processing. For example,
+:isccmd:`config-get` is sent to retrieve the configuration of one of the Kea
+services. When the CA receives this command, including a ``service``
+parameter indicating that the client wishes to retrieve the
+configuration of the DHCPv4 server, the CA forwards the command to that
+server and passes the received response back to the client. More about
+the ``service`` parameter and the general structure of commands can be
+found in :ref:`ctrl-channel`.
+
+The CA uses UNIX domain sockets to forward control commands and receive
+responses from other Kea services. The ``dhcp4``, ``dhcp6``, and ``d2``
+maps specify the files to which UNIX domain sockets are bound. In the
+configuration above, the CA connects to the DHCPv4 server via
+``/path/to/the/unix/socket-v4`` to forward the commands to it.
+Obviously, the DHCPv4 server must be configured to listen to connections
+via this same socket. In other words, the command-socket configuration
+for the DHCPv4 server and the CA (for that server) must match. Consult
+:ref:`dhcp4-ctrl-channel`, :ref:`dhcp6-ctrl-channel`, and
+:ref:`d2-ctrl-channel` to learn how the socket configuration is
+specified for the DHCPv4, DHCPv6, and D2 services.
+
+User contexts can store arbitrary data as long as they are in valid JSON
+syntax and their top-level element is a map (i.e. the data must be
+enclosed in curly brackets). Some hook libraries may expect specific
+formatting; please consult the relevant hook library documentation for
+details.
+
+User contexts can be specified on either global scope, control socket,
+basic authentication, or loggers. One other useful feature is the
+ability to store comments or descriptions; the parser translates a
+"comment" entry into a user context with the entry, which allows a
+comment to be attached within the configuration itself.
+
+Basic HTTP authentication protects
+against unauthorized uses of the control agent by local users. For
+protection against remote attackers, HTTPS and reverse proxy of
+:ref:`agent-secure-connection` provide stronger security.
+
+The authentication is described in the ``authentication`` block
+with the mandatory ``type`` parameter, which selects the authentication.
+Currently only the basic HTTP authentication (type basic) is supported.
+
+The ``realm`` authentication parameter is used for error messages when
+the basic HTTP authentication is required but the client is not
+authorized.
+
+When the ``clients`` authentication list is configured and not empty,
+basic HTTP authentication is required. Each element of the list
+specifies a user ID and a password. The user ID is mandatory, must
+be not empty, and must not contain the colon (:) character. The
+password is optional; when it is not specified an empty password
+is used.
+
+.. note::
+
+ The basic HTTP authentication user ID and password are encoded
+ in UTF-8, but the current Kea JSON syntax only supports the Latin-1
+ (i.e. 0x00..0xff) Unicode subset.
+
+To avoid exposing the user ID and/or the associated
+password, these values can be read from files. The syntax is extended by:
+
+- The ``directory`` authentication parameter, which handles the common
+ part of file paths. The default value is the empty string.
+
+- The ``password-file`` client parameter, which, alongside the ``directory``
+ parameter, specifies the path of a file that can contain the password,
+ or when no user ID is given, the whole basic HTTP authentication secret.
+
+- The ``user-file`` client parameter, which, with the ``directory`` parameter,
+ specifies the path of a file where the user ID can be read.
+
+When files are used, they are read when the configuration is loaded,
+to detect configuration errors as soon as possible.
+
+Hook libraries can be loaded by :iscman:`kea-ctrl-agent` in the same way as
+they are loaded by :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. The CA currently
+supports one hook point - ``control_command_receive`` - which makes it
+possible to delegate the processing of some commands to the hook library.
+The ``hooks-libraries`` list contains the list of hook libraries that
+should be loaded by :iscman:`kea-ctrl-agent`, along with their configuration information
+specified with ``parameters``.
+
+Please consult :ref:`logging` for the details on how to configure
+logging. The CA's root logger's name is :iscman:`kea-ctrl-agent`, as given in
+the example above.
+
+.. _agent-secure-connection:
+
+Secure Connections
+==================
+
+The Kea Control Agent natively supports secure
+HTTP connections using TLS. This allows protection against users from
+the node where the agent runs, something that a reverse proxy cannot
+provide. More about TLS/HTTPS support in Kea can be found in :ref:`tls`.
+
+TLS is configured using three string parameters with file names, and
+a boolean parameter:
+
+- The ``trust-anchor`` specifies the Certification Authority file name or
+ directory path.
+
+- The ``cert-file`` specifies the server certificate file name.
+
+- The ``key-file`` specifies the private key file name. The file must not
+ be encrypted.
+
+- The ``cert-required`` specifies whether client certificates are required
+ or optional. The default is to require them and to perform mutual
+ authentication.
+
+The file format is PEM. Either all the string parameters are specified and
+HTTP over TLS (HTTPS) is used, or none is specified and plain HTTP is used.
+Configuring only one or two string parameters results in an error.
+
+.. note::
+
+ When client certificates are not required, only the server side is
+ authenticated, i.e. the communication is encrypted with an unknown
+ client. This protects only against passive attacks; active
+ attacks, such as "man-in-the-middle," are still possible.
+
+.. note::
+
+ No standard HTTP authentication scheme cryptographically binds its end
+ entity with TLS. This means that the TLS client and server can be
+ mutually authenticated, but there is no proof they are the same as
+ for the HTTP authentication.
+
+The :iscman:`kea-shell` tool also supports TLS.
+
+.. _agent-launch:
+
+Starting and Stopping the Control Agent
+=======================================
+
+:iscman:`kea-ctrl-agent` accepts the following command-line switches:
+
+- ``-c file`` - specifies the configuration file.
+
+- ``-d`` - specifies whether the agent logging should be switched to
+ debug/verbose mode. In verbose mode, the logging severity and
+ debuglevel specified in the configuration file are ignored and
+ "debug" severity and the maximum debuglevel (99) are assumed. The
+ flag is convenient for temporarily switching the server into maximum
+ verbosity, e.g. when debugging.
+
+- ``-t file`` - specifies the configuration file to be tested.
+ :iscman:`kea-netconf` attempts to load it and conducts sanity checks;
+ certain checks are possible only while running the actual server. The
+ actual status is reported with exit code (0 = configuration appears valid,
+ 1 = error encountered). Kea prints out log messages to standard
+ output and error to standard error when testing the configuration.
+
+- ``-v`` - displays the version of :iscman:`kea-ctrl-agent` and exits.
+
+- ``-V`` - displays the extended version information for :iscman:`kea-ctrl-agent`
+ and exits. The listing includes the versions of the libraries
+ dynamically linked to Kea.
+
+- ``-W`` - displays the Kea configuration report and exits. The report
+ is a copy of the ``config.report`` file produced by ``./configure``;
+ it is embedded in the executable binary.
+
+ The contents of the ``config.report`` file may also be accessed by examining
+ certain libraries in the installation tree or in the source tree.
+
+ .. code-block:: shell
+
+ # from installation using libkea-process.so
+ $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.so
+ $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.a
+ $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
+
+ # from sources using libcfgrpt.a
+ $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
+
+The CA is started by running its binary and specifying the configuration
+file it should use. For example:
+
+.. code-block:: console
+
+ $ ./kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf
+
+It can be started by :iscman:`keactrl` as well (see :ref:`keactrl`).
+
+.. _agent-clients:
+
+Connecting to the Control Agent
+===============================
+
+For an example of a tool that can take advantage of the RESTful API, see
+:ref:`kea-shell`.
diff --git a/doc/sphinx/arm/classify.rst b/doc/sphinx/arm/classify.rst
new file mode 100644
index 0000000..7f011ec
--- /dev/null
+++ b/doc/sphinx/arm/classify.rst
@@ -0,0 +1,1265 @@
+.. _classify:
+
+*********************
+Client Classification
+*********************
+
+Client Classification Overview
+==============================
+
+In certain cases it is useful to differentiate among different types
+of clients and treat them accordingly. Common reasons include:
+
+- The clients represent different pieces of topology, e.g. a cable
+ modem is not the same as the clients behind that modem.
+
+- The clients have different behavior, e.g. a smartphone behaves
+ differently from a laptop.
+
+- The clients require different values for some options, e.g. a
+ docsis3.0 cable modem requires different settings from a docsis2.0
+ cable modem.
+
+To make management easier, different clients can be grouped into a
+client class to receive common options.
+
+An incoming packet can be associated with a client class in several
+ways:
+
+- Implicitly, using a vendor class option or another built-in condition.
+
+- Using an expression which evaluates to ``true``.
+
+- Using static host reservations, a shared network, a subnet, etc.
+
+- Using a hook.
+
+Client classification can be used to change the behavior of almost any
+part of the DHCP message processing. There are currently nine
+mechanisms that take advantage of client classification:
+
+- Dropping queries.
+
+- Subnet selection.
+
+- Pool selection.
+
+- Lease limiting.
+
+- Rate limiting.
+
+- DDNS tuning.
+
+- Defining DHCPv4 private (codes 224-254) and code 43 options.
+
+- Assigning different options.
+
+- Setting specific options for use with the TFTP server address
+ and the boot file field for DHCPv4 cable modems.
+
+.. _classify-classification-steps:
+
+Classification Steps
+--------------------
+
+The classification process is conducted in several steps:
+
+1. The ``ALL`` class is associated with the incoming packet.
+
+2. Vendor class options are processed.
+
+3. Classes with matching expressions and not marked for later evaluation ("on
+ request" or depending on the ``KNOWN``/``UNKNOWN`` built-in classes)
+ are processed in the order they are defined in the
+ configuration; the boolean expression is evaluated and, if it
+ returns ``true`` (a match), the incoming packet is associated with the
+ class.
+
+4. If a private or code 43 DHCPv4 option is received, it is decoded
+ following its client-class or global (or, for option 43,
+ last-resort) definition.
+
+5. When the incoming packet belongs to the special class ``DROP``, it is
+ dropped and an informational message is logged with the packet
+ information.
+
+.. note::
+
+ The ``pkt4_receive`` and ``pkt6_receive`` callouts are called here.
+
+6. When the ``early-global-reservations-lookup`` global parameter is
+ configured to ``true``, the process looks up global reservations and
+ partially performs steps 8, 9, and 10. The lookup is limited to
+ global reservations; if one is found the ``KNOWN`` class is set,
+ but if none is found the ``UNKNOWN`` class is **not** set.
+
+7. A subnet is chosen, possibly based on the class information when
+ some subnets are reserved. More precisely: when choosing a subnet,
+ the server iterates over all of the subnets that are feasible given
+ the information found in the packet (client address, relay address,
+ etc.). It uses the first subnet it finds that either has no
+ class associated with it, or has a class which matches one of the
+ packet's classes.
+
+.. note::
+
+ The ``subnet4_select`` and ``subnet6_select`` callouts are called here.
+
+8. The server looks for host reservations. If an identifier from the
+ incoming packet matches a host reservation in the subnet or shared
+ network, the packet is associated with the ``KNOWN`` class and all
+ classes of the host reservation. If a reservation is not found, the
+ packet is assigned to the ``UNKNOWN`` class.
+
+9. Classes with matching expressions - directly, or indirectly using the
+ ``KNOWN``/``UNKNOWN`` built-in classes and not marked for later evaluation
+ ("on request") - are processed in the order they are defined
+ in the configuration; the boolean expression is evaluated and, if it
+ returns ``true`` (a match), the incoming packet is associated with the
+ class. After a subnet is selected, the server determines whether
+ there is a reservation for a given client. Therefore, it is not
+ possible to use the ``UNKNOWN`` class to select a shared network or
+ a subnet. For the ``KNOWN`` class, only global reservations are used and the
+ ``early-global-reservations-lookup`` parameter must be configured to
+ ``true``.
+
+10. When the incoming packet belongs to the special class ``DROP``, it is
+ dropped and an informational message is logged with the packet
+ information. Since Kea version 1.9.8, it is permissible to make the ``DROP``
+ class dependent on the ``KNOWN``/``UNKNOWN`` classes.
+
+11. If needed, addresses and prefixes from pools are assigned, possibly
+ based on the class information when some pools are reserved for
+ class members.
+
+.. note::
+
+ The ``lease4_select``, ``lease4_renew``, ``lease6_select``, ``lease6_renew``, and ``lease6_rebind``
+ callouts are called here.
+
+12. Classes marked as "required" are evaluated in the order in which
+ they are listed: first the shared network, then the subnet, and
+ finally the pools that assigned resources belong to.
+
+13. Options are assigned, again possibly based on the class information
+ in the order that classes were associated with the incoming packet.
+ For DHCPv4 private and code 43 options, this includes option
+ definitions specified within classes.
+
+.. note::
+
+ Care should be taken with client classification, as it is easy for
+ clients that do not meet any class criteria to be denied service
+ altogether.
+
+.. _built-in-client-classes:
+
+Built-in Client Classes
+=======================
+
+Some classes are built-in, so they do not need to be explicitly defined. They
+can be defined if there is a need to associate lease lifetimes, option data,
+etc. with them.
+
+Vendor class information is the primary example: the server checks whether an
+incoming DHCPv4 packet includes the vendor class identifier option (60)
+or an incoming DHCPv6 packet includes the vendor class option (16). If
+it does, the content of that option is prepended with ``VENDOR_CLASS_``
+and the result is interpreted as a class for that packet. The content that is
+considered is the whole class identifier for DHCPv4, and the first vendor class
+data field for DHCPv6. The enterprise number and subsequent vendor class data
+fields are not used for the purpose of classification. For example, modern cable
+modems send such options with value ``docsis3.0``, so the packet belongs to
+class ``VENDOR_CLASS_docsis3.0``.
+
+The ``HA_`` prefix is used by :ischooklib:`libdhcp_ha.so` to
+designate certain servers to process DHCP packets as a result of load
+balancing. The class name is constructed by prepending the ``HA_`` prefix
+to the name of the server which should process the DHCP packet. This
+server uses an appropriate pool or subnet to allocate IP addresses
+(and/or prefixes), based on the assigned client classes. The details can
+be found in :ref:`hooks-high-availability`.
+
+The ``SPAWN_`` prefix is used by template classes to generate spawned class
+names at runtime. The spawned class name is constructed by prepending the
+``SPAWN_`` prefix to the template class name and the evaluated value:
+``SPAWN_<template-class-name>_<evaluated-value>``.
+More details can be found in :ref:`classification-configuring`.
+
+The ``BOOTP`` class is used by :ischooklib:`libdhcp_bootp.so` to classify and
+respond to inbound BOOTP queries.
+
+The ``SKIP_DDNS`` class is used by the DDNS-tuning hook library to suppress
+DDNS updates on a per client basis.
+
+Other examples are the ``ALL`` class, to which all incoming packets belong,
+and the ``KNOWN`` class, assigned when host reservations exist for a
+particular client. By convention, the names of built-in classes begin with all
+capital letters.
+
+Currently recognized built-in class names are ``ALL``, ``KNOWN`` and ``UNKNOWN``,
+and the prefixes ``VENDOR_CLASS_``, ``HA_``, ``AFTER_``, ``EXTERNAL_``,
+``SKIP_DDNS``. Although the ``AFTER_`` prefix is a provision for an
+as-yet-unwritten hook, the ``EXTERNAL_`` prefix can be freely used; built-in
+classes are implicitly defined so they never raise warnings if they do not
+appear in the configuration.
+
+.. _classification-using-expressions:
+
+Using Expressions in Classification
+===================================
+
+The expression portion of a classification definition contains operators
+and values. All values are currently strings; operators take a string or
+strings and return another string. When all the operations have
+completed, the result should be a value of ``true`` or ``false``. The packet
+belongs to the class (and the class name is added to the list of
+classes) if the result is ``true``. Expressions are written in standard
+format and can be nested.
+
+Expressions are pre-processed during the parsing of the configuration
+file and converted to an internal representation. This allows certain
+types of errors to be caught and logged during parsing. Examples of
+these errors include an incorrect number or type of argument to an
+operator. The evaluation code also checks for this class of error and
+generally throws an exception, though this should not occur in a
+normally functioning system.
+
+Other issues, such as the starting position of a substring being
+outside of the substring or an option not existing in the packet, result
+in the operator returning an empty string.
+
+Dependencies between classes are also checked. For instance, forward
+dependencies are rejected when the configuration is parsed; an
+expression can only depend on already-defined classes (including built-in
+classes) which are evaluated in a previous or the same evaluation phase.
+This does not apply to the ``KNOWN`` or ``UNKNOWN`` classes.
+
+.. table:: List of classification values
+
+ +-----------------------+-------------------------------+-----------------------+
+ | Name | Example expression | Example value |
+ +=======================+===============================+=======================+
+ | String literal | 'example' | 'example' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Hexadecimal string | 0x5a7d | 'Z}' |
+ | literal | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | IP address literal | 10.0.0.1 | 0x0a000001 |
+ +-----------------------+-------------------------------+-----------------------+
+ | Integer literal | 123 | '123' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Binary content of the | option[123].hex | '(content of the |
+ | option | | option)' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Option existence | option[123].exists | 'true' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Binary content of the | option[12].option[34].hex | '(content of the |
+ | sub-option | | sub-option)' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Sub-Option existence | option[12].option[34].exists | 'true' |
+ +-----------------------+-------------------------------+-----------------------+
+ | Client class | member('foobar') | 'true' |
+ | membership | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Known client | known | member('KNOWN') |
+ +-----------------------+-------------------------------+-----------------------+
+ | Unknown client | unknown | not member('KNOWN') |
+ +-----------------------+-------------------------------+-----------------------+
+ | DHCPv4 relay agent | relay4[123].hex | '(content of the RAI |
+ | sub-option | | sub-option)' |
+ +-----------------------+-------------------------------+-----------------------+
+ | DHCPv6 Relay Options | relay6[nest].option[code].hex | (value of the option) |
+ +-----------------------+-------------------------------+-----------------------+
+ | DHCPv6 Relay Peer | relay6[nest].peeraddr | 2001:DB8::1 |
+ | Address | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | DHCPv6 Relay Link | relay6[nest].linkaddr | 2001:DB8::1 |
+ | Address | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Interface name of | pkt.iface | eth0 |
+ | packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Source address of | pkt.src | 10.1.2.3 |
+ | packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Destination address | pkt.dst | 10.1.2.3 |
+ | of packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Length of packet | pkt.len | 513 |
+ +-----------------------+-------------------------------+-----------------------+
+ | Hardware address in | pkt4.mac | 0x010203040506 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Hardware length in | pkt4.hlen | 6 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Hardware type in | pkt4.htype | 6 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | ciaddr field in | pkt4.ciaddr | 192.0.2.1 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | giaddr field in | pkt4.giaddr | 192.0.2.1 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | yiaddr field in | pkt4.yiaddr | 192.0.2.1 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | siaddr field in | pkt4.siaddr | 192.0.2.1 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Message type in | pkt4.msgtype | 1 |
+ | DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Transaction ID (xid) | pkt4.transid | 12345 |
+ | in DHCPv4 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Message type in | pkt6.msgtype | 1 |
+ | DHCPv6 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Transaction ID in | pkt6.transid | 12345 |
+ | DHCPv6 packet | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor option | vendor[*].exists | 'true' |
+ | existence (any | | |
+ | vendor) | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor option | vendor[4491].exists | 'true' |
+ | existence (specific | | |
+ | vendor) | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Enterprise-id from | vendor.enterprise | 4491 |
+ | vendor option | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor sub-option | vendor[4491].option[1].exists | 'true' |
+ | existence | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor sub-option | vendor[4491].option[1].hex | docsis3.0 |
+ | content | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor class option | vendor-class[*].exists | 'true' |
+ | existence (any | | |
+ | vendor) | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Vendor class option | vendor-class[4491].exists | 'true' |
+ | existence (specific | | |
+ | vendor) | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Enterprise-id from | vendor-class.enterprise | 4491 |
+ | vendor class option | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | First data chunk from | vendor-class[4491].data | docsis3.0 |
+ | vendor class option | | |
+ +-----------------------+-------------------------------+-----------------------+
+ | Specific data chunk | vendor-class[4491].data[3] | docsis3.0 |
+ | from vendor class | | |
+ | option | | |
+ +-----------------------+-------------------------------+-----------------------+
+
+Notes:
+
+- Hexadecimal strings are converted into a string as expected. The
+ starting ``0X`` or ``0x`` is removed, and if the string is an odd number
+ of characters a "0" is prepended to it.
+
+- IP addresses are converted into strings of length 4 or 16. IPv4,
+ IPv6, and IPv4-embedded IPv6 (e.g. IPv4-mapped IPv6) addresses are
+ supported.
+
+- Integers in an expression are converted to 32-bit unsigned integers
+ and are represented as four-byte strings; for example, 123 is
+ represented as ``0x0000007b``. All expressions that return numeric values
+ use 32-bit unsigned integers, even if the field in the packet is
+ smaller. In general, it is easier to use decimal notation to
+ represent integers, but it is also possible to use hexadecimal
+ notation. When writing an integer in hexadecimal, care should be
+ taken to make sure the value is represented as 32 bits, e.g. use
+ ``0x00000001`` instead of ``0x1`` or ``0x01``. Also, make sure the value is
+ specified in network order, e.g. 1 is represented as ``0x00000001``.
+
+- ``option[code].hex`` extracts the value of the option with the code
+ ``code`` from the incoming packet. If the packet does not contain the
+ option, it returns an empty string. The string is presented as a byte
+ string of the option payload, without the type code or length fields.
+
+- ``option[code].exists`` checks whether an option with the code ``code``
+ is present in the incoming packet. It can be used with empty options.
+
+- ``member('foobar')`` checks whether the packet belongs to the client
+ class ``foobar``. To avoid dependency loops, the configuration file
+ parser verifies whether client classes were already defined or are
+ built-in, i.e., beginning with ``VENDOR_CLASS_``, ``AFTER_`` (for the
+ to-come "after" hook) and ``EXTERNAL_`` or equal to ``ALL``, ``KNOWN``,
+ ``UNKNOWN``, etc.
+
+ ``known`` and ``unknown`` are shorthand for ``member('KNOWN')`` and ``not
+ member('KNOWN')``. Note that the evaluation of any expression using
+ the ``KNOWN`` class (directly or indirectly) is deferred after the host
+ reservation lookup (i.e. when the ``KNOWN`` or ``UNKNOWN`` partition is
+ determined).
+
+- ``relay4[code].hex`` attempts to extract the value of the sub-option
+ ``code`` from the option inserted as the DHCPv4 Relay Agent Information
+ (82) option. If the packet does not contain a RAI option, or the RAI
+ option does not contain the requested sub-option, the expression
+ returns an empty string. The string is presented as a byte string of
+ the option payload without the type code or length fields. This
+ expression is allowed in DHCPv4 only.
+
+- ``relay4`` shares the same representation types as ``option``; for
+ instance, ``relay4[code].exists`` is supported.
+
+- ``relay6[nest]`` allows access to the encapsulations used by any DHCPv6
+ relays that forwarded the packet. The ``nest`` level specifies the
+ relay from which to extract the information, with a value of 0
+ indicating the relay closest to the DHCPv6 server. Negative values
+ allow relays to be specified counting from the DHCPv6 client, with -1 indicating
+ the relay closest to the client. If the requested
+ encapsulation does not exist, an empty string ``""`` is returned. This
+ expression is allowed in DHCPv6 only.
+
+- ``relay6[nest].option[code]`` shares the same representation types as
+ ``option``; for instance, ``relay6[nest].option[code].exists`` is
+ supported.
+
+- Expressions starting with ``pkt4`` can be used only in DHCPv4. They
+ allow access to DHCPv4 message fields.
+
+- ``pkt6`` refers to information from the client request. To access any
+ information from an intermediate relay, use ``relay6``. ``pkt6.msgtype``
+ and ``pkt6.transid`` output a 4-byte binary string for the message type
+ or transaction ID. For example, the message type ``SOLICIT`` is
+ ``0x00000001`` or simply 1, as in ``pkt6.msgtype == 1``.
+
+- "Vendor option" means the Vendor-Identifying Vendor-Specific Information
+ option in DHCPv4 (code 125; see `Section 4 of RFC
+ 3925 <https://tools.ietf.org/html/rfc3925#section-4>`__) and the
+ Vendor-Specific Information Option in DHCPv6 (code 17, defined in
+ `Section 21.17 of RFC
+ 8415 <https://tools.ietf.org/html/rfc8415#section-21.17>`__). "Vendor
+ class option" means the Vendor-Identifying Vendor Class Option in DHCPv4
+ (code 124; see `Section 3 of RFC
+ 3925 <https://tools.ietf.org/html/rfc3925#section-3>`__) in DHCPv4 and
+ the Class Option in DHCPv6 (code 16; see `Section 21.16 of RFC
+ 8415 <https://tools.ietf.org/html/rfc8415#section-21.16>`__). Vendor
+ options may have sub-options that are referenced by their codes.
+ Vendor class options do not have sub-options, but rather data chunks,
+ which are referenced by index value. Index 0 means the first data
+ chunk, index 1 is for the second data chunk (if present), etc.
+
+- In the vendor and vendor-class constructs an asterisk (*) or 0 can be
+ used to specify a wildcard ``enterprise-id`` value, i.e. it will match
+ any ``enterprise-id`` value.
+
+- Vendor Class Identifier (option 60 in DHCPv4) can be accessed using the
+ option[60] expression.
+
+- `RFC 3925 <https://tools.ietf.org/html/rfc3925>`__ and `RFC
+ 8415 <https://tools.ietf.org/html/rfc8415>`__ allow for multiple
+ instances of vendor options to appear in a single message. The client
+ classification code currently examines the first instance if more
+ than one appear. For the ``vendor.enterprise`` and ``vendor-class.enterprise``
+ expressions, the value from the first instance is returned. Please
+ submit a feature request on the
+ `Kea GitLab site <https://gitlab.isc.org/isc-projects/kea>`__ to request
+ support for multiple instances.
+
+.. table:: List of classification expressions
+
+ +-----------------------+-------------------------+-----------------------+
+ | Name | Example | Description |
+ +=======================+=========================+=======================+
+ | Equal | 'foo' == 'bar' | Compare the two |
+ | | | values and return |
+ | | | ``true`` or ``false`` |
+ +-----------------------+-------------------------+-----------------------+
+ | Not | not ('foo' == 'bar') | Logical negation |
+ +-----------------------+-------------------------+-----------------------+
+ | And | ('foo' == 'bar') and | Logical and |
+ | | ('bar' == 'foo') | |
+ +-----------------------+-------------------------+-----------------------+
+ | Or | ('foo' == 'bar') or | Logical or |
+ | | ('bar' == 'foo') | |
+ +-----------------------+-------------------------+-----------------------+
+ | Substring | substring('foobar',0,3) | Return the requested |
+ | | | substring |
+ +-----------------------+-------------------------+-----------------------+
+ | Concat | concat('foo','bar') | Return the |
+ | | | concatenation of the |
+ | | | strings |
+ +-----------------------+-------------------------+-----------------------+
+ | Concat (operator +) | 'foo' + 'bar' | Return the |
+ | | | concatenation of the |
+ | | | strings |
+ +-----------------------+-------------------------+-----------------------+
+ | Ifelse | ifelse('foo' == | Return the branch |
+ | | 'bar','us','them') | value according to |
+ | | | the condition |
+ +-----------------------+-------------------------+-----------------------+
+ | Hexstring | hexstring('foo', '-') | Converts the value to |
+ | | | a hexadecimal string, |
+ | | | e.g. 66-6F-6F |
+ +-----------------------+-------------------------+-----------------------+
+ | Lcase | lcase('LoWeR') | Converts the value of |
+ | | | a string expression |
+ | | | to lower case e.g. |
+ | | | 'lower' |
+ +-----------------------+-------------------------+-----------------------+
+ | Ucase | ucase('uPpEr') | Converts the value of |
+ | | | a string expression |
+ | | | to upper case e.g. |
+ | | | 'UPPER' |
+ +-----------------------+-------------------------+-----------------------+
+ | Split | split('foo.bar', '.', 2)| Return the second |
+ | | | field, splitting on |
+ | | | dots. |
+ +-----------------------+-------------------------+-----------------------+
+
+.. table:: List of conversion-to-text expressions
+
+ +-----------------------+---------------------------+------------------------+
+ | Name | Example | Description |
+ +=======================+===========================+========================+
+ | AddressToText | addrtotext (192.10.0.1) | Represent the 4 bytes |
+ | | addrtotext (2003:db8::) | of an IPv4 address or |
+ | | | the 16 bytes of an |
+ | | | IPv6 address in human |
+ | | | readable format |
+ +-----------------------+---------------------------+------------------------+
+ | Int8ToText | int8totext (-1) | Represents the 8-bit |
+ | | | signed integer in text |
+ | | | format |
+ +-----------------------+---------------------------+------------------------+
+ | Int16ToText | int16totext (-1) | Represents the 16-bit |
+ | | | signed integer in text |
+ | | | format |
+ +-----------------------+---------------------------+------------------------+
+ | Int32ToText | int32totext (-1) | Represents the 32-bit |
+ | | | signed integer in text |
+ | | | format |
+ +-----------------------+---------------------------+------------------------+
+ | UInt8ToText | uint8totext (255) | Represents the 8-bit |
+ | | | unsigned integer in |
+ | | | text format |
+ +-----------------------+---------------------------+------------------------+
+ | UInt16ToText | uint16totext (65535) | Represents the 16-bit |
+ | | | unsigned integer in |
+ | | | text format |
+ +-----------------------+---------------------------+------------------------+
+ | UInt32ToText | uint32totext (4294967295) | Represents the 32-bit |
+ | | | unsigned integer in |
+ | | | text format |
+ +-----------------------+---------------------------+------------------------+
+
+Notes:
+
+The conversion operators can be used to transform data from binary to the text
+representation. The only requirement is that the input data type length matches
+an expected value.
+
+The ``AddressToText`` token expects 4 bytes for IPv4 addresses or 16 bytes for IPv6
+addresses. The ``Int8ToText`` and ``UInt8ToText`` tokens expect 1 byte, the ``Int16ToText`` and
+``UInt16ToText`` tokens expect 2 bytes, and ``Int32ToText`` and ``UInt32ToText`` expect 4 bytes.
+For all conversion tokens, if the data length is 0, the result string is empty.
+
+Logical Operators
+-----------------
+
+The Not, And, and Or logical operators are the common operators. Not has
+the highest precedence and Or the lowest. And and Or are (left)
+associative. Parentheses around a logical expression can be used to
+enforce a specific grouping; for instance, in "A and (B or C)". Without
+parentheses, "A and B or C" means "(A and B) or C".
+
+Substring
+---------
+
+The substring operator ``substring(value, start, length)`` accepts both
+positive and negative values for the starting position and the length.
+For ``start``, a value of 0 is the first byte in the string while -1 is
+the last byte. If the starting point is outside of the original string
+an empty string is returned. ``length`` is the number of bytes to extract.
+A negative number means to count towards the beginning of the string but
+does not include the byte pointed to by ``start``. The special value ``all``
+means to return all bytes from start to the end of the string. If the length
+is longer than the remaining portion of the string, then the entire
+remaining portion is returned. Some examples may be helpful:
+::
+
+ substring('foobar', 0, 6) == 'foobar'
+ substring('foobar', 3, 3) == 'bar'
+ substring('foobar', 3, all) == 'bar'
+ substring('foobar', 1, 4) == 'ooba'
+ substring('foobar', -5, 4) == 'ooba'
+ substring('foobar', -1, -3) == 'oba'
+ substring('foobar', 4, -2) == 'ob'
+ substring('foobar', 10, 2) == ''
+
+
+Concat
+------
+
+The concat function ``concat(string1, string2)`` returns the concatenation
+of its two arguments. For instance:
+::
+
+ concat('foo', 'bar') == 'foobar'
+
+For user convenience, Kea version 1.9.8 added an associative operator
+version of the concat function. For instance:
+::
+
+ 'abc' + 'def' + 'ghi' + 'jkl' + '...'
+
+is the same as:
+::
+
+ concat(concat(concat(concat('abc', 'def'), 'ghi'), 'jkl'), '...')
+
+or:
+::
+
+ concat('abc', concat('def', concat('ghi', concat('jkl', '...'))))
+
+or:
+::
+
+ 'abcdefghijkl...'
+
+Split
+---------
+
+The split operator ``split(value, delimiters, field-number)`` accepts a list
+of characters to use as delimiters and a positive field number of the
+desired field when the value is split into fields separated by the delimiters.
+Adjacent delimiters are not compressed out, rather they result in an empty
+string for that field number. If value is an empty string, the result will be an
+empty string. If the delimiters list is empty, the result will be the original
+value. If the field-number is less than one or larger than the number of
+fields, the result will be an empty string. Some examples follow:
+::
+
+ split ('one.two..four', '.', 1) == 'one'
+ split ('one.two..four', '.', 2) == 'two'
+ split ('one.two..four', '.', 3) == ''
+ split ('one.two..four', '.', 4) == 'four'
+ split ('one.two..four', '.', 5) == ''
+
+.. note::
+
+ To use a hard-to-escape character as a delimiter, use its ASCII hex value.
+ For example, split by ``single quote`` using ``0x27``:
+ ``split(option[39].text, 0x27, 1)``
+
+Ifelse
+------
+
+The ifelse function ``ifelse(cond, iftrue, ifelse)`` returns the ``iftrue``
+or ``ifelse`` branch value following the boolean condition ``cond``. For
+instance:
+::
+
+ ifelse(option[230].exists, option[230].hex, 'none')
+
+
+Hexstring
+---------
+
+The hexstring function ``hexstring(binary, separator)`` returns the binary
+value as its hexadecimal string representation: pairs of hexadecimal
+digits separated by the separator, e.g ``':'``, ``'-'``, ``''`` (empty separator).
+::
+
+ hexstring(pkt4.mac, ':')
+
+
+.. note::
+
+ The expression for each class is executed on each packet received. If
+ the expressions are overly complex, the time taken to execute them
+ may impact the performance of the server. Administrators who need complex or
+ time-consuming expressions should consider writing a
+ :ref:`hook <hooks-libraries>` to perform the necessary work.
+
+.. _classification-configuring:
+
+Configuring Classes
+===================
+
+A client class definition can contain the following properties:
+ - The ``name`` parameter is mandatory and must be unique among all classes.
+ - The ``test`` expression is not mandatory and represents a string containing the
+ logical expression used to determine membership in the class. The entire
+ expression is included in double quotes (``"``). The result should evaluate
+ to a boolean value (``true`` or ``false``).
+ - The ``template-test`` expression is not mandatory and represents a string
+ containing the logical expression used to generate a spawning class. The
+ entire expression is included in double quotes (``"``). The result should
+ evaluate to a string value representing the variable part of the spawned
+ class name. If the resulting string is empty, no spawning class is generated.
+ The resulting spawned class has the following generated name format:
+ ``SPAWN_<template-class-name>_<evaluated-value>``.
+ After classes are evaluated and a spawned class is generated, the corresponding
+ template class name is also associated with the packet.
+ - The ``option-data`` list is not mandatory and contains options that should be
+ assigned to members of this class. In the case of a template class, these
+ options are assigned to the generated spawned class.
+ - The ``option-def`` list is not mandatory and is used to define custom options.
+ - The ``only-if-required`` flag is not mandatory; when its value is set to
+ ``false`` (the default), membership is determined during classification and is
+ available for subnet selection, for instance. When the value is set to
+ ``true``, membership is evaluated only when required and is usable only for
+ option configuration.
+ - The ``user-context`` is not mandatory and represents a map with user-defined data
+ and possibly configuration options for hook libraries.
+ - The ``next-server`` parameter is not mandatory and configures the ``siaddr`` field in
+ packets associated with this class. It is used in DHCPv4 only.
+ - The ``server-hostname`` is not mandatory and configures the ``sname`` field in
+ packets associated with this class. It is used in DHCPv4 only.
+ - The ``boot-file-name`` is not mandatory and configures the ``file`` field in
+ packets associated with this class. It is used in DHCPv4 only.
+ - The ``valid-lifetime``, ``min-valid-lifetime``, and ``max-valid-lifetime`` are
+ not mandatory and configure the valid lifetime fields for this client class.
+ - The ``preferred-lifetime``, ``min-preferred-lifetime``, and
+ ``max-preferred-lifetime`` are not mandatory and configure the preferred
+ lifetime fields for this client class. It is used in DHCPv6 only.
+
+
+.. note::
+
+ ``test`` and ``template-test`` are mutually exclusive in a client class
+ definition. Use either one, or neither, but not both. If both are provided,
+ the configuration is rejected.
+
+In the following example, the class named ``Client_foo`` is defined. It is
+comprised of all clients whose client IDs (option 61) start with the string
+``foo``. Members of this class will be given 192.0.2.1 and 192.0.2.2 as their
+domain name servers.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.1, 192.0.2.2"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ }
+
+The next example shows a client class being defined for use by the DHCPv6
+server. In it the class named "Client_enterprise" is defined. It is
+comprised of all clients whose client identifiers start with the given
+hex string (which would indicate a DUID based on an enterprise ID of
+``0x0002AABBCCDD``). Members of this class will be given 2001:db8:0::1 and
+2001:db8:2::1 as their domain name servers.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client_enterprise",
+ "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:0::1, 2001:db8:2::1"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ }
+
+It is also possible to have both left and right operands of the evaluated
+expression processed at runtime. Expressions related to packets can appear in
+the expression as many times as needed; there is no limit. However, each token
+has a small impact on performance and excessively complex expressions may cause a
+bottleneck.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Infrastructure",
+ "test": "option[82].option[2].hex == pkt4.mac",
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+.. _template-classes:
+
+Template Classes
+----------------
+
+The ``template-test`` parameter indicates that the class is a template class.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client-ID",
+ "template-test": "substring(option[61].hex,0,3)",
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+If the received DHCPv4 packet contains option 61, then the first three bytes represent
+the value ``foo`` in ASCII, and the spawned class uses the
+``SPAWN_Client-ID_foo`` name.
+Both the ``SPAWN_Client-ID_foo`` and ``Client-ID`` classes are associated with
+the packet.
+
+.. note ::
+
+ Template classes can also be used to spawn classes which match regular
+ classes, effectively associating the regular class to the packet.
+ To achieve this, the regular class must also contain the fixed part of the
+ spawned class name:
+
+ ``SPAWN_<template-class-name-used-to-activate-this-regular-class>_<evaluated-value-filtering-this-regular-class>``
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "SPAWN_Client-ID_foobar",
+ "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
+ ...
+ },
+ {
+ "name": "Client-ID",
+ "template-test": "substring(option[1].hex,0,6)",
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+If the received DHCPv6 packet contains option 1 (client identifier) with hex
+value ``0x0002AABBCCDD``, then the ``SPAWN_Client-ID_foobar`` is associated
+with the packet. Moreover, if the first six bytes represent value ``foobar`` in
+ASCII, then the spawned class uses the ``SPAWN_Client-ID_foobar`` name,
+effectively associating the regular class to the packet. In this second case,
+both the ``SPAWN_Client-ID_foobar`` and ``Client-ID`` classes are associated
+with the packet.
+The ``test`` expression on the regular class ``SPAWN_Client-ID_foobar`` is not
+mandatory and can be omitted, but it is used here with a different match
+expression for example purposes.
+
+Usually the ``test`` and ``template-test`` expressions are evaluated before
+subnet selection, but in some cases it is useful to evaluate it later when the
+subnet, shared network, or pools are known but output-option processing has not
+yet been done. For this purpose, the ``only-if-required`` flag, which is
+``false`` by default, allows the evaluation of the ``test`` expression or the
+``template-test`` expression only when it is required, i.e. in a
+``require-client-classes`` list of the selected subnet, shared network, or pool.
+
+The ``require-client-classes`` list, which is valid for shared-network, subnet,
+and pool scope, specifies the classes which are evaluated in the second pass
+before output-option processing. The list is built in reverse-precedence
+order of the option data, i.e. an option data item in a subnet takes precedence over
+one in a shared network, but a required class in a subnet is added after one in a
+shared network. The mechanism is related to the ``only-if-required`` flag but it
+is not mandatory that the flag be set to ``true``.
+
+.. note ::
+
+ The ``template-test`` expression can also be used to filter generated spawned
+ classes, so that they are created only when needed by using the ``ifelse``
+ instruction.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client-ID",
+ "template-test": "ifelse(substring(option[61].hex,4,3) == 'foo', substring(option[12].hex,0,12), '')",
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+.. note ::
+
+ The template classes can be used to configure limits which, just like
+ options, are associated with the spawned class. This permits the configuration of
+ limits that apply to all packets associated with a class spawned at
+ runtime, according to the ``template-test`` expression in the parent template
+ class. For a more detailed description of how to configure limits using the
+ limits hook library, see :ref:`hooks-limits-configuration`.
+ For example, using the configuration below, ingress DHCPv6 packets that have
+ client ID values (in the format expressed by the Kea evaluator) ``foobar``
+ and ``foofoo`` both amount to the same limit of 60 packets per day, while
+ other packets that have the first three hextets different than ``foo`` are put
+ in separate rate-limiting buckets.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client-ID",
+ "template-test": "substring(option[1].hex,0,3)",
+ "user-context" : {
+ "limits": {
+ "rate-limit": "60 packets per day"
+ }
+ },
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+
+.. _classification-using-host-reservations:
+
+Using Static Host Reservations in Classification
+================================================
+
+Classes can be statically assigned to clients using techniques
+described in :ref:`reservation4-client-classes` and
+:ref:`reservation6-client-classes`.
+
+Subnet host reservations are searched after subnet selection.
+Global host reservations are searched at the same time by default but
+the ``early-global-reservations-lookup`` allows to change this behavior
+into searching them before the subnet selection.
+
+Pool selection is performed after all host reservations lookups.
+
+.. _classification-subnets:
+
+Configuring Subnets With Class Information
+==========================================
+
+In certain cases it is beneficial to restrict access to certain subnets
+only to clients that belong to a given class, using the ``client-class``
+keyword when defining the subnet.
+
+Let's assume that the server is connected to a network segment that uses the
+192.0.2.0/24 prefix. The administrator of that network has decided that
+addresses from the range 192.0.2.10 to 192.0.2.20 will be managed by the DHCPv4
+server. Only clients belonging to client class ``Client_foo`` are allowed to use
+this subnet. Such a configuration can be achieved in the following way:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.1, 192.0.2.2"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "client-class": "Client_foo"
+ },
+ ...
+ ],
+ ...
+ }
+
+The following example shows how to restrict access to a DHCPv6 subnet. This
+configuration restricts use of the addresses in the range 2001:db8:1::1 to
+2001:db8:1::FFFF to members of the "Client_enterprise" class.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client_enterprise",
+ "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:0::1, 2001:db8:2::1"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ],
+ "client-class": "Client_enterprise"
+ }
+ ],
+ ...
+ }
+
+.. _classification-pools:
+
+Configuring Pools With Class Information
+========================================
+
+Similar to subnets, in certain cases access to certain address or prefix
+pools must be restricted to only clients that belong to a given class,
+using the ``client-class`` when defining the pool.
+
+Let's assume that the server is connected to a network segment that uses the
+192.0.2.0/24 prefix. The administrator of that network has decided that
+addresses from the range 192.0.2.10 to 192.0.2.20 are going to be managed by the
+DHCPv4 server. Only clients belonging to client class ``Client_foo`` are allowed
+to use this pool. Such a configuration can be achieved in the following way:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.1, 192.0.2.2"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.10 - 192.0.2.20",
+ "client-class": "Client_foo"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ }
+
+The following example shows how to restrict access to an address pool. This
+configuration restricts use of the addresses in the range 2001:db8:1::1 to
+2001:db8:1::FFFF to members of the "Client_enterprise" class.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client_enterprise_",
+ "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:0::1, 2001:db8:2::1"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+
+ "subnet": "2001:db8:1::/64",
+
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::ffff",
+ "client-class": "Client_foo"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ }
+
+Class Priority
+==============
+
+Client classes in Kea follow the order in which they are specified in the
+configuration (vs. alphabetical order). Required classes follow the order in
+which they are required.
+
+When determining which client-class information (comprising of
+options, lease lifetimes or DHCPv4 field values) that is part of class
+definitions, to include in the response, the server examines the union of
+options from all of the assigned classes. If two or more classes include the
+same class information, the value from the first assigned class is used.
+``ALL`` is always the first class, hence the class with the highest
+priority, and matching required classes are last, so they have the
+lowest priority.
+
+Optons defined in classes override any global options, and in turn will be
+overridden by options defined for an individual subnet, shared network, pool or
+reservation.
+
+On the other hand, lease lifetimes and DHCPv4 field values defined at class
+scope override any values defined globally, in a subnet scope, or in a
+shared-network scope.
+
+As an example, imagine that an incoming packet matches two classes.
+Class ``foo`` defines values for an NTP server (option 42 in DHCPv4) and
+an SMTP server (option 69 in DHCPv4), while class ``bar`` defines values
+for an NTP server and a POP3 server (option 70 in DHCPv4). The server
+examines the three options - NTP, SMTP, and POP3 - and returns any that
+the client requested. As the NTP server was defined twice, the server
+chooses only one of the values for the reply; the class from which the
+value is obtained is determined as explained in the previous paragraphs.
+
+Classes and Hooks
+=================
+
+Hooks may be used to classify packets. This may be useful if the
+expression would be complex or time-consuming to write, and could be
+better or more easily written as code. Once the hook has added the proper class name
+to the packet, the rest of the classification system will work as expected
+in choosing a subnet and selecting options. For a description of hooks,
+see :ref:`hooks-libraries`; for information on configuring classes,
+see :ref:`classification-configuring` and :ref:`classification-subnets`.
+
+Debugging Expressions
+=====================
+
+While constructing classification expressions, administrators may find
+it useful to enable logging; see :ref:`logging` for a more complete
+description of the logging facility.
+
+To enable the debug statements in the classification system,
+the severity must be set to ``DEBUG`` and the debug level to at least 55.
+The specific loggers are ``kea-dhcp4.eval`` and ``kea-dhcp6.eval``.
+
+To understand the logging statements, it is essential to understand a bit about
+how expressions are evaluated; for a more complete description, refer to
+[the design document](https://gitlab.isc.org/isc-projects/kea/-/wikis/designs/client-classification-design).
+In brief, there are two structures used during the evaluation of an
+expression: a list of tokens which represent the expressions, and a value
+stack which represents the values being manipulated.
+
+The list of tokens is created when the configuration file is processed,
+with most expressions and values being converted to a token. The list is
+organized in reverse Polish notation. During execution, the list is
+traversed in order; as each token is executed, it is able to pop
+values from the top of the stack and eventually push its result on the
+top of the stack. Imagine the following expression:
+
+::
+
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+
+
+This will result in the following tokens:
+
+::
+
+ option, number (0), number (3), substring, text ('foo'), equals
+
+
+In this example, the first three tokens will simply push values onto the
+stack. The substring token will then remove those three values and
+compute a result that it places on the stack. The text option also
+places a value on the stack, and finally the equals token removes the two
+tokens on the stack and places its result on the stack.
+
+When debug logging is enabled, each time a token is evaluated it
+emits a log message indicating the values of any objects that were popped
+off of the value stack, and any objects that were pushed onto the value
+stack.
+
+The values are displayed as either text, if the command is known to
+use text values, or hexadecimal, if the command either uses binary values
+or can manipulate either text or binary values. For expressions that pop
+multiple values off the stack, the values are displayed in the order
+they were popped. For most expressions this will not matter, but for the
+concat expression the values are displayed in reverse order from their
+written order in the expression.
+
+Let us assume that the following test has been entered into the
+configuration. This example skips most of the configuration to
+concentrate on the test.
+
+::
+
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+
+
+The logging might then resemble this:
+
+::
+
+ 2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172
+ 2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0'
+ 2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3'
+ 2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F
+ 2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo'
+ 2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true'
+
+.. note::
+
+ The debug logging may be quite verbose if there are multiple
+ expressions to evaluate; it is intended as an aid in helping
+ create and debug expressions. Administrators should plan to disable debug
+ logging when expressions are working correctly. Users may also
+ wish to include only one set of expressions at a time in the
+ configuration file while debugging them, to limit the log
+ statements. For example, when adding a new set of expressions, an administrator
+ might find it more convenient to create a configuration file that
+ only includes the new expressions until they are working
+ correctly, and then add the new set to the main configuration file.
diff --git a/doc/sphinx/arm/config-backend.rst b/doc/sphinx/arm/config-backend.rst
new file mode 100644
index 0000000..f83bf5c
--- /dev/null
+++ b/doc/sphinx/arm/config-backend.rst
@@ -0,0 +1,327 @@
+.. _config-backend:
+
+Kea Configuration Backend
+=========================
+
+.. _cb-applicability:
+
+Applicability
+-------------
+
+Kea Configuration Backend (CB or config backend) gives Kea servers the ability
+to manage and fetch their configuration from one or more databases. In
+this documentation, the term "Configuration Backend" may also refer to
+the particular Kea module providing support to manage and fetch the
+configuration information from the particular database type. For
+example, the MySQL Configuration Backend is the logic implemented within
+:ischooklib:`libdhcp_mysql_cb.so`, which provides a complete set of functions to
+manage and fetch the configuration information from the MySQL database.
+The PostgreSQL Configuration Backend is the logic implemented within
+:ischooklib:`libdhcp_pgsql_cb.so`, which provides a complete set of functions to
+manage and fetch the configuration information from the PostgreSQL database.
+From herein, the term "database" is used to refer to either a MySQL or
+PostgreSQL database.
+
+In small deployments, e.g. those comprising a single DHCP server
+instance with limited and infrequently changing number of subnets, it
+may be impractical to use the CB as a configuration repository because
+it requires additional third-party software to be installed and
+configured - in particular the database server, client and libraries.
+Once the number of DHCP servers and/or the number of managed subnets in the
+network grows, the usefulness of the CB becomes obvious.
+
+One use case for the CB is a pair of Kea DHCP servers that are configured
+to support High Availability as described in
+:ref:`hooks-high-availability`. The configurations of both servers
+(including the value of the ``server-tag`` parameter)
+are almost exactly the same: they may differ by the server identifier
+and designation of the server as a primary or standby (or secondary), and/or
+by their interfaces' configuration. Typically, the
+subnets, shared networks, option definitions, and global parameters are the
+same for both servers and can be sourced from a single database instance
+to both Kea servers.
+
+Using the database as a single source of configuration for subnets
+and/or other configuration information supported by the CB has the
+advantage that any modifications to the configuration in the database are
+automatically applied to both servers.
+
+Another case when the centralized configuration repository is useful is
+in deployments including a large number of DHCP servers, possibly
+using a common lease database to provide redundancy. New servers can
+be added to the pool frequently to fulfill growing scalability
+requirements. Adding a new server does not require replicating the
+entire configuration to the new server when a common database is used.
+
+Using the database as a configuration repository for Kea servers also
+brings other benefits, such as:
+
+- the ability to use database specific tools to access the configuration
+ information;
+
+- the ability to create customized statistics based on the information
+ stored in the database; and
+
+- the ability to backup the configuration information using the database's
+ built-in replication mechanisms.
+
+.. _cb-limitations:
+
+CB Capabilities and Limitations
+-------------------------------
+
+Currently, the Kea CB has the following limitations:
+
+- It is only supported for MySQL and PostgreSQL databases.
+
+- It is only supported for the DHCPv4 and DHCPv6 daemons; the Control Agent,
+ D2 daemon, and the NETCONF daemon cannot be configured from the database,
+
+- Only certain DHCP configuration parameters can be set in the
+ database: global parameters, option definitions, global options, client
+ classes, shared networks, and subnets. Other configuration parameters
+ must be sourced from a JSON configuration file.
+
+Kea CB stores data in a schema that is public. It is possible to
+insert configuration data into the tables manually or automatically
+using SQL scripts, but this requires SQL and schema knowledge.
+The supported method for managing the data is through :ischooklib:`libdhcp_cb_cmds.so`,
+which provides management commands for config backends. It simplifies many
+typical operations, such as listing, adding, retrieving, and deleting global
+parameters, shared networks, subnets, pools, options, option definitions, and
+client classes. In addition, it provides essential business logic that ensures
+the logical integrity of the data. See commands starting with ``remote-`` in
+Appendix A of this manual for a complete list.
+
+.. note::
+
+ :ischooklib:`libdhcp_cb_cmds.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options, please
+ complete the form at https://www.isc.org/contact.
+
+The schema creation scripts can be found at
+`dhcpdb_create.mysql <https://gitlab.isc.org/isc-projects/kea/blob/master/src/share/database/scripts/mysql/dhcpdb_create.mysql>`__
+and
+`dhcpdb_create.pgsql <https://gitlab.isc.org/isc-projects/kea/blob/master/src/share/database/scripts/pgsql/dhcpdb_create.pgsql>`__.
+Other related design documents are stored in our GitLab:
+`CB Design <https://gitlab.isc.org/isc-projects/kea/wikis/designs/configuration-in-db-design>`__
+and
+`Client Classes in CB Design <https://gitlab.isc.org/isc-projects/kea/wikis/designs/client-classes-in-cb>`__.
+
+We strongly recommend against duplication of configuration information
+in both the file and the database. For example, when specifying subnets
+for the DHCP server, please store them in either the configuration backend
+or in the configuration file, not both. Storing some subnets in the database
+and others in the file may put users at risk of potential configuration
+conflicts. Note that the configuration instructions from the database take
+precedence over instructions from the file, so parts of the configuration
+specified in the file may be overridden if contradicted by information in
+the database.
+
+Although it is not recommended, it is possible to specify certain parameter
+types both in a configuration file and the database. For example, a subnet
+can be specified in the configuration file and another subnet in the database;
+in this case, the server will use both subnets. DHCP client classes, however,
+must not be specified in both the configuration file and the database, even if
+they do not overlap. If any client classes are specified in the database
+for a particular DHCP server, this server will use these classes and ignore
+all classes present in its configuration file. This behavior was introduced
+to ensure that the server receives a consistent set of client classes
+specified in an expected order with all inter-class dependencies fulfilled.
+It is impossible to guarantee consistency when client classes are specified
+in two independent configuration sources.
+
+.. note::
+
+ It is recommended that :ischooklib:`libdhcp_subnet_cmds.so` not be used to
+ manage subnets when the configuration backend is used as a source
+ of information about the subnets. :ischooklib:`libdhcp_subnet_cmds.so`
+ modifies the local subnets configuration in the server's memory,
+ not in the database. Use :ischooklib:`libdhcp_cb_cmds.so` to manage the
+ subnets information in the database instead.
+
+.. note::
+
+ Using custom option formats requires creating definitions for these options.
+ Suppose a user wishes to set option data in the configuration backend. In
+ that case, we recommend specifying the definition for that option in the
+ configuration backend as well. It is essential when multiple servers are
+ managed via the configuration backend, and may differ in their
+ configurations. The option data parser can search for an option definition
+ appropriate for the server for which the option data is specified.
+
+ In a single-server deployment, or when all servers share the same
+ configuration file information, it is possible to specify option
+ definitions in the configuration files and option data in the configuration
+ backend. The server receiving a command to set option data must have a
+ valid definition in its configuration file, even when it sets option data
+ for another server.
+
+ It is not supported to specify option definitions in the configuration
+ backend and the corresponding option data in the server configuration files.
+
+CB Components
+-------------
+
+To use a MySQL configuration backend you must compile
+:ischooklib:`libdhcp_mysql_cb.so` and configure the DHCP servers to load it.
+It is compiled when the ``--with-mysql`` configuration switch is used during the Kea build.
+The MySQL C client libraries must be installed, as explained in :ref:`dhcp-install-configure`.
+
+To use a PostgreSQL configuration backend you must compile :ischooklib:`libdhcp_pgsql_cb.so`
+and configure the DHCP servers to load it. It is compiled when
+the ``--with-pgsql`` configuration switch is used during the Kea build. The PostgreSQL
+C client libraries must be installed, as explained in :ref:`dhcp-install-configure`.
+
+.. note::
+
+ An existing database schema must be upgraded to the latest schema
+ required by the particular Kea version using the :iscman:`kea-admin` tool,
+ as described in :ref:`kea-admin`.
+
+:ischooklib:`libdhcp_cb_cmds.so` provides a complete set of commands to manage the
+servers' configuration information within the database. This library can
+be attached to both DHCPv4 and DHCPv6 server instances. While it is
+possible to manage the configuration information without :ischooklib:`libdhcp_cb_cmds.so`
+with commonly available tools, such as MySQL Workbench or
+the command-line MySQL client, or by directly working with the database;
+these avenues are neither recommended nor supported.
+
+The DHCPv4 and DHCPv6 server-specific configurations of the CB, as well as
+the list of supported configuration parameters, can be found in
+:ref:`dhcp4-cb` and :ref:`dhcp6-cb`, respectively.
+
+.. _cb-sharing:
+
+Configuration Sharing and Server Tags
+-------------------------------------
+
+The configuration database is designed to store configuration information
+for multiple Kea servers. Depending on the use case, the entire configuration
+may be shared by all servers; parts of the configuration may be shared by
+multiple servers and the rest of the configuration may be different for these
+servers; or each server may have its own non-shared configuration.
+
+The configuration elements in the database are associated with the servers
+by "server tags." The server tag is an arbitrary string holding the name
+of the Kea server instance. The tags of the DHCPv4 and DHCPv6 servers are
+independent in the database, i.e. the same server tag can be created for
+both the DHCPv4 and the DHCPv6 server. The value is configured
+using the ``server-tag`` parameter in the ``Dhcp4`` or ``Dhcp6`` scope. The current
+server tag can be checked with the :isccmd:`server-tag-get` command.
+
+The server definition, which consists of the server tag and the server
+description, must be stored in the configuration database prior to creating
+the dedicated configuration for that server. In cases when all servers use
+the same configuration, e.g. a pair of servers running as High Availability
+peers, there is no need to configure the server tags for these
+servers in the database.
+
+Commands which contain the logical server `all` are applied to all servers
+connecting to the database. The `all` server cannot be
+deleted or modified, and it is not returned among other servers
+as a result of the :isccmd:`remote-server4-get-all`, :isccmd:`remote-server6-get-all` commands.
+
+In most cases, there are no server tags defined in the configuration
+database; all connecting servers get the same configuration
+regardless of the server tag they use. The server tag that a
+particular Kea instance presents to the database to fetch its configuration
+is specified in the Kea configuration file, using the
+`config-control` map (please refer to the :ref:`dhcp4-cb-json` and
+:ref:`dhcp6-cb-json` for details). All Kea instances presenting the same
+server tag to the configuration database
+are given the same configuration.
+
+It is the administrator's choice whether
+multiple Kea instances use the same server tag or each Kea instance uses
+a different server tag. There is no requirement that the instances
+running on the same physical or virtual machine use the same server tag. It is
+even possible to configure the Kea server without assigning it a server tag.
+In such a case the server will be given the configuration specified for `all`
+servers.
+
+To differentiate between different Kea server configurations, a
+list of the server tags used by the servers must be stored in the
+database. For the DHCPv4 and DHCPv6 servers, it can be done using the
+:isccmd:`remote-server4-set` and :isccmd:`remote-server6-set` commands. The
+server tags can then be used to associate the configuration information with
+the servers. However, it is important to note that some DHCP
+configuration elements may be associated with multiple server tags (known
+as "shareable" elements), while
+other configuration elements may be associated with only one
+server tag ("non-shareable" elements). The :ref:`dhcp4-cb`
+and :ref:`dhcp6-cb` sections list the DHCP-specific shareable and
+non-shareable configuration elements; however, in this section we
+briefly explain the differences between them.
+
+A shareable configuration element is one which has some unique
+property identifying it, and which may appear only once in
+the database. An example of a shareable DHCP element is a subnet
+instance: the subnet is a part of the network topology and we assume
+that any particular subnet may have only one definition within this
+network. Each subnet has two unique identifiers: the subnet identifier and the
+subnet prefix. The subnet identifier is used in Kea to uniquely
+identify the subnet within the network and to connect it with other configuration elements,
+e.g. in host reservations. Some commands provided by
+:ischooklib:`libdhcp_cb_cmds.so` allow the subnet
+information to be accessed by either subnet identifier or prefix, and explicitly prohibit
+using the server tag to access the subnet. This is because, in
+general, the subnet definition is associated with multiple servers
+rather than a single server. In fact, it may even be associated
+with no servers (unassigned). Still, the unassigned subnet has an
+identifier and prefix which can be used to access the subnet.
+
+A shareable configuration element may be associated with multiple
+servers, one server, or no servers. Deletion of the server which is
+associated with the shareable element does not cause the deletion of
+the shareable element. It merely deletes the association of the
+deleted server with the element.
+
+Unlike a shareable element, a non-shareable element must not be
+explicitly associated with more than one server and must not exist
+after the server is deleted (must not remain unassigned). A
+non-shareable element only exists within the context of the server.
+An example of a non-shareable element in DHCP is a global
+parameter, e.g. `renew-timer`. The renew timer
+is the value to be used by a particular server and only this
+server. Other servers may have their respective renew timers
+set to the same or different values. The renew timer
+parameter has no unique identifier by which it could be
+accessed, modified, or otherwise used. Global parameters like
+the renew timer can be accessed by the parameter name and the
+tag of the server for which they are configured. For example, the
+:isccmd:`remote-global-parameter4-get` and
+:isccmd:`remote-global-parameter6-get` commands allow
+the value of the global parameter to be fetched by the parameter name and
+the server name. Getting the global parameter only by its name (without
+specifying the server tag) is not possible, because there may be many
+global parameters with a given name in the database.
+
+When the server associated with a non-shareable configuration element
+is deleted, the configuration element is automatically deleted from
+the database along with the server because the non-shareable element
+must be always assigned to a server (or the logical server `all`).
+
+The terms "shareable" and "non-shareable" only apply to associations
+with user-defined servers; all configuration elements associated with
+the logical server `all` are by definition shareable. For example: the
+`renew-timer` associated with `all` servers is used
+by all servers connecting to the database which do not have their specific
+renew timers defined. In a special case, when none of the configuration
+elements are associated with user-defined servers, the entire
+configuration in the database is shareable because all its pieces
+belong to `all` servers.
+
+.. note::
+
+ Be very careful when associating configuration elements with
+ different server tags. The configuration backend does not protect
+ against some possible misconfigurations that may arise from the
+ wrong server tags' assignments. For example: if a shared
+ network is assigned to one server and the subnets belonging to this shared network
+ to another server, the servers will fail upon trying to fetch and
+ use this configuration. The server fetching the subnets will be
+ aware that the subnets are associated with the shared network, but
+ the shared network will not be found by this server since it doesn't
+ belong to it. In such a case, both the shared network and the subnets
+ should be assigned to the same set of servers.
diff --git a/doc/sphinx/arm/config-templates.rst b/doc/sphinx/arm/config-templates.rst
new file mode 100644
index 0000000..caff036
--- /dev/null
+++ b/doc/sphinx/arm/config-templates.rst
@@ -0,0 +1,74 @@
+.. _config-templates:
+
+Configuration Templates
+=======================
+
+The following sections include configuration templates for
+certain deployment types. The example configuration files are also available in the Kea sources,
+in the ``doc/examples`` directory.
+
+.. include:: template-power-user-home.md
+
+Some tweaking of these templates may be required to match specific system needs: at a
+minimum, the lines highlighted in yellow must be adjusted to match the actual deployment.
+
+Server1's Control Agent configuration file:
+
+.. literalinclude:: template-power-user-home-ca-1.conf
+ :language: javascript
+ :emphasize-lines: 9, 12
+ :linenos:
+
+Server1's DHCPv4 configuration file:
+
+.. literalinclude:: template-power-user-home-dhcp4-1.conf
+ :language: javascript
+ :emphasize-lines: 25, 79, 84, 124, 136, 151, 155, 158-162, 170-184, 194-203
+ :linenos:
+
+Server2's Control Agent configuration file:
+
+.. literalinclude:: template-power-user-home-ca-2.conf
+ :language: javascript
+ :emphasize-lines: 9, 12
+ :linenos:
+
+Server2's DHCPv4 configuration file:
+
+.. literalinclude:: template-power-user-home-dhcp4-2.conf
+ :language: javascript
+ :emphasize-lines: 25, 79, 84, 124, 136, 151, 155, 158-162, 170-184, 194-203
+ :linenos:
+
+.. include:: template-ha-mt-tls.md
+
+Some tweaking of these templates may be required to match specific system needs: at a
+minimum, the lines highlighted in yellow must be adjusted to match the actual deployment.
+
+Server1's Control Agent configuration file:
+
+.. literalinclude:: template-ha-mt-tls-ca-1.conf
+ :language: javascript
+ :emphasize-lines: 10, 14, 18, 21, 24, 36
+ :linenos:
+
+Server1's DHCPv4 configuration file:
+
+.. literalinclude:: template-ha-mt-tls-dhcp4-1.conf
+ :language: javascript
+ :emphasize-lines: 25, 38-54, 98, 103, 139-152, 161, 163, 165, 167, 181, 183, 185, 187, 204, 208, 211-215
+ :linenos:
+
+Server2's Control Agent configuration file:
+
+.. literalinclude:: template-ha-mt-tls-ca-2.conf
+ :language: javascript
+ :emphasize-lines: 10, 14, 18, 21, 24, 36
+ :linenos:
+
+Server2's DHCPv4 configuration file:
+
+.. literalinclude:: template-ha-mt-tls-dhcp4-2.conf
+ :language: javascript
+ :emphasize-lines: 25, 38-54, 98, 103, 139-152, 161, 163, 165, 167, 181, 183, 185, 187, 204, 208, 211-215
+ :linenos:
diff --git a/doc/sphinx/arm/config.rst b/doc/sphinx/arm/config.rst
new file mode 100644
index 0000000..46833a3
--- /dev/null
+++ b/doc/sphinx/arm/config.rst
@@ -0,0 +1,339 @@
+.. _kea-config:
+
+*****************
+Kea Configuration
+*****************
+
+Kea uses JSON structures to represent server configurations. The
+following sections describe how the configuration structures are
+organized.
+
+.. _json:
+
+JSON Configuration
+==================
+
+JSON is the notation used throughout the Kea project. The most obvious
+usage is for the configuration file, but JSON is also used for sending
+commands over the Management API (see :ref:`ctrl-channel`) and for
+communicating between DHCP servers and the DDNS update daemon.
+
+Typical usage assumes that the servers are started from the command
+line, either directly or using a script, e.g. :iscman:`keactrl`. The
+configuration file is specified upon startup using the ``-c`` parameter.
+
+.. _json-format:
+
+JSON Syntax
+-----------
+
+Configuration files for the DHCPv4, DHCPv6, DDNS, Control Agent, and
+NETCONF modules are defined in an extended JSON format. Basic JSON is
+defined in `RFC 7159 <https://tools.ietf.org/html/rfc7159>`__ and `ECMA
+404 <https://www.ecma-international.org/publications/standards/Ecma-404.htm>`__.
+In particular, the only boolean values allowed are true or false (all
+lowercase). The capitalized versions (True or False) are not accepted.
+
+Even though the JSON standard (ECMA 404) does not require JSON objects
+(i.e. name/value maps) to have unique entries, Kea implements them
+using a C++ STL map with unique entries. Therefore, if there are multiple
+values for the same name in an object/map, the last value overwrites previous values.
+Since Kea 1.9.0, configuration file parsers raise a syntax error in such cases.
+
+Kea components use extended JSON with additional features allowed:
+
+- Shell comments: any text after the hash (#) character is ignored.
+
+- C comments: any text after the double slashes (//) character is
+ ignored.
+
+- Multiline comments: any text between /\* and \*/ is ignored. This
+ comment can span multiple lines.
+
+- File inclusion: JSON files can include other JSON files by using a
+ statement of the form \<?include "file.json"?\>.
+
+- Extra commas: to remove the inconvenience of errors caused by leftover commas
+ after making changes to configuration. While parsing, a warning is printed
+ with the location of the comma to give the user the ability to correct a
+ potential mistake.
+
+.. warning::
+
+ These features are meant to be used in a JSON configuration file.
+ Their usage in any other way may result in errors.
+
+The configuration file consists of a single object (often colloquially
+called a map) started with a curly bracket. It comprises only one of
+the "Dhcp4", "Dhcp6", "DhcpDdns", "Control-agent", or "Netconf" objects.
+It is possible to define additional elements but they will be ignored.
+
+A very simple configuration for DHCPv4 could look like this:
+
+::
+
+ # The whole configuration starts here.
+ {
+ # DHCPv4 specific configuration starts here.
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth0" ],
+ "dhcp-socket-type": "raw"
+ },
+ "valid-lifetime": 4000,
+ "renew-timer": 1000,
+ "rebind-timer": 2000,
+ "subnet4": [{
+ "pools": [ { "pool": "192.0.2.1-192.0.2.200" } ],
+ "subnet": "192.0.2.0/24",
+ "id": 1
+ }],
+
+ # Now loggers are inside the DHCPv4 object.
+ "loggers": [{
+ "name": "*",
+ "severity": "DEBUG"
+ }]
+ }
+
+ # The whole configuration structure ends here.
+ }
+
+More examples are available in the installed ``share/doc/kea/examples``
+directory.
+
+To avoid repetition of mostly similar structures, examples in the rest
+of this guide will showcase only the subset of parameters appropriate
+for a given context. For example, when discussing the IPv6 subnets
+configuration in DHCPv6, only subnet6 parameters will be mentioned. It
+is implied that the remaining elements (the global map that holds Dhcp6)
+are present, but they are omitted for clarity. Usually,
+locations where extra parameters may appear are denoted by an ellipsis
+(...).
+
+.. _user-context:
+
+Comments and User Context
+-------------------------
+
+Shell, C, or C++ style comments are all permitted in the JSON configuration file if
+the file is used locally. This is convenient and works in simple cases where
+the configuration is kept statically using a local file. However, since comments
+are not part of JSON syntax, most JSON tools detect them as
+errors. Another problem with them is that once Kea loads its configuration, the
+shell, C, and C++ style comments are ignored. If commands such as
+:isccmd:`config-get` or :isccmd:`config-write` are used, those comments are lost. An example of such
+comments was presented in the previous section.
+
+Historically, to address the problem, Kea code allowed the use of `comment` strings
+as valid JSON entities. This had the benefit of being retained through various
+operations (such as :isccmd:`config-get`), or allowing processing by JSON tools. An
+example JSON comment looks like this:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [{ "pool": "192.0.2.10 - 192.0.2.20" }],
+ "comment": "second floor"
+ }]
+ }
+
+However, the facts that the comment could only be a single line, and that it was not
+possible to add any other information in a more structured form, were frustrating. One specific
+example was a request to add floor levels and building numbers to subnets. This
+was one of the reasons why the concept of user context was introduced. It
+allows adding an arbitrary JSON structure to most Kea configuration structures.
+
+This has a number of benefits compared to earlier approaches. First, it is fully
+compatible with JSON tools and Kea commands. Second, it allows storing simple
+comment strings, but it can also store much more complex data, such as
+multiple lines (as a string array), extra typed data (such as floor numbers being
+actual numbers), and more. Third, the data is exposed to hooks, so it is possible
+to develop third-party hooks that take advantage of that extra information. An
+example user context looks like this:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [{ "pool": "192.0.2.10 - 192.0.2.20" }],
+ "user-context": {
+ "comment": "second floor",
+ "floor": 2
+ }
+ }]
+ }
+
+User contexts can store an arbitrary data file as long as it has valid JSON
+syntax and its top-level element is a map (i.e. the data must be enclosed in
+curly brackets). However, some hook libraries may expect specific formatting;
+please consult the specific hook library documentation for details.
+
+In a sense the user-context mechanism has superseded the JSON comment
+capabilities; ISC encourages administrators to use user-context instead of
+the older mechanisms. To promote this way of storing comments, Kea compared
+converts JSON comments to user-context on the fly.
+
+However, if the configuration uses the old JSON
+comment, the :isccmd:`config-get` command returns a slightly modified
+configuration. It is not uncommon for a call for :isccmd:`config-set` followed by a
+:isccmd:`config-get` to receive a slightly different structure.
+The best way to avoid this problem is simply to abandon JSON comments and
+use user-context.
+
+Kea supports user contexts at the following levels: global scope,
+interfaces configuration, shared networks,
+subnets, client classes, option data and definitions, host
+reservations, control socket, DHCP-DDNS, loggers, leases, and server ID. These
+are supported in both DHCPv4 and DHCPv6, with the exception of server ID,
+which is DHCPv6 only.
+
+User context can be added and edited in structures supported by commands.
+
+We encourage Kea users to utilize these functions to store information
+used by other systems and custom hooks.
+
+For example, the :isccmd:`subnet4-update` command can be used to add user context data
+to an existing subnet.
+
+::
+
+ {
+ "subnet4": [ {
+ "id": 1,
+ "subnet": "10.20.30.0/24",
+ "user-context": {
+ "building": "Main",
+ "floor": 1
+ }
+ } ]
+ }
+
+The same can be done with many other commands, like :isccmd:`lease6-add`, etc.
+
+Kea also uses user context to store non-standard data.
+Currently, only :ref:`dhcp4-store-extended-info` uses this feature.
+
+When enabled, it adds the ISC key in ``user-context`` to differentiate automatically
+added content.
+
+Example of relay information stored in a lease:
+
+::
+
+ {
+ "arguments": {
+ "client-id": "42:42:42:42:42:42:42:42",
+ "cltt": 12345678,
+ "fqdn-fwd": false,
+ "fqdn-rev": true,
+ "hostname": "myhost.example.com.",
+ "hw-address": "08:08:08:08:08:08",
+ "ip-address": "192.0.2.1",
+ "state": 0,
+ "subnet-id": 44,
+ "valid-lft": 3600,
+ "user-context": {
+ "ISC": {
+ "relays": [
+ {
+ "hop": 2,
+ "link": "2001:db8::1",
+ "peer": "2001:db8::2"
+ },
+ {
+ "hop": 1,
+ "link": "2001:db8::3",
+ "options": "0x00C800080102030405060708",
+ "peer": "2001:db8::4"
+ }]
+ }
+ }
+ }
+ }
+
+
+User context can store configuration for multiple hooks and comments at once.
+
+For a discussion about user context used in hooks, see :ref:`user-context-hooks`.
+
+
+Simplified Notation
+-------------------
+
+It is sometimes convenient to refer to a specific element in the
+configuration hierarchy. Each hierarchy level is separated by a slash.
+If there is an array, a specific instance within that array is
+referenced by a number in square brackets (with numbering starting at
+zero). For example, in the above configuration the valid-lifetime in the
+Dhcp4 component can be referred to as Dhcp4/valid-lifetime, and the pool
+in the first subnet defined in the DHCPv4 configuration as
+Dhcp4/subnet4[0]/pool.
+
+
+.. include:: config-backend.rst
+
+
+Configuration Files Inclusion
+-----------------------------
+
+The parser provides the ability to include files. The syntax was chosen
+to look similar to how Apache includes PHP scripts in HTML code. This particular
+syntax was chosen to emphasize that the include directive is an additional
+feature and not a part of JSON syntax.
+
+The inclusion is implemented as a stack of files. You can use the include directive
+in nested includes. Up to ten nesting levels are supported. This arbitrarily chosen
+limit is protection against recursive inclusions.
+
+The include directive has the form:
+
+::
+
+ <?include "[PATH]"?>
+
+The *[PATH]* pattern should be replaced with an absolute path or a path relative to
+the current working directory at the time the Kea process was launched.
+
+To include one file from another, use the following syntax:
+
+.. code-block:: javascript
+
+ {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "*" ]},
+ "preferred-lifetime": 3000,
+ "rebind-timer": 2000,
+ "renew-timer": 1000,
+ <?include "subnets.json"?>
+ "valid-lifetime": 4000
+ }
+ }
+
+where the content of "subnets.json" may be:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "id": 123,
+ "subnet": "192.0.2.0/24"
+ },
+ {
+ "id": 234,
+ "subnet": "192.0.3.0/24"
+ },
+ {
+ "id": 345,
+ "subnet": "10.0.0.0/8"
+ }
+ ],
+ ...
+ }
diff --git a/doc/sphinx/arm/congestion-handling.rst b/doc/sphinx/arm/congestion-handling.rst
new file mode 100644
index 0000000..68b7913
--- /dev/null
+++ b/doc/sphinx/arm/congestion-handling.rst
@@ -0,0 +1,129 @@
+.. _congestion-handling:
+
+*******************
+Congestion Handling
+*******************
+
+.. _congestion-handling-background:
+
+What is Congestion?
+===================
+
+Congestion occurs when servers are subjected to client queries faster
+than those queries can be processed. As a result, the servers begin accumulating
+a backlog of pending queries. The longer the high rate of traffic
+continues, the farther behind the servers fall. Depending on the client
+implementations, those that fail to get leases either give up or simply
+continue to retry forever. In the former case, the server may eventually
+recover, but the latter case is a vicious cycle from which the server is
+unable to escape.
+
+Congestion typically occurs when there is a network event that causes overly large
+numbers of clients to simultaneously need leases, such as recovery after
+a network outage. In a well-planned deployment, the number and capacity of servers is
+matched to the maximum expected client load. If the load is routinely too
+heavy, then the deployment needs to be re-evaluated.
+
+The goal of congestion handling is to help servers mitigate the peak in
+traffic by fulfilling as many of the most relevant requests as possible
+until the congestion subsides.
+
+.. _congestion-handling-solution:
+
+Configuring Congestion Handling
+===============================
+
+Congestion handling
+offers the ability to configure the server to use a separate thread to
+read packets from the interface socket buffers. As the thread reads
+packets from the buffers, they are added to an internal packet queue,
+and the server's main application thread processes packets from this
+queue rather than from the socket buffers. By structuring it this way, a
+configurable layer has been introduced which can make decisions on which
+packets to process, how to store them, and the order in which they are
+processed by the server.
+
+The default packet queue implementation for both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`
+is a simple ring buffer. Once it reaches capacity, new packets get added
+to the back of the queue by discarding packets from the front of the
+queue. Rather than always discarding the newest packets, Kea now always
+discards the oldest packets. The capacity of the buffer, i.e. the maximum
+number of packets the buffer can contain, is configurable. A reasonable
+starting point is to match the capacity to the number of leases
+per second a specific installation of Kea can handle. This
+figure varies widely depending on the specifics of an individual deployment.
+
+As there is no one algorithm that can best handle the dynamics of all
+sites, and because over time new approaches will evolve, the packet
+queue is implemented as a plug-in, which can be replaced by a custom queue
+implementation via a hook library. This should make it straightforward
+for interested parties to experiment with their own solutions.
+(Developers can refer to ``isc::dhcp::PacketQueue`` and
+``isc::dhcp::PacketQueueMgr``, described in the
+`Kea Developer's Guide <https://reports.kea.isc.org/dev_guide/index.html>`__.)
+
+Packet queue behavior is configured in both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`
+servers through an optional, top-level, configuration element,
+``dhcp-queue-control``. Omitting this element disables packet queueing:
+
+::
+
+ "dhcp-queue-control": {
+ "enable-queue": true, // true|false
+ "queue-type": "queue type",
+ "capacity" : 256 // n packets
+ }
+
+where:
+
+- ``enable-queue`` - enables or disables packet queueing.
+ When ``true``, the server processes packets from the packet queue, which
+ is filled by a separate thread. When ``false``, the server processes
+ packets directly from the socket buffers in the main thread. It is
+ disabled (``false``) by default.
+
+- ``queue-type`` - the name of the queue implementation to use. This value
+ exists so that custom implementations can be registered (via a hook
+ library) and then selected. There is a default packet queue
+ implementation that is pre-registered during server start up:
+ "kea-ring4" for :iscman:`kea-dhcp4` and "kea-ring6" for :iscman:`kea-dhcp6`.
+
+- ``capacity`` - this is the maximum number of packets the
+ queue can hold before packets are discarded. The optimal value for
+ this is extremely site-dependent. The default value is 64 for both
+ "kea-ring4" and "kea-ring6".
+
+The following example enables the default packet queue for :iscman:`kea-dhcp4`,
+with a queue capacity of 250 packets:
+
+::
+
+ "Dhcp4":
+ {
+ "dhcp-queue-control": {
+ "enable-queue": true,
+ "queue-type": "kea-ring4",
+ "capacity" : 250
+ },
+ ...
+ }
+
+The following example enables the default packet queue for :iscman:`kea-dhcp6`,
+with a queue capacity of 300 packets:
+
+::
+
+ "Dhcp6":
+ {
+ "dhcp-queue-control": {
+ "enable-queue": true,
+ "queue-type": "kea-ring6",
+ "capacity" : 300
+ },
+ ...
+ }
+
+.. note::
+
+ Congestion handling is currently incompatible with multi-threading;
+ when both are enabled, congestion handling is silently disabled.
diff --git a/doc/sphinx/arm/ctrl-channel.rst b/doc/sphinx/arm/ctrl-channel.rst
new file mode 100644
index 0000000..b6a5cd8
--- /dev/null
+++ b/doc/sphinx/arm/ctrl-channel.rst
@@ -0,0 +1,906 @@
+.. _ctrl-channel:
+
+**************
+Management API
+**************
+
+A classic approach to daemon configuration assumes that the server's
+configuration is stored in configuration files and, when the
+configuration is changed, the daemon is restarted. This approach has the
+significant disadvantage of introducing periods of downtime when client
+traffic is not handled. Another risk is that if the new configuration is
+invalid for any reason, the server may refuse to start, which will
+further extend the downtime period until the issue is resolved.
+
+To avoid such problems, the DHCPv4, DHCPv6, and D2 servers in Kea include
+support for a mechanism that allows online reconfiguration without
+requiring server shutdown. Both servers can be instructed to open
+control sockets, which is a communications channel. The server is able
+to receive commands on that channel, act on them, and report back
+status.
+
+The DHCPv4, DHCPv6, and D2 servers receive commands over the UNIX domain
+sockets. For details on how to configure these sockets, see
+:ref:`dhcp4-ctrl-channel` and :ref:`dhcp6-ctrl-channel`. While
+it is possible to control the servers directly using UNIX domain sockets,
+that requires that the controlling client be running on the same machine
+as the server. SSH is usually used to connect remotely to the controlled
+machine.
+
+Network administrators usually prefer using some form of a RESTful API
+to control the servers, rather than using UNIX domain sockets directly.
+Therefore, Kea includes a component called the Control Agent (CA), which
+exposes a RESTful API to the controlling clients and can forward
+commands to the respective Kea services over the UNIX domain sockets.
+The CA configuration is described in
+:ref:`agent-configuration`.
+
+The HTTP requests received by the CA contain the control commands
+encapsulated within HTTP requests. Simply speaking, the CA is
+responsible for stripping the HTTP layer from the received commands and
+forwarding the commands in a JSON format over the UNIX domain sockets to
+the respective services. Because the CA receives commands for all
+services, it requires additional "forwarding" information to be included
+in the client's messages. This forwarding information is carried within
+the ``service`` parameter of the received command. If the ``service``
+parameter is not included, or if the parameter is a blank list, the CA
+assumes that the control command is targeted at the CA itself and
+attempts to respond.
+
+Control connections over both HTTP and UNIX domain sockets are guarded
+with timeouts. The timeout value is set to 10 seconds and is not
+configurable.
+
+This API can be used by external tools to manage and monitor Kea operation.
+An example of such a monitoring tool is ISC's Stork. For details, see
+:ref:`stork`.
+
+.. _ctrl-channel-syntax:
+
+Data Syntax
+===========
+
+Communication over the control channel is conducted using JSON
+structures. If configured, Kea opens a socket and listens for
+incoming connections. A process connecting to this socket is expected to
+send JSON commands structured as follows:
+
+::
+
+ {
+ "command": "foo",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "param1": "value1",
+ "param2": "value2",
+ ...
+ }
+ }
+
+The same command sent over the RESTful interface to the CA has the
+following structure:
+
+::
+
+ POST / HTTP/1.1\r\n
+ Content-Type: application/json\r\n
+ Content-Length: 147\r\n\r\n
+ {
+ "command": "foo",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "param1": "value1",
+ "param2": "value2",
+ ...
+ }
+ }
+
+The ``command`` parameter contains the name of the command to execute and it
+is mandatory.
+The ``arguments`` map contains the parameters required to carry out the
+given command. The exact content and format of the map are command-specific.
+
+The ``service`` list contains the servers at which the control command is
+targeted. In the example above, the control command is targeted at the
+DHCPv4 server. In most cases, the CA simply forwards this command to
+the DHCPv4 server for processing via a UNIX domain socket. Sometimes,
+the command including a service value may also be processed by the CA,
+if the CA is running a hook library which handles such a command for
+the given server. As an example, the hook library loaded by the CA may
+perform some operations on the database, such as adding host
+reservations, modifying leases, etc. An advantage of performing
+DHCPv4-specific administrative operations in the CA, rather than
+forwarding it to the DHCPv4 server, is the ability to perform these
+operations without disrupting the DHCPv4 service, since the DHCPv4
+server does not have to stop processing DHCP messages to apply changes to
+the database. Nevertheless, these situations are rather rare; in
+most cases, when the ``service`` parameter contains a name of the
+service, the commands are simply forwarded by the CA. The forwarded
+command includes the ``service`` parameter, but this parameter is ignored
+by the receiving server. This parameter is only meaningful to the CA.
+
+If the command received by the CA does not include a ``service``
+parameter or this list is empty, the CA simply processes this message on
+its own. For example, a :isccmd:`config-get` command which includes no service
+parameter returns the Control Agent's own configuration. The :isccmd:`config-get`
+command with a service value "dhcp4" is forwarded to the DHCPv4 server and
+returns the DHCPv4 server's configuration.
+
+The following list shows the mapping of the values carried within the
+``service`` parameter to the servers to which the commands are
+forwarded:
+
+- ``dhcp4`` - the command is forwarded to the :iscman:`kea-dhcp4` server.
+
+- ``dhcp6`` - the command is forwarded to the :iscman:`kea-dhcp6` server.
+
+- ``d2`` - the command is forwarded to the :iscman:`kea-dhcp-ddns` server.
+
+The server processing the incoming command sends a response of the
+form:
+
+::
+
+ {
+ "result": 0, // 0|1|2|3|4
+ "text": "textual description",
+ "arguments": {
+ "argument1": "value1",
+ "argument2": "value2",
+ ...
+ }
+ }
+
+The ``result`` value is a status code indicating a result of the command. The
+following general status codes are currently supported:
+
+- ``0`` - the command has been processed successfully.
+- ``1`` - a general error or failure has occurred during the command processing.
+- ``2`` - the specified command is unsupported by the server receiving it.
+- ``3`` - the requested operation has been completed but the requested
+ resource was not found. This status code is returned when a command
+ returns no resources or affects no resources.
+- ``4`` - the well-formed command has been processed but the requested
+ changes could not be applied, because they were in conflict with the
+ server state or its notion of the configuration.
+
+For example, a well-formed command that requests a subnet that exists
+in a server's configuration returns the result 0. If the server encounters
+an error condition, it returns 1. If the command asks for an IPv6 subnet,
+but was sent to a DHCPv4 server, it returns 2. If the query asks for a
+subnet with ``subnet-id`` that has matches, the result is 3.
+If the command attempts to update a lease but the specified ``subnet-id``
+does not match the identifier in the server's configuration, the result
+is 4.
+
+Hook libraries can sometimes return additional status codes specific
+to their use cases.
+
+The ``text`` field typically appears when the result is non-zero and
+contains a description of the error encountered, but it often also
+appears for successful outcomes. The exact text is command-specific, but
+in general uses plain English to describe the outcome of the command.
+The ``arguments`` map contains additional data values returned by the server
+which are specific to the command issued. The map may be present, but that
+depends on the specific command.
+
+.. note::
+
+ Since Kea 1.9.7, it is possible to put comments in commands as
+ in the configuration file. For instance:
+
+::
+
+ {
+ "command": "foo",
+ // service is a list
+ "service": [ "dhcp4" ],
+ # command arguments are here.
+ "arguments": {
+ "param1": "value1",
+ ...
+ /*
+ "param2": "value2",
+ ...
+ */
+ }
+ }
+
+.. _ctrl-channel-control-agent-command-response-format:
+
+Control Agent Command Response Format
+=====================================
+
+When sending commands via the Control Agent, it is possible to specify
+multiple services at which the command is targeted. CA forwards this
+command to each service individually. Thus, the CA response to the
+controlling client is always wrapped in an array (JSON list) of
+individual responses. For example, the response for a command sent
+to one service would be structured as follows:
+
+::
+
+ [
+ {
+ "result": 0, // 0|1|2|3|4
+ "text": "textual description",
+ "arguments": {
+ "argument1": "value1",
+ "argument2": "value2",
+ ...
+ }
+ }
+ ]
+
+
+If the command is sent to more than one service, the array would
+contain responses from each service, in the order they were requested:
+
+::
+
+ [
+ {
+ "result": 0, // 0|1|2|3|4
+ "text": "textual description",
+ "arguments": {
+ "argument1": "value1",
+ "argument2": "value2",
+ ...
+ }
+ },
+ {
+ "result": 0, // 0|1|2|3|4
+ "text": "textual description",
+ "arguments": {
+ "argument1": "value1",
+ "argument2": "value2",
+ ...
+ }
+ },
+ ...
+ ]
+
+An exception to this are authentication or authorization errors which cause CA
+to reject the command entirely. The response to such an error is formatted
+as a single entry (JSON map) as follows:
+
+::
+
+ {
+ "result": 403,
+ "text": "Forbidden"
+ }
+
+
+These types of errors are possible on systems configured for either basic
+authentication or agents that load :ischooklib:`libca_rbac.so`.
+
+.. _ctrl-channel-client:
+
+Using the Control Channel
+=========================
+
+The easiest way to start interacting with the control API is to use
+common UNIX/Linux tools such as ``socat`` and ``curl``.
+
+In order to control the given Kea service via a UNIX domain socket, use
+``socat`` in interactive mode as follows:
+
+.. code-block:: console
+
+ $ socat UNIX:/path/to/the/kea/socket -
+
+or in batch mode, include the "ignoreeof" option as shown below to
+ensure ``socat`` waits long enough for the server to respond:
+
+.. code-block:: console
+
+ $ echo "{ some command...}" | socat UNIX:/path/to/the/kea/socket -,ignoreeof
+
+where ``/path/to/the/kea/socket`` is the path specified in the
+``Dhcp4/control-socket/socket-name`` parameter in the Kea configuration
+file. Text passed to ``socat`` is sent to Kea and the responses received
+from Kea are printed to standard output. This approach communicates with
+the specific server directly and bypasses the Control Agent.
+
+It is also easy to open a UNIX socket programmatically. An example of a
+simple client written in C is available in the Kea Developer's Guide, in
+the Control Channel Overview chapter, in the
+`Using Control Channel <https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html#ctrlSocketClient>`__
+section.
+
+To use Kea's RESTful API with ``curl``, use the following:
+
+.. code-block:: console
+
+ $ curl -X POST -H "Content-Type: application/json" -d '{ "command": "config-get", "service": [ "dhcp4" ] }' http://ca.example.org:8000/
+
+This assumes that the Control Agent is running on host
+``ca.example.org`` and is running the RESTful service on port 8000.
+
+.. _commands-common:
+
+Commands Supported by Both the DHCPv4 and DHCPv6 Servers
+========================================================
+
+.. isccmd:: build-report
+.. _command-build-report:
+
+The ``build-report`` Command
+----------------------------
+
+The :isccmd:`build-report` command returns on the control channel what the
+command line ``-W`` argument displays, i.e. the embedded content of the
+``config.report`` file. This command does not take any parameters.
+
+::
+
+ {
+ "command": "build-report"
+ }
+
+.. isccmd:: config-get
+.. _command-config-get:
+
+The ``config-get`` Command
+--------------------------
+
+The :isccmd:`config-get` command retrieves the current configuration used by the
+server. This command does not take any parameters. The configuration
+returned is roughly equal to the configuration that was loaded using the
+``-c`` command-line option during server start-up, or was later set using the
+:isccmd:`config-set` command. However, there may be certain differences, as
+comments are not retained. If the original configuration used file
+inclusion, the returned configuration includes all parameters from
+all included files. Starting with 2.4.0, the successful response also
+contains a SHA-256 digest that can be used to easily determine if a
+configuration has changed or not.
+
+.. warning::
+
+ The returned configuration is not redacted, i.e. it
+ contains database passwords in plain text, if those were specified in the
+ original configuration. Care should be taken not to expose the command
+ channel to unprivileged users.
+
+An example command invocation looks like this:
+
+::
+
+ {
+ "command": "config-get"
+ }
+
+.. isccmd:: config-hash-get
+.. _command-config-hash-get:
+
+The ``config-hash-get`` Command
+-------------------------------
+
+The ``config-hash-get`` command retrieves the SHA-256 hash of the current
+configuration used by the server. This command does not take any parameters.
+The returned hash can be used to detect configuration changes.
+
+An example command invocation looks like this:
+
+::
+
+ {
+ "command": "config-hash-get"
+ }
+
+And the server's response:
+
+::
+
+ {
+ "result": 0,
+ "arguments": {
+ "hash": "5C3C90EF7035249E2FF74D003C19F34EE0B83A3D329E741B52B2EF95A2C9CC5C"
+ }
+ }
+
+Starting with 2.4.0, also ``config-set`` and ``config-get`` return the SHA-256 hash
+of the new or current configuration. This may be used to later determine if a configuration
+has changed or not.
+
+.. isccmd:: config-reload
+.. _command-config-reload:
+
+The ``config-reload`` Command
+-----------------------------
+
+The :isccmd:`config-reload` command instructs Kea to load again the
+configuration file that was used previously. This operation is useful if
+the configuration file has been changed by some external source; for
+example, a system administrator can tweak the configuration file and use this
+command to force Kea pick up the changes.
+
+Caution should be taken when mixing this with the :isccmd:`config-set` command. Kea
+remembers the location of the configuration file it was started with,
+and this configuration can be significantly changed using the :isccmd:`config-set`
+command. When :isccmd:`config-reload` is issued after :isccmd:`config-set`, Kea attempts
+to reload its original configuration from the file, possibly losing all
+changes introduced using :isccmd:`config-set` or other commands.
+
+The :isccmd:`config-reload` command does not take any parameters. An example command
+invocation looks like this:
+
+::
+
+ {
+ "command": "config-reload"
+ }
+
+If the configuration file is incorrect, reloading it can raise an error
+which leaves the server in an unusable state. See :ref:`command-config-set`
+to learn how to recover from a non-working server.
+
+.. isccmd:: config-test
+.. _command-config-test:
+
+The ``config-test`` Command
+---------------------------
+
+The :isccmd:`config-test` command instructs the server to check whether the new
+configuration supplied in the command's arguments can be loaded. The
+supplied configuration is expected to be the full configuration for the
+target server, along with an optional logger configuration. The configuration
+is sanity-checked to the extent possible without the server actually
+attempting to load it; it is possible for a configuration which successfully
+passes this command to still fail in the :isccmd:`config-set` command or at launch
+time. The structure of the command is as follows:
+
+::
+
+ {
+ "command": "config-test",
+ "arguments": {
+ "<server>": {
+ }
+ }
+ }
+
+where <server> is the configuration element name for a given server, such
+as "Dhcp4" or "Dhcp6". For example:
+
+::
+
+ {
+ "command": "config-test",
+ "arguments": {
+ "Dhcp6": {
+ ...
+ }
+ }
+ }
+
+The server's response contains a numeric code, ``result`` (0 for
+success, non-zero on failure), and a string, ``text``, describing the
+outcome:
+
+::
+
+ {"result": 0, "text": "Configuration seems sane..." }
+
+ or
+
+ {"result": 1, "text": "unsupported parameter: BOGUS (<string>:16:26)" }
+
+.. isccmd:: config-write
+.. _command-config-write:
+
+The ``config-write`` Command
+----------------------------
+
+The :isccmd:`config-write` command instructs the Kea server to write its current
+configuration to a file on disk. It takes one optional argument, called
+"filename", that specifies the name of the file to write the
+configuration to. If not specified, the name used when starting Kea
+(passed as a ``-c`` argument) is used. If a relative path is specified,
+Kea writes its files only in the directory where it is running.
+
+An example command invocation looks like this:
+
+::
+
+ {
+ "command": "config-write",
+ "arguments": {
+ "filename": "config-modified-2017-03-15.json"
+ }
+ }
+
+.. isccmd:: leases-reclaim
+.. _command-leases-reclaim:
+
+The ``leases-reclaim`` Command
+------------------------------
+
+The :isccmd:`leases-reclaim` command instructs the server to reclaim all expired
+leases immediately. The command has the following JSON syntax:
+
+::
+
+ {
+ "command": "leases-reclaim",
+ "arguments": {
+ "remove": true
+ }
+ }
+
+The ``remove`` boolean parameter is mandatory and indicates whether the
+reclaimed leases should be removed from the lease database (if ``true``), or
+left in the ``expired-reclaimed`` state (if ``false``). The latter facilitates
+lease affinity, i.e. the ability to re-assign an expired lease to a
+returning client that previously used that lease. See :ref:`lease-affinity`
+for details. Also, see :ref:`lease-reclamation` for general
+information about the processing of expired leases (lease reclamation).
+
+.. isccmd:: libreload
+.. _command-libreload:
+
+The ``libreload`` Command
+-------------------------
+
+This command is now deprecated and will be removed in future Kea versions.
+
+The :isccmd:`libreload` command first unloads and then loads all currently
+loaded hook libraries. This is primarily intended to allow one or more
+hook libraries to be replaced with newer versions, without requiring Kea
+servers to be reconfigured or restarted. The hook libraries
+are passed the same parameter values (if any) that were passed when they
+originally loaded.
+
+::
+
+ {
+ "command": "libreload",
+ "arguments": { }
+ }
+
+The server responds with a result of either 0, indicating success,
+or 1, indicating failure.
+
+.. isccmd:: list-commands
+.. _command-list-commands:
+
+The ``list-commands`` Command
+-----------------------------
+
+The :isccmd:`list-commands` command retrieves a list of all commands supported
+by the server. It does not take any arguments. An example command may
+look like this:
+
+::
+
+ {
+ "command": "list-commands",
+ "arguments": { }
+ }
+
+The server responds with a list of all supported commands. The arguments
+element is a list of strings, each of which conveys one supported
+command.
+
+.. isccmd:: config-set
+.. _command-config-set:
+
+The ``config-set`` Command
+--------------------------
+
+The :isccmd:`config-set` command instructs the server to replace its current
+configuration with the new configuration supplied in the command's
+arguments. The supplied configuration is expected to be the full
+configuration for the target server, along with an optional logger
+configuration. While optional, the logger configuration is highly
+recommended, as without it the server reverts to its default logging
+configuration. The structure of the command is as follows:
+
+::
+
+ {
+ "command": "config-set",
+ "arguments": {
+ "<server>": {
+ }
+ }
+ }
+
+where <server> is the configuration element name for a given server, such
+as "Dhcp4" or "Dhcp6". For example:
+
+::
+
+ {
+ "command": "config-set",
+ "arguments": {
+ "Dhcp6": {
+ ...
+ }
+ }
+ }
+
+If the new configuration proves to be invalid, the server retains its
+current configuration; however, in some cases a fatal error message is logged
+indicating that the server is no longer providing any service: a working
+configuration must be loaded as soon as possible. If the control channel
+is dead, the configuration file can still be reloaded using the ``SIGHUP``
+signal. If that is unsuccessful, restart the server.
+
+Please note that the new configuration is
+retained in memory only; if the server is restarted or a configuration
+reload is triggered via a signal, the server uses the configuration
+stored in its configuration file. The server's response contains a
+numeric code, ``result`` (0 for success, non-zero on failure), and a
+string, ``text``, describing the outcome:
+
+::
+
+ {"result": 0, "text": "Configuration successful." }
+
+ or
+
+ {"result": 1, "text": "unsupported parameter: BOGUS (<string>:16:26)" }
+
+Starting with 2.4.0, the successful response from a DHCPv4, DHCPv6, or DHCP-DDNS daemons
+also contain a SHA-256 digest of the newly set configuration. The digest can be used to easily
+determine if a configuration has changed or not.
+
+.. isccmd:: shutdown
+.. _command-shutdown:
+
+The ``shutdown`` Command
+------------------------
+
+The :isccmd:`shutdown` command instructs the server to initiate its shutdown
+procedure. It is the equivalent of sending a ``SIGTERM`` signal to the
+process. This command does not take any arguments. An example command
+may look like this:
+
+::
+
+ {
+ "command": "shutdown",
+ "arguments": {
+ "exit-value": 3
+ }
+ }
+
+The server responds with a confirmation that the shutdown procedure has
+been initiated. The optional parameter, ``exit-value``, specifies the
+numeric value with which the server process exits to the system.
+The default value is zero.
+
+The DDNS daemon supports an extra parameter, ``type``, which controls the way
+the process cleans up on exit. The supported shutdown types are:
+
+ - "normal" - stops the queue manager and finishes all current transactions
+ before exiting. This is the default.
+
+ - "drain_first" - stops the queue manager but continues processing requests
+ from the queue until it is empty.
+
+ - "now" - exits immediately.
+
+An example command may look like this:
+
+::
+
+ {
+ "command": "shutdown",
+ "arguments": {
+ "exit-value": 3,
+ "type": "drain_first"
+ }
+ }
+
+.. isccmd:: dhcp-disable
+.. _command-dhcp-disable:
+
+The ``dhcp-disable`` Command
+----------------------------
+
+The :isccmd:`dhcp-disable` command globally disables the DHCP service. The
+server continues to operate, but it drops all received DHCP messages.
+This command is useful when the server's maintenance requires that the
+server temporarily stop allocating new leases and renew existing leases.
+It is also useful in failover-like configurations during a
+synchronization of the lease databases at startup, or recovery after a
+failure. The optional parameter ``max-period`` specifies the time in
+seconds after which the DHCP service should be automatically re-enabled,
+if the :isccmd:`dhcp-enable` command is not sent before this time elapses.
+
+Since Kea 1.9.4, there is an additional ``origin`` parameter that specifies the
+command source. A server administrator should typically omit this parameter
+because the default value "user" indicates that the administrator sent the
+command. This command can also be sent by the partner server running HA hooks
+library. In that case, the partner server sets the parameter to a unique
+integer identifier of an HA service. The integer values are reserved for the
+communication between HA partners and should not be specified in the
+administrator's commands, as it may interfere with HA operation. The
+administrator should either omit this parameter or set it to "user".
+
+::
+
+ {
+ "command": "dhcp-disable",
+ "arguments": {
+ "max-period": 20,
+ "origin": "user"
+ }
+ }
+
+.. isccmd:: dhcp-enable
+.. _command-dhcp-enable:
+
+The ``dhcp-enable`` Command
+---------------------------
+
+The :isccmd:`dhcp-enable` command globally enables the DHCP service.
+
+Since Kea 1.9.4, there is an additional ``origin`` parameter that specifies the
+command source. A server administrator should typically omit this parameter
+because the default value "user" indicates that the administrator sent the
+command. This command can also be sent by the partner server running the HA hook
+library. In that case, the partner server sets the parameter to a unique
+integer identifier of an HA service. The integer values are reserved for the
+communication between HA partners and should not be specified in the
+administrator's commands, as it may interfere with HA operation. The
+administrator should either omit this parameter or set it to
+"user".
+
+::
+
+ {
+ "command": "dhcp-enable",
+ "arguments": {
+ "origin": "user"
+ }
+ }
+
+.. isccmd:: status-get
+.. _command-status-get:
+
+The ``status-get`` Command
+--------------------------
+
+The :isccmd:`status-get` command returns the server's runtime information:
+
+ - ``pid``: the process ID.
+
+ - ``uptime``: the number of seconds since the start of the server.
+
+ - ``reload``: the number of seconds since the last configuration (re)load.
+
+ - ``high-availability``: HA-specific status information about the DHCP servers
+ configured to use the HA hook library:
+
+ * ``local``: the state, the role (primary,
+ secondary, ...), and the scopes (i.e. what the server is actually
+ processing) of the local server.
+
+ * ``remote``: the remote server's last known state, its served
+ HA scopes, and the role of the remote server in the HA relationship.
+
+ - ``multi-threading-enabled``: a flag indicating whether multi-threading is enabled.
+
+ - ``thread-pool-size``: the number of DHCP service threads.
+
+ - ``packet-queue-size``: the maximum size of the packet queue. There is one queue,
+ regardless of the number of running threads.
+
+ - ``packet-queue-statistics``: the average queue size for the last 10, 100, and 1000
+ packets, using an approach similar to the UNIX ``top`` command.
+ The average queue size for the last 10 packets can be considered an
+ instantaneous value, while the average for the last 1000 packets shows
+ a longer-term trend.
+
+The ``high-availability`` information is returned only when the command is
+sent to the DHCP servers in an HA setup. This parameter is
+never returned when the :isccmd:`status-get` command is sent to the
+Control Agent or DDNS daemon.
+
+The ``thread-pool-size``, ``packet-queue-size`` and
+``packet-queue-statistics`` parameters are returned only when the
+command is sent to DHCP servers with multi-threading enabled. These
+three parameters and ``multi-threading-enabled`` are never returned when
+the :isccmd:`status-get` command is sent to the Control Agent or DDNS daemon.
+
+To learn more about the HA status information returned by the
+:isccmd:`status-get` command, please refer to the :ref:`command-ha-status-get`
+section.
+
+
+.. isccmd:: server-tag-get
+.. _command-server-tag-get:
+
+The ``server-tag-get`` Command:
+-------------------------------
+
+The :isccmd:`server-tag-get` command returns the configured server tag of
+the DHCPv4 or DHCPv6 server (:ref:`cb-sharing` explains the server tag concept).
+
+.. isccmd:: config-backend-pull
+.. _command-config-backend-pull:
+
+The ``config-backend-pull`` Command:
+------------------------------------
+
+The :isccmd:`config-backend-pull` command triggers the polling of configuration backends
+(which must be configured for this command to have an effect),
+explained in :ref:`dhcp4-cb-json`.
+
+.. isccmd:: version-get
+.. _command-version-get:
+
+The ``version-get`` Command
+---------------------------
+
+The :isccmd:`version-get` command returns extended information about the Kea
+version. It is the same information available via the ``-V``
+command-line argument. This command does not take any parameters.
+
+::
+
+ {
+ "command": "version-get"
+ }
+
+Commands Supported by the D2 Server
+===================================
+
+The D2 server supports only a subset of the DHCPv4/DHCPv6 server commands:
+
+- :isccmd:`build-report`
+
+- :isccmd:`config-get`
+
+- :isccmd:`config-hash-get`
+
+- :isccmd:`config-reload`
+
+- :isccmd:`config-set`
+
+- :isccmd:`config-test`
+
+- :isccmd:`config-write`
+
+- :isccmd:`list-commands`
+
+- :isccmd:`shutdown`
+
+- :isccmd:`status-get`
+
+- :isccmd:`version-get`
+
+.. _agent-commands:
+
+Commands Supported by the Control Agent
+=======================================
+
+The following commands, listed in :ref:`commands-common`, are also supported by the
+Control Agent; when the ``service`` parameter is blank, the
+commands are handled by the CA and they relate to the CA process itself:
+
+- :isccmd:`build-report`
+
+- :isccmd:`config-get`
+
+- :isccmd:`config-hash-get`
+
+- :isccmd:`config-reload`
+
+- :isccmd:`config-set`
+
+- :isccmd:`config-test`
+
+- :isccmd:`config-write`
+
+- :isccmd:`list-commands`
+
+- :isccmd:`shutdown`
+
+- :isccmd:`status-get`
+
+- :isccmd:`version-get`
diff --git a/doc/sphinx/arm/database-connectivity.rst b/doc/sphinx/arm/database-connectivity.rst
new file mode 100644
index 0000000..8d61d64
--- /dev/null
+++ b/doc/sphinx/arm/database-connectivity.rst
@@ -0,0 +1,104 @@
+.. _database-connectivity:
+
+*********************
+Database Connectivity
+*********************
+
+The Kea servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`) can be configured to use a variety of
+database backends for leases, hosts, and configuration. They can be
+configured to support automatic recovery when connectivity is lost, via
+the ``on-fail`` and ``retry-on-startup`` parameters.
+(The ``reconnect-wait-time`` and ``max-reconnect-tries`` parameters are
+described in :ref:`database-configuration4` and :ref:`database-configuration6`.)
+
+It is important to understand how and when automatic recovery comes into play.
+Automatic recovery, when configured, only operates after a successful startup
+or reconfiguration during which connectivity to all backends has been
+successfully established.
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
+Database connection retries are not attempted on startup if the
+:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a
+valid connection to the database to check if JSON format is supported and to
+recount class limits.
+
+During dynamic reconfiguration, all backends are disconnected and then
+reconnected using the new configuration. If connectivity to any of the
+backends cannot be established, the server logs a fatal error but remains
+up. It is able to process commands but does not serve clients. This
+allows the configuration to be corrected via the :isccmd:`config-set` or
+``remote-*`` commands, if required.
+
+During normal operations, if connectivity to any of the backends is lost and
+automatic recovery for that backend is enabled, the server disconnects from the
+respective backend and then attempts to reconnect. During the recovery process,
+the server ceases to serve clients according to the ``on-fail`` configured
+option but continues to respond to commands.
+
+The ``on-fail`` parameter configures the actions the server should take when a
+connection is lost. It can have one of the following values:
+
+- ``stop-retry-exit`` - indicates that the server should stop the service
+ while it tries to recover the connection, and exit if recovery is not
+ successful after ``max-reconnect-tries``.
+
+- ``serve-retry-exit`` - indicates that the server should not stop the
+ service while it tries to recover the connection, and exit if recovery is not
+ successful after ``max-reconnect-tries``.
+
+- ``serve-retry-continue`` - indicates that the server should not stop the
+ service while it tries to recover the connection, and not exit if recovery is
+ not successful after ``max-reconnect-tries``.
+
+If connectivity to all backends is restored, the server returns to normal
+operations. If the connection cannot be restored and the server is configured
+to exit, it issues a fatal error before shutdown.
+
+For Kea DHCP servers to work with database backends, the schema has to be
+created and has to have the version specific to the version of the running Kea
+server. If the version check fails on a database backend that is not configured
+as readonly, Kea attempts to initialize the schema.
+
+.. note::
+
+ Schema upgrades are not attempted to not accidentally remove the
+ opportunity for prior administrative actions that users may be interested in,
+ like, for example, backing up the database or temporarily shutting off running
+ Kea servers that are currently operating on the database.
+
+The connection to the database server can optionally be protected by TLS.
+Corresponding database configuration parameters for Kea servers are:
+
+- The ``trust-anchor`` specifies the Certification Authority file name or
+ directory path.
+
+- The ``cert-file`` specifies the client certificate file name.
+
+- The ``key-file`` specifies the private key file name.
+
+- The ``cipher-list`` specifies the list of TLS ciphers (the syntax of
+ the content of this parameter is described in the OpenSSL ciphers
+ manual).
+
+These parameters are similar to the parameters of the secure connections
+with the agent but are interpreted by different backends using database
+configurations too.
+
+Currently the support for each database is:
+
+- MySQL supports the whole set, additional configuration must be done
+ in the MySQL local setup, for instance certificate revocation list,
+ choice of a specific TLS version, mutual authentication, etc.
+ When a TLS connection was required but the actual connection is in
+ clear text an error log is emitted.
+
+- PostgreSQL only uses the configuration to enable the SSL/TLS support
+ in the client library (libpq). Anything else must be done in the
+ PostgreSQL local configuration.
diff --git a/doc/sphinx/arm/ddns.rst b/doc/sphinx/arm/ddns.rst
new file mode 100644
index 0000000..9b3464e
--- /dev/null
+++ b/doc/sphinx/arm/ddns.rst
@@ -0,0 +1,1027 @@
+.. _dhcp-ddns-server:
+
+********************
+The DHCP-DDNS Server
+********************
+
+.. _dhcp-ddns-overview:
+
+Overview
+========
+
+The DHCP-DDNS Server (:iscman:`kea-dhcp-ddns`, known informally as D2) conducts
+the client side of the Dynamic DNS protocol (DDNS, defined in `RFC
+2136 <https://tools.ietf.org/html/rfc2136>`__) on behalf of the DHCPv4
+and DHCPv6 servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` respectively).
+The DHCP servers construct DDNS update requests, known as NameChangeRequests
+(NCRs), based on DHCP lease change events and then post them to D2. D2
+attempts to match each request to the appropriate DNS server(s) and
+carries out the necessary conversation with those servers to update the
+DNS data.
+
+For the ability to generate host names procedurally, based on an expression, and
+for the ability to skip DDNS updates on a per-client basis, or fine-tuning
+various DNS update aspects, the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` can
+load the premium hook library `libdhcp_ddns_tuning.so` which is available from
+ISC. Please refer to :ref:`hooks-ddns-tuning` documentation for the
+configuration options.
+
+.. _dhcp-ddns-dns-server-selection:
+
+DNS Server Selection
+--------------------
+
+To match a request to the appropriate DNS servers, D2 must have
+a catalog of servers from which to select. In fact, D2 has two such
+catalogs, one for forward DNS and one for reverse DNS; these catalogs
+are referred to as "DDNS domain lists." Each list consists of one or more
+named DDNS domains. Further, each DDNS domain has a list of one or more
+DNS servers that publish the DNS data for that domain.
+
+When conducting forward-domain matching, D2 compares the fully qualified
+domain name (FQDN) in the request against the name of each forward DDNS
+domain in its catalog. The domain whose name matches the longest portion
+of the FQDN is considered the best match. For example, if the FQDN is
+"myhost.sample.example.com.", and there are two forward domains in the
+catalog, "sample.example.com." and "example.com.", the former is
+regarded as the best match. In some cases, it may not be possible to
+find a suitable match. Given the same two forward domains there would be
+no match for the FQDN "bogus.net", so the request would be rejected.
+Finally, if there are no forward DDNS domains defined, D2 simply
+disregards the forward-update portion of requests.
+
+When conducting reverse-domain matching, D2 constructs a reverse FQDN
+from the lease address in the request and compares that against the name
+of each reverse DDNS domain. Again, the domain whose name matches the
+longest portion of the FQDN is considered the best match. For instance,
+if the lease address is "172.16.1.40" and there are two reverse domains
+in the catalog, "1.16.172.in-addr.arpa." and "16.172.in-addr.arpa", the
+former is the best match. As with forward matching, D2 may not find a
+suitable match. Given the same two domains, there would be no match for
+the lease address, "192.168.1.50", and the request would be rejected.
+As with forward-domain matching, if there are no reverse DDNS domains defined, D2 simply
+disregards the reverse-update portion of requests.
+
+.. _dhcp-ddns-conflict-resolution:
+
+Conflict Resolution
+-------------------
+
+D2 implements the conflict resolution strategy prescribed by `RFC
+4703 <https://tools.ietf.org/html/rfc4703>`__. Conflict resolution is
+intended to prevent different clients from mapping to the same FQDN at
+the same time. To make this possible, the RFC requires that forward DNS
+entries for a given FQDN must be accompanied by a DHCID resource record
+(RR). This record contains a client identifier that uniquely identifies
+the client to whom the name belongs. Furthermore, any DNS updater that
+wishes to update or remove existing forward entries for an FQDN may only
+do so if their client matches that of the DHCID RR.
+
+In other words, the DHCID RR maps an FQDN to the client to whom it
+belongs, and thereafter changes to that mapping can only be done by
+or at the behest of that client.
+
+Conflict resolution can be indirectly enabled or disabled via
+the configuration parameter ``ddns-use-conflict-resolution``, supported
+by both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. These servers use this parameter to
+set a flag within each NameChangeRequest they send that tells D2
+whether conflict resolution should be employed for that request.
+By default, conflict resolution is enabled. For more details, please refer
+to discussions of ``ddns-use-conflict-resolution`` in :ref:`dhcp4-ddns-config` and :ref:`dhcp6-ddns-config`.
+
+When conflict resolution is disabled, D2 still adds DHCID RRs but does
+not use them to enforce client ownership of DNS entries. Disabling it should
+only be used after careful consideration.
+
+.. _dhcp-ddns-dual-stack:
+
+Dual-Stack Environments
+-----------------------
+
+`RFC 4703, section
+5.2, <https://tools.ietf.org/html/rfc4703#section-5.2>`__ describes
+issues that may arise with dual-stack clients. These are clients that
+wish to have both IPv4 and IPv6 mappings for the same FQDN.
+To work properly, clients must embed their IPv6 DUID
+within their IPv4 client identifier option, as described in `RFC
+4361 <https://tools.ietf.org/html/rfc4361>`__. In this way, DNS updates
+for both IPv4 and IPv6 can be managed under the same DHCID RR. This feature
+is supported by Kea beginning with release 2.1.2.
+
+.. _dhcp-ddns-server-start-stop:
+
+Starting and Stopping the DHCP-DDNS Server
+==========================================
+
+:iscman:`kea-dhcp-ddns` is the Kea DHCP-DDNS server and, due to the nature of
+DDNS, it runs alongside either the DHCPv4 or DHCPv6 component (or both).
+Like other parts of Kea, it is a separate binary that can be run on its
+own or through :iscman:`keactrl` (see :ref:`keactrl`). In normal
+operation, controlling :iscman:`kea-dhcp-ddns` with :iscman:`keactrl` is
+recommended; however, it is also possible to run the DHCP-DDNS server
+directly. It accepts the following command-line switches:
+
+- ``-c file`` - specifies the configuration file. This is the only
+ mandatory switch.
+
+- ``-d`` - specifies whether server logging should be switched to
+ debug/verbose mode. In verbose mode, the logging severity and
+ debuglevel specified in the configuration file are ignored and
+ "debug" severity and the maximum debuglevel (99) are assumed. The
+ flag is convenient for temporarily switching the server into maximum
+ verbosity, e.g. when debugging.
+
+- ``-v`` - displays the Kea version and exits.
+
+- ``-W`` - displays the Kea configuration report and exits. The report
+ is a copy of the ``config.report`` file produced by ``./configure``;
+ it is embedded in the executable binary.
+
+- ``-t file`` - specifies the configuration file to be tested.
+ :iscman:`kea-dhcp-ddns` attempts to load it and conducts sanity checks.
+ Certain checks are possible only while running the actual
+ server. The actual status is reported with an exit code (0 =
+ configuration looks okay, 1 = error encountered). Kea prints out log
+ messages to standard output and errors to standard error when testing
+ the configuration.
+
+ The contents of the ``config.report`` file may also be accessed by examining
+ certain libraries in the installation tree or in the source tree.
+
+ .. code-block:: shell
+
+ # from installation using libkea-process.so
+ $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.so
+ $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.a
+ $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
+
+ # from sources using libcfgrpt.a
+ $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
+
+Upon startup, the module loads its configuration and begins listening
+for NCRs based on that configuration.
+
+During startup, the server attempts to create a PID file of the form:
+``[runstatedir]/[conf name].kea-dhcp-ddns.pid`` where:
+
+- ``runstatedir`` - is the value as passed into the build configure
+ script; it defaults to "/usr/local/var/run". Note that this value may be
+ overridden at runtime by setting the environment variable
+ ``KEA_PIDFILE_DIR``. This is intended primarily for testing purposes.
+
+- ``conf name`` - is the configuration file name used to start the server,
+ minus all preceding paths and the file extension. For example, given
+ a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would
+ be "myconf".
+
+If the file already exists and contains the PID of a live process, the
+server issues a ``DHCP_DDNS_ALREADY_RUNNING`` log message and exits. It
+is possible, though unlikely, that the file is a remnant of a system
+crash and the process to which the PID belongs is unrelated to Kea. In
+such a case it is necessary to manually delete the PID file.
+
+.. _d2-configuration:
+
+Configuring the DHCP-DDNS Server
+================================
+
+Before starting the :iscman:`kea-dhcp-ddns` module for the first time, a
+configuration file must be created. The following default configuration
+is a template that can be customized to individual requirements.
+
+::
+
+ "DhcpDdns": {
+ "ip-address": "127.0.0.1",
+ "port": 53001,
+ "dns-server-timeout": 500,
+ "ncr-protocol": "UDP",
+ "ncr-format": "JSON",
+ "tsig-keys": [ ],
+ "forward-ddns": {
+ "ddns-domains": [ ]
+ },
+ "reverse-ddns": {
+ "ddns-domains": [ ]
+ }
+ }
+
+The configuration can be divided into the following sections, each of
+which is described below:
+
+- *Global Server Parameters* - define values which control connectivity and
+ global server behavior.
+
+- *Control Socket* - defines the Control Socket type and name.
+
+- *TSIG Key Info* - defines the TSIG keys used for secure traffic with
+ DNS servers.
+
+- *Forward DDNS* - defines the catalog of forward DDNS domains.
+
+- *Reverse DDNS* - defines the catalog of reverse DDNS domains.
+
+.. _d2-server-parameter-config:
+
+Global Server Parameters
+------------------------
+
+- ``ip-address`` - the IP address on which D2 listens for requests. The
+ default is the local loopback interface at address 127.0.0.1.
+ Either an IPv4 or IPv6 address may be specified.
+
+- ``port`` - the port on which D2 listens for requests. The default value
+ is 53001.
+
+- ``dns-server-timeout`` - the maximum amount of time, in milliseconds,
+ that D2 will wait for a response from a DNS server to a single DNS
+ update message. The default is 500 ms.
+
+- ``ncr-protocol`` - the socket protocol to use when sending requests to
+ D2. Currently only UDP is supported.
+
+- ``ncr-format`` - the packet format to use when sending requests to D2.
+ Currently only JSON format is supported.
+
+D2 must listen for change requests on a known address and port. By
+default it listens at 127.0.0.1 on port 53001. The following example
+illustrates how to change D2's global parameters so it will listen at
+192.168.1.10 port 900:
+
+::
+
+ "DhcpDdns": {
+ "ip-address": "192.168.1.10",
+ "port": 900,
+ ...
+ }
+
+.. warning::
+
+ It is possible for a malicious attacker to send bogus
+ NameChangeRequests to the DHCP-DDNS server. Addresses other than the
+ IPv4 or IPv6 loopback addresses (127.0.0.1 or ::1) should only be
+ used for testing purposes; note that local users may still
+ communicate with the DHCP-DDNS server.
+
+.. note::
+
+ If the ``ip-address`` and ``port`` are changed, the corresponding values in
+ the DHCP servers' ``dhcp-ddns`` configuration section must be changed.
+
+.. _d2-ctrl-channel:
+
+Management API for the D2 Server
+--------------------------------
+
+The management API allows the issuing of specific management commands,
+such as configuration retrieval or shutdown. For more details, see
+:ref:`ctrl-channel`. Currently, the only supported communication
+channel type is the UNIX stream socket. By default there are no sockets
+open; to instruct Kea to open a socket, the following entry in the
+configuration file can be used:
+
+::
+
+ "DhcpDdns": {
+ "control-socket": {
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket"
+ },
+ ...
+ }
+
+The length of the path specified by the ``socket-name`` parameter is
+restricted by the maximum length for the UNIX socket name on the
+operating system, i.e. the size of the ``sun_path`` field in the
+``sockaddr_un`` structure, decreased by 1. This value varies on
+different operating systems, between 91 and 107 characters. Typical
+values are 107 on Linux and 103 on FreeBSD.
+
+Communication over the control channel is conducted using JSON structures.
+See the `Control Channel section in the Kea Developer's
+Guide <https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__
+for more details.
+
+The D2 server supports the following operational commands:
+
+- :isccmd:`build-report`
+- :isccmd:`config-get`
+- :isccmd:`config-hash-get`
+- :isccmd:`config-reload`
+- :isccmd:`config-set`
+- :isccmd:`config-test`
+- :isccmd:`config-write`
+- :isccmd:`list-commands`
+- :isccmd:`shutdown`
+- :isccmd:`status-get`
+- :isccmd:`version-get`
+
+Since Kea version 2.0.0, the D2 server also supports the following
+operational commands for statistics:
+
+- :isccmd:`statistic-get`
+- :isccmd:`statistic-get`-all
+- :isccmd:`statistic-reset`
+- :isccmd:`statistic-reset`-all
+
+The :isccmd:`shutdown` command supports the extra ``type`` argument, which controls the
+way the D2 server cleans up on exit.
+The supported shutdown types are:
+
+- ``normal`` - stops the queue manager and finishes all current transactions
+ before exiting. This is the default.
+
+- ``drain_first`` - stops the queue manager but continues processing requests
+ from the queue until it is empty.
+
+- ``now`` - exits immediately.
+
+An example command may look like this:
+
+::
+
+ {
+ "command": "shutdown",
+ "arguments": {
+ "exit-value": 3,
+ "type": "drain_first"
+ }
+ }
+
+.. _d2-tsig-key-list-config:
+
+TSIG Key List
+-------------
+
+A DDNS protocol exchange can be conducted with or without a transaction
+signature, or TSIG (defined
+in `RFC 2845 <https://tools.ietf.org/html/rfc2845>`__). This
+configuration section allows the administrator to define the set of TSIG
+keys that may be used in such exchanges.
+
+To use TSIG when updating entries in a DNS domain, a key must be defined
+in the TSIG key list and referenced by name in that domain's
+configuration entry. When D2 matches a change request to a domain, it
+checks whether the domain has a TSIG key associated with it. If so, D2
+uses that key to sign DNS update messages sent to and verify
+responses received from the domain's DNS server(s). For each TSIG key
+required by the DNS servers that D2 is working with, there must be
+a corresponding TSIG key in the TSIG key list.
+
+As one might gather from the name, the ``tsig-key`` section of the D2
+configuration lists the TSIG keys. Each entry describes a TSIG key used
+by one or more DNS servers to authenticate requests and sign responses.
+Every entry in the list has three parameters:
+
+- ``name`` - is a unique text label used to identify this key within the
+ list. This value is used to specify which key (if any) should be used
+ when updating a specific domain. As long as the name is unique its
+ content is arbitrary, although for clarity and ease of maintenance it
+ is recommended that it match the name used on the DNS server(s). This
+ field cannot be blank.
+
+- ``algorithm`` - specifies which hashing algorithm should be used with
+ this key. This value must specify the same algorithm used for the key
+ on the DNS server(s). The supported algorithms are listed below:
+
+ - HMAC-MD5
+ - HMAC-SHA1
+ - HMAC-SHA224
+ - HMAC-SHA256
+ - HMAC-SHA384
+ - HMAC-SHA512
+
+ This value is not case-sensitive.
+
+- ``digest-bits`` - is used to specify the minimum truncated length in
+ bits. The default value 0 means truncation is forbidden; non-zero
+ values must be an integral number of octets, and be greater than both
+ 80 and half of the full length. (Note that in BIND 9 this parameter
+ is appended to the algorithm name, after a dash.)
+
+- ``secret`` - is used to specify the shared secret key code for this
+ key. This value is case-sensitive and must exactly match the value
+ specified on the DNS server(s). It is a base64-encoded text value.
+
+As an example, suppose that a domain D2 will be updating is maintained
+by a BIND 9 DNS server, which requires dynamic updates to be secured
+with TSIG. Suppose further that the entry for the TSIG key in BIND 9's
+named.conf file looks like this:
+
+::
+
+ :
+ key "key.four.example.com." {
+ algorithm hmac-sha224;
+ secret "bZEG7Ow8OgAUPfLWV3aAUQ==";
+ };
+ :
+
+By default, the TSIG key list is empty:
+
+::
+
+ "DhcpDdns": {
+ "tsig-keys": [ ],
+ ...
+ }
+
+A new key must be added to the list:
+
+::
+
+ "DhcpDdns": {
+ "tsig-keys": [
+ {
+ "name": "key.four.example.com.",
+ "algorithm": "HMAC-SHA224",
+ "secret": "bZEG7Ow8OgAUPfLWV3aAUQ=="
+ }
+ ],
+ ...
+ }
+
+These steps must be repeated for each TSIG key needed, although the
+same TSIG key can be used with more than one domain.
+
+.. _d2-forward-ddns-config:
+
+Forward DDNS
+------------
+
+The forward DDNS section is used to configure D2's forward-update
+behavior. Currently it contains a single parameter, the catalog of
+forward DDNS domains, which is a list of structures.
+
+::
+
+ "DhcpDdns": {
+ "forward-ddns": {
+ "ddns-domains": [ ]
+ },
+ ...
+ }
+
+By default, this list is empty, which causes the server to ignore
+the forward-update portions of requests.
+
+.. _add-forward-ddns-domain:
+
+Adding Forward DDNS Domains
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A forward DDNS domain maps a forward DNS zone to a set of DNS servers
+which maintain the forward DNS data (i.e. name-to-address mapping) for
+that zone. Each zone served needs one forward DDNS domain.
+Some or all of the zones may be maintained by the same
+servers, but one DDNS domain is still needed for each zone. Remember that
+matching a request to the appropriate server(s) is done by zone and a
+DDNS domain only defines a single zone.
+
+This section describes how to add forward DDNS domains; repeat these
+steps for each forward DDNS domain desired. Each forward DDNS domain has
+the following parameters:
+
+- ``name`` - this is the fully qualified domain name (or zone) that this DDNS
+ domain can update. This value is compared against the request FQDN
+ during forward matching. It must be unique within the catalog.
+
+- ``key-name`` - if TSIG is used with this domain's servers, this value
+ should be the name of the key from the TSIG key list. If the
+ value is blank (the default), TSIG will not be used in DDNS
+ conversations with this domain's servers.
+
+- ``dns-servers`` - this is a list of one or more DNS servers which can conduct
+ the server side of the DDNS protocol for this domain. The servers are
+ used in a first-to-last preference; in other words, when D2 begins to
+ process a request for this domain, it will pick the first server in
+ this list and attempt to communicate with it. If that attempt fails,
+ D2 will move to the next one in the list and so on, until either it
+ is successful or the list is exhausted.
+
+To create a new forward DDNS domain, add a new domain element and set
+its parameters:
+
+::
+
+ "DhcpDdns": {
+ "forward-ddns": {
+ "ddns-domains": [
+ {
+ "name": "other.example.com.",
+ "key-name": "",
+ "dns-servers": [
+ ]
+ }
+ ]
+ }
+ }
+
+It is possible to add a domain without any servers; however, if that
+domain matches a request, the request will fail. To make the domain
+useful, at least one DNS server must be added to it.
+
+.. _add-forward-dns-servers:
+
+Adding Forward DNS Servers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section describes how to add DNS servers to a forward DDNS domain.
+Repeat these instructions as needed for all the servers in each domain.
+
+Forward DNS server entries represent actual DNS servers which support
+the server side of the DDNS protocol. Each forward DNS server has the
+following parameters:
+
+- ``hostname`` - the resolvable host name of the DNS server; this
+ parameter is not yet implemented.
+
+- ``ip-address`` - the IP address at which the server listens for DDNS
+ requests. This may be either an IPv4 or an IPv6 address.
+
+- ``port`` - the port on which the server listens for DDNS requests. It
+ defaults to the standard DNS service port of 53.
+
+To create a new forward DNS server, a new server element must be added to
+the domain and its parameters filled in. If, for example, the service is
+running at "172.88.99.10", set the forward DNS server as follows:
+
+::
+
+ "DhcpDdns": {
+ "forward-ddns": {
+ "ddns-domains": [
+ {
+ "name": "other.example.com.",
+ "key-name": "",
+ "dns-servers": [
+ {
+ "ip-address": "172.88.99.10",
+ "port": 53
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ Since ``hostname`` is not yet supported, the parameter ``ip-address``
+ must be set to the address of the DNS server.
+
+.. _d2-reverse-ddns-config:
+
+Reverse DDNS
+------------
+
+The reverse DDNS section is used to configure D2's reverse update
+behavior, and the concepts are the same as for the forward DDNS section.
+Currently it contains a single parameter, the catalog of reverse DDNS
+domains, which is a list of structures.
+
+::
+
+ "DhcpDdns": {
+ "reverse-ddns": {
+ "ddns-domains": [ ]
+ },
+ ...
+ }
+
+By default, this list is empty, which causes the server to ignore
+the reverse-update portions of requests.
+
+.. _add-reverse-ddns-domain:
+
+Adding Reverse DDNS Domains
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A reverse DDNS domain maps a reverse DNS zone to a set of DNS servers
+which maintain the reverse DNS data (address-to-name mapping) for that
+zone. Each zone served needs one reverse DDNS domain.
+Some or all of the zones may be maintained by the same servers, but
+one DDNS domain entry is needed for each zone. Remember that
+matching a request to the appropriate server(s) is done by zone and a
+DDNS domain only defines a single zone.
+
+This section describes how to add reverse DDNS domains; repeat these
+steps for each reverse DDNS domain desired. Each reverse DDNS domain has
+the following parameters:
+
+- ``name`` - this is the fully qualified reverse zone that this DDNS domain can
+ update. This is the value used during reverse matching, which
+ compares it with a reversed version of the request's lease address.
+ The zone name should follow the appropriate standards; for example,
+ to support the IPv4 subnet 172.16.1, the name should be
+ "1.16.172.in-addr.arpa.". Similarly, to support an IPv6 subnet of
+ 2001:db8:1, the name should be "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa."
+ The name must be unique within the catalog.
+
+- ``key-name`` - if TSIG is used with this domain's servers,
+ this value should be the name of the key from the TSIG key list. If
+ the value is blank (the default), TSIG will not be used in DDNS
+ conversations with this domain's servers.
+
+- ``dns-servers`` - this is a list of one or more DNS servers which can conduct
+ the server side of the DDNS protocol for this domain. Currently, the
+ servers are used in a first-to-last preference; in other words, when
+ D2 begins to process a request for this domain, it will pick the
+ first server in this list and attempt to communicate with it. If that
+ attempt fails, D2 will move to the next one in the list and so on,
+ until either it is successful or the list is exhausted.
+
+To create a new reverse DDNS domain, a new domain element must be added
+and its parameters set. For example, to support subnet 2001:db8:1::, the
+following configuration could be used:
+
+::
+
+ "DhcpDdns": {
+ "reverse-ddns": {
+ "ddns-domains": [
+ {
+ "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
+ "key-name": "",
+ "dns-servers": [
+ ]
+ }
+ ]
+ }
+ }
+
+It is possible to add a domain without any servers; however, if that
+domain matches a request, the request will fail. To make the domain
+useful, at least one DNS server must be added to it.
+
+.. _add-reverse-dns-servers:
+
+Adding Reverse DNS Servers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section describes how to add DNS servers to a reverse DDNS domain.
+Repeat these instructions as needed for all the servers in each domain.
+
+Reverse DNS server entries represent actual DNS servers which support
+the server side of the DDNS protocol. Each reverse DNS server has the
+following parameters:
+
+- ``hostname`` - the resolvable host name of the DNS server; this value
+ is currently ignored.
+
+- ``ip-address`` - the IP address at which the server listens for DDNS
+ requests.
+
+- ``port`` - the port on which the server listens for DDNS requests. It
+ defaults to the standard DNS service port of 53.
+
+To create a new reverse DNS server, a new server
+element must be added to the domain and its parameters specified. If, for example, the
+service is running at "172.88.99.10", then set it as follows:
+
+::
+
+ "DhcpDdns": {
+ "reverse-ddns": {
+ "ddns-domains": [
+ {
+ "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
+ "key-name": "",
+ "dns-servers": [
+ {
+ "ip-address": "172.88.99.10",
+ "port": 53
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ Since ``hostname`` is not yet supported, the parameter ``ip-address``
+ must be set to the address of the DNS server.
+
+.. _per-server-keys:
+
+Per-DNS-Server TSIG Keys
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since Kea version 2.0.0, a TSIG key can be specified in a DNS server
+configuration. The priority rule is:
+
+- if a not-empty key name is specified in a DNS server entry, this TSIG
+ key protects DNS updates sent to this server.
+
+- if the DNS server entry is empty, but a
+ not-empty key name is specified in the parent's domain entry, the parent domain's
+ TSIG key protects DNS updates sent to this server.
+
+- if the DNS server entry is empty, and no key name is specified in its parent
+ domain entry, no TSIG protects DNS updates sent to this server.
+
+For instance, in this configuration:
+
+::
+
+ "DhcpDdns": {
+ "forward-ddns": {
+ "ddns-domains": [
+ {
+ "name": "other.example.com.",
+ "key-name": "foo",
+ "dns-servers": [
+ {
+ "ip-address": "172.88.99.10",
+ "port": 53
+ },
+ {
+ "ip-address": "172.88.99.11",
+ "port": 53,
+ "key-name": "bar"
+ }
+ ]
+ }
+ ]
+ },
+ "reverse-ddns": {
+ "ddns-domains": [
+ {
+ "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
+ "dns-servers": [
+ {
+ "ip-address": "172.88.99.12",
+ "port": 53
+ },
+ {
+ "ip-address": "172.88.99.13",
+ "port": 53,
+ "key-name": "bar"
+ }
+ ]
+ }
+ ]
+ },
+ "tsig-keys": [
+ {
+ "name": "foo",
+ "algorithm": "HMAC-MD5",
+ "secret": "LSWXnfkKZjdPJI5QxlpnfQ=="
+ },
+ {
+ "name": "bar",
+ "algorithm": "HMAC-SHA224",
+ "secret": "bZEG7Ow8OgAUPfLWV3aAUQ=="
+ }
+ ]
+ }
+
+
+The 172.88.99.10 server will use the "foo" TSIG key, the 172.88.99.11 and
+172.88.99.13 servers will use the "bar" key. and 172.88.99.12 will not use TSIG.
+
+.. _d2-user-contexts:
+
+User Contexts in DDNS
+---------------------
+
+See :ref:`user-context` for additional background regarding the user
+context idea.
+
+User contexts can be specified on a global scope, a DDNS domain, a DNS server,
+a TSIG key, and loggers. One other useful usage is the ability to store
+comments or descriptions; the parser translates a "comment" entry into a
+user context with the entry, which allows a comment to be attached
+inside the configuration itself.
+
+.. _d2-example-config:
+
+Example DHCP-DDNS Server Configuration
+--------------------------------------
+
+This section provides a sample DHCP-DDNS server configuration, based on
+a small example network. Let's suppose our example network has three
+domains, each with their own subnet.
+
+.. table:: Our example network
+
+ +------------------+-----------------+-----------------+-----------------+
+ | Domain | Subnet | Forward DNS | Reverse DNS |
+ | | | Servers | Servers |
+ +==================+=================+=================+=================+
+ | four.example.com | 192.0.2.0/24 | 172.16.1.5, | 172.16.1.5, |
+ | | | 172.16.2.5 | 172.16.2.5 |
+ +------------------+-----------------+-----------------+-----------------+
+ | six.example.com | 2001:db8:1::/64 | 3001:1::50 | 3001:1::51 |
+ +------------------+-----------------+-----------------+-----------------+
+ | example.com | 192.0.0.0/16 | 172.16.2.5 | 172.16.2.5 |
+ +------------------+-----------------+-----------------+-----------------+
+
+We need to construct three forward DDNS domains:
+
+.. table:: Forward DDNS domains needed
+
+ +----+-------------------+------------------------+
+ | # | DDNS Domain Name | DNS Servers |
+ +====+===================+========================+
+ | 1. | four.example.com. | 172.16.1.5, 172.16.2.5 |
+ +----+-------------------+------------------------+
+ | 2. | six.example.com. | 3001:1::50 |
+ +----+-------------------+------------------------+
+ | 3. | example.com. | 172.16.2.5 |
+ +----+-------------------+------------------------+
+
+As discussed earlier, FQDN-to-domain matching is based on the longest
+match. The FQDN "myhost.four.example.com." matches the first domain
+("four.example.com"), while "admin.example.com." matches the third
+domain ("example.com"). The FQDN "other.example.net." fails to
+match any domain and is rejected.
+
+The following example configuration specifies the forward DDNS domains.
+
+::
+
+ "DhcpDdns": {
+ "comment": "example configuration: forward part",
+ "forward-ddns": {
+ "ddns-domains": [
+ {
+ "name": "four.example.com.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "172.16.1.5" },
+ { "ip-address": "172.16.2.5" }
+ ]
+ },
+ {
+ "name": "six.example.com.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "2001:db8::1" }
+ ]
+ },
+ {
+ "name": "example.com.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "172.16.2.5" }
+ ],
+ "user-context": { "backup": false }
+ },
+ ...
+ ]
+ }
+ }
+
+Similarly, we need to construct the three reverse DDNS domains:
+
+.. table:: Reverse DDNS domains needed
+
+ +----+-----------------------------------+------------------------+
+ | # | DDNS Domain Name | DNS Servers |
+ +====+===================================+========================+
+ | 1. | 2.0.192.in-addr.arpa. | 172.16.1.5, 172.16.2.5 |
+ +----+-----------------------------------+------------------------+
+ | 2. | 1.0.0.0.8.d.b.0.1.0.0.2.ip6.arpa. | 3001:1::50 |
+ +----+-----------------------------------+------------------------+
+ | 3. | 0.182.in-addr.arpa. | 172.16.2.5 |
+ +----+-----------------------------------+------------------------+
+
+An address of "192.0.2.150" matches the first domain,
+"2001:db8:1::10" matches the second domain, and "192.0.50.77" matches the
+third domain.
+
+These reverse DDNS domains are specified as follows:
+
+::
+
+ "DhcpDdns": {
+ "comment": "example configuration: reverse part",
+ "reverse-ddns": {
+ "ddns-domains": [
+ {
+ "name": "2.0.192.in-addr.arpa.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "172.16.1.5" },
+ { "ip-address": "172.16.2.5" }
+ ]
+ },
+ {
+ "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "2001:db8::1" }
+ ]
+ },
+ {
+ "name": "0.192.in-addr.arpa.",
+ "key-name": "",
+ "dns-servers": [
+ { "ip-address": "172.16.2.5" }
+ ]
+ },
+ ...
+ ]
+ }
+ }
+
+DHCP-DDNS Server Statistics
+===========================
+
+Kea version 2.0.0 introduced statistics support for DHCP-DDNS.
+
+Statistics are divided into three groups: NameChangeRequests, DNS updates,
+and per-TSIG-key DNS updates. While the statistics of the first two groups
+are cumulative, i.e. not affected by configuration change or reload,
+per-key statistics are reset to 0 when the underlying object is
+(re)created.
+
+Currently Kea's statistics management has the following limitations:
+
+- only integer samples (i.e. a counter and a timestamp) are used;
+- the maximum sample count is 1;
+- there is no API to remove one or all statistics;
+- there is no API to set the maximum sample count or age.
+
+.. note::
+
+ Hook libraries, such as the ISC subscriber-only GSS-TSIG library,
+ make new statistics available in Kea.
+
+More information about Kea statistics can be found at :ref:`stats`.
+
+NCR Statistics
+--------------
+
+The NameChangeRequest statistics are:
+
+- ``ncr-received`` - the number of received valid NCRs
+- ``ncr-invalid`` - the number of received invalid NCRs
+- ``ncr-error`` - the number of errors in NCR receptions other than an I/O cancel on shutdown
+
+DNS Update Statistics
+---------------------
+
+The global DNS update statistics are:
+
+- ``update-sent`` - the number of DNS updates sent
+- ``update-signed`` - the number of DNS updates sent and protected by TSIG
+- ``update-unsigned`` - the number of DNS updates sent and not protected by TSIG
+- ``update-success`` - the number of DNS updates which successfully completed
+- ``update-timeout`` - the number of DNS updates which completed on timeout
+- ``update-error`` - the number of DNS updates which completed with an error other than
+ timeout
+
+Per-TSIG-Key DNS Update Statistics
+----------------------------------
+
+The per TSIG key DNS update statistics are:
+
+- ``update-sent`` - the number of DNS updates sent
+- ``update-success`` - the number of DNS updates which successfully completed
+- ``update-timeout`` - the number of DNS updates which completed on timeout
+- ``update-error`` - the number of DNS updates which completed with an error other than
+ timeout
+
+The name format for per-key statistics is ``key[<key-DNS-name>].<stat-name>``:
+for instance, the name of the ``update-sent`` statistics for the
+``key.example.com.`` TSIG key is ``key[key.example.com.].update-sent``.
+
+DHCP-DDNS Server Limitations
+============================
+
+The following are the current limitations of the DHCP-DDNS server.
+
+- Requests received from the DHCP servers are placed in a queue until
+ they are processed. Currently, all queued requests are lost if the
+ server shuts down.
+
+Supported Standards
+===================
+
+The following RFCs are supported by the DHCP-DDNS server:
+
+- *Secret Key Transaction Authentication for DNS (TSIG)*, `RFC 2845
+ <https://tools.ietf.org/html/rfc2845>`__: All DNS update packets sent and
+ received by the DHCP-DDNS server can be protected by TSIG signatures.
+
+- *Dynamic Updates in the Domain Name System (DNS UPDATE)*, `RFC 2136
+ <https://tools.ietf.org/html/rfc2136>`__: The complete DNS update mechanism is
+ supported.
+
+- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host
+ Configuration Protocol (DHCP) Clients*, `RFC 4703
+ <https://tools.ietf.org/html/rfc4703>`__: DHCP-DDNS takes care of
+ conflict resolution, for both DHCPv4 and DHCPv6 servers.
+
+- *A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol
+ (DHCP) Information (DHCID RR)*, `RFC 4701
+ <https://tools.ietf.org/html/rfc4701>`__: The DHCP-DDNS server uses DHCID
+ records.
diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst
new file mode 100644
index 0000000..eea2648
--- /dev/null
+++ b/doc/sphinx/arm/dhcp4-srv.rst
@@ -0,0 +1,8455 @@
+.. _dhcp4:
+
+*****************
+The DHCPv4 Server
+*****************
+
+.. _dhcp4-start-stop:
+
+Starting and Stopping the DHCPv4 Server
+=======================================
+
+It is recommended that the Kea DHCPv4 server be started and stopped
+using :iscman:`keactrl` (described in :ref:`keactrl`); however, it is also
+possible to run the server directly via the :iscman:`kea-dhcp4` command, which accepts
+the following command-line switches:
+
+- ``-c file`` - specifies the configuration file. This is the only
+ mandatory switch.
+
+- ``-d`` - specifies whether the server logging should be switched to
+ debug/verbose mode. In verbose mode, the logging severity and debuglevel
+ specified in the configuration file are ignored; "debug" severity
+ and the maximum debuglevel (99) are assumed. The flag is convenient
+ for temporarily switching the server into maximum verbosity, e.g.
+ when debugging.
+
+- ``-p server-port`` - specifies the local UDP port on which the server
+ listens. This is only useful during testing, as a DHCPv4 server
+ listening on ports other than the standard ones is not able to
+ handle regular DHCPv4 queries.
+
+- ``-P client-port`` - specifies the remote UDP port to which the
+ server sends all responses. This is only useful during testing,
+ as a DHCPv4 server sending responses to ports other than the standard
+ ones is not able to handle regular DHCPv4 queries.
+
+- ``-t file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp4`
+ loads it, checks it, and exits. During the test, log messages are
+ printed to standard output and error messages to standard error. The
+ result of the test is reported through the exit code (0 =
+ configuration looks OK, 1 = error encountered). The check is not
+ comprehensive; certain checks are possible only when running the
+ server.
+
+- ``-T file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp4`
+ loads it, checks it, and exits. It performs extra checks beyond what ``-t``
+ offers, such as establishing database connections (for the lease backend,
+ host reservations backend, configuration backend, and forensic logging
+ backend), loading hook libraries, parsing hook-library configurations, etc.
+ It does not open UNIX or TCP/UDP sockets, nor does it open or rotate
+ files, as any of these actions could interfere with a running process on the
+ same machine.
+
+- ``-v`` - displays the Kea version and exits.
+
+- ``-V`` - displays the Kea extended version with additional parameters
+ and exits. The listing includes the versions of the libraries
+ dynamically linked to Kea.
+
+- ``-W`` - displays the Kea configuration report and exits. The report
+ is a copy of the ``config.report`` file produced by ``./configure``;
+ it is embedded in the executable binary.
+
+ The contents of the ``config.report`` file may also be accessed by examining
+ certain libraries in the installation tree or in the source tree.
+
+ .. code-block:: shell
+
+ # from installation using libkea-process.so
+ $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.so
+ $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.a
+ $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
+
+ # from sources using libcfgrpt.a
+ $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
+
+On startup, the server detects available network interfaces and
+attempts to open UDP sockets on all interfaces listed in the
+configuration file. Since the DHCPv4 server opens privileged ports, it
+requires root access; this daemon must be run as root.
+
+During startup, the server attempts to create a PID file of the
+form: ``[runstatedir]/kea/[conf name].kea-dhcp4.pid``, where:
+
+- ``runstatedir``: The value as passed into the build configure
+ script; it defaults to ``/usr/local/var/run``. Note that this value may be
+ overridden at runtime by setting the environment variable
+ ``KEA_PIDFILE_DIR``, although this is intended primarily for testing
+ purposes.
+
+- ``conf name``: The configuration file name used to start the server,
+ minus all preceding paths and the file extension. For example, given
+ a pathname of ``/usr/local/etc/kea/myconf.txt``, the portion used would
+ be ``myconf``.
+
+If the file already exists and contains the PID of a live process, the
+server issues a ``DHCP4_ALREADY_RUNNING`` log message and exits. It is
+possible, though unlikely, that the file is a remnant of a system crash
+and the process to which the PID belongs is unrelated to Kea. In such a
+case, it would be necessary to manually delete the PID file.
+
+The server can be stopped using the ``kill`` command. When running in a
+console, the server can also be shut down by pressing Ctrl-c. Kea detects
+the key combination and shuts down gracefully.
+
+The reconfiguration of each Kea server is triggered by the SIGHUP signal.
+When a server receives the SIGHUP signal it rereads its configuration file and,
+if the new configuration is valid, uses the new configuration.
+If the new configuration proves to be invalid, the server retains its
+current configuration; however, in some cases a fatal error message is logged
+indicating that the server is no longer providing any service: a working
+configuration must be loaded as soon as possible.
+
+.. _dhcp4-configuration:
+
+DHCPv4 Server Configuration
+===========================
+
+Introduction
+------------
+
+This section explains how to configure the Kea DHCPv4 server using a
+configuration file.
+
+Before DHCPv4 is started, its configuration file must
+be created. The basic configuration is as follows:
+
+::
+
+ {
+ # DHCPv4 configuration starts on the next line
+ "Dhcp4": {
+
+ # First we set up global values
+ "valid-lifetime": 4000,
+ "renew-timer": 1000,
+ "rebind-timer": 2000,
+
+ # Next we set up the interfaces to be used by the server.
+ "interfaces-config": {
+ "interfaces": [ "eth0" ]
+ },
+
+ # And we specify the type of lease database
+ "lease-database": {
+ "type": "memfile",
+ "persist": true,
+ "name": "/var/lib/kea/dhcp4.leases"
+ },
+
+ # Finally, we list the subnets from which we will be leasing addresses.
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.1 - 192.0.2.200"
+ }
+ ]
+ }
+ ]
+ # DHCPv4 configuration ends with the next line
+ }
+
+ }
+
+The following paragraphs provide a brief overview of the parameters in
+the above example, along with their format. Subsequent sections of this
+chapter go into much greater detail for these and other parameters.
+
+The lines starting with a hash (#) are comments and are ignored by the
+server; they do not impact its operation in any way.
+
+The configuration starts in the first line with the initial opening
+curly bracket (or brace). Each configuration must contain an object
+specifying the configuration of the Kea module using it. In the example
+above, this object is called ``Dhcp4``.
+
+The ``Dhcp4`` configuration starts with the ``"Dhcp4": {`` line and ends
+with the corresponding closing brace (in the above example, the brace
+after the last comment). Everything defined between those lines is
+considered to be the ``Dhcp4`` configuration.
+
+In general, the order in which those parameters appear does not
+matter, but there are two caveats. The first one is that the
+configuration file must be well-formed JSON, meaning that the
+parameters for any given scope must be separated by a comma, and there
+must not be a comma after the last parameter. When reordering a
+configuration file, moving a parameter to or from the
+last position in a given scope may also require moving the comma. The
+second caveat is that it is uncommon — although legal JSON — to repeat
+the same parameter multiple times. If that happens, the last occurrence
+of a given parameter in a given scope is used, while all previous
+instances are ignored. This is unlikely to cause any confusion as there
+are no real-life reasons to keep multiple copies of the same parameter
+in the configuration file.
+
+The first few DHCPv4 configuration elements
+define some global parameters. ``valid-lifetime`` defines how long the
+addresses (leases) given out by the server are valid; the default
+is for a client to be allowed to use a given address for 4000
+seconds. (Note that integer numbers are specified as is, without any
+quotes around them.) ``renew-timer`` and ``rebind-timer`` are values
+(also in seconds) that define the T1 and T2 timers that govern when the
+client begins the renewal and rebind processes.
+
+.. note::
+
+ The lease valid lifetime is expressed as a triplet with minimum, default, and
+ maximum values using configuration entries
+ ``min-valid-lifetime``, ``valid-lifetime``, and ``max-valid-lifetime``.
+ Since Kea 1.9.5, these values may be specified in client classes. The procedure
+ the server uses to select which lifetime value to use is as follows:
+
+ If the client query is a BOOTP query, the server always uses the
+ infinite lease time (e.g. 0xffffffff). Otherwise, the server must
+ determine which configured triplet to use by first searching all
+ classes assigned to the query, and then the subnet selected for
+ the query.
+
+ Classes are searched in the order they were assigned to the query; the
+ server uses the triplet from the first class that specifies it.
+ If no classes specify the triplet, the server uses the triplet
+ specified by the subnet selected for the client. If the subnet does not
+ explicitly specify it, the server next looks at the subnet's
+ shared-network (if one exists), then for a global specification, and
+ finally the global default.
+
+ If the client requested a lifetime value via DHCP option 51, then the
+ lifetime value used is the requested value bounded by the configured
+ triplet. In other words, if the requested lifetime is less than the
+ configured minimum, the configured minimum is used; if it is more
+ than the configured maximum, the configured maximum is used. If
+ the client did not provide a requested value, the lifetime value used
+ is the triplet default value.
+
+.. note::
+
+ Both ``renew-timer`` and ``rebind-timer``
+ are optional. The server only sends ``rebind-timer`` to the client,
+ via DHCPv4 option code 59, if it is less than ``valid-lifetime``; and it
+ only sends ``renew-timer``, via DHCPv4 option code 58, if it is less
+ than ``rebind-timer`` (or ``valid-lifetime`` if ``rebind-timer`` was not
+ specified). In their absence, the client should select values for T1
+ and T2 timers according to `RFC 2131 <https://tools.ietf.org/html/rfc2131>`_.
+ See section :ref:`dhcp4-t1-t2-times`
+ for more details on generating T1 and T2.
+
+The ``interfaces-config`` map specifies the network interfaces on which the
+server should listen to DHCP messages. The ``interfaces`` parameter specifies
+a list of network interfaces on which the server should listen. Lists are
+opened and closed with square brackets, with elements separated by commas. To
+listen on two interfaces, the ``interfaces-config`` element should look like
+this:
+
+::
+
+ {
+ "interfaces-config": {
+ "interfaces": [ "eth0", "eth1" ]
+ },
+ ...
+ }
+
+The next lines define the lease database, the place where the
+server stores its lease information. This particular example tells the
+server to use memfile, which is the simplest and fastest database
+backend. It uses an in-memory database and stores leases on disk in a
+CSV (comma-separated values) file. This is a very simple configuration example;
+usually the lease database configuration is more extensive and contains
+additional parameters. Note that ``lease-database`` is an object and opens up a
+new scope, using an opening brace. Its parameters (just one in this example:
+``type``) follow. If there were more than one, they would be separated
+by commas. This scope is closed with a closing brace. As more parameters
+for the ``Dhcp4`` definition follow, a trailing comma is present.
+
+Finally, we need to define a list of IPv4 subnets. This is the most
+important DHCPv4 configuration structure, as the server uses that
+information to process clients' requests. It defines all subnets from
+which the server is expected to receive DHCP requests. The subnets are
+specified with the ``subnet4`` parameter. It is a list, so it starts and
+ends with square brackets. Each subnet definition in the list has
+several attributes associated with it, so it is a structure and is
+opened and closed with braces. At a minimum, a subnet definition must
+have at least two parameters: ``subnet``, which defines the whole
+subnet; and ``pools``, which is a list of dynamically allocated pools
+that are governed by the DHCP server.
+
+The example contains a single subnet. If more than one were defined,
+additional elements in the ``subnet4`` parameter would be specified and
+separated by commas. For example, to define three subnets, the following
+syntax would be used:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ "subnet": "192.0.2.0/24"
+ },
+ {
+ "id": 2,
+ "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ],
+ "subnet": "192.0.3.0/24"
+ },
+ {
+ "id": 3,
+ "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ],
+ "subnet": "192.0.4.0/24"
+ }
+ ],
+ ...
+ }
+
+Note that indentation is optional and is used for aesthetic purposes
+only. In some cases it may be preferable to use more compact notation.
+
+After all the parameters have been specified, there are two contexts open:
+``global`` and ``Dhcp4``; thus, two closing curly brackets must be used to close
+them.
+
+Lease Storage
+-------------
+
+All leases issued by the server are stored in the lease database.
+There are three database backends available: memfile
+(the default), MySQL, PostgreSQL.
+
+Memfile - Basic Storage for Leases
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server is able to store lease data in different repositories. Larger
+deployments may elect to store leases in a database;
+:ref:`database-configuration4` describes this option. In
+typical smaller deployments, though, the server stores lease
+information in a CSV file rather than a database. As well as requiring
+less administration, an advantage of using a file for storage is that it
+eliminates a dependency on third-party database software.
+
+The configuration of the memfile backend is controlled through
+the ``Dhcp4``/``lease-database`` parameters. The ``type`` parameter is mandatory
+and specifies which storage for leases the server should use, through
+the ``"memfile"`` value. The following list gives additional optional parameters
+that can be used to configure the memfile backend.
+
+- ``persist``: controls whether the new leases and updates to existing
+ leases are written to the file. It is strongly recommended that the
+ value of this parameter be set to ``true`` at all times during the
+ server's normal operation. Not writing leases to disk means that if a
+ server is restarted (e.g. after a power failure), it will not know
+ which addresses have been assigned. As a result, it may assign new clients
+ addresses that are already in use. The value of
+ ``false`` is mostly useful for performance-testing purposes. The
+ default value of the ``persist`` parameter is ``true``, which enables
+ writing lease updates to the lease file.
+
+- ``name``: specifies an absolute location of the lease file in which
+ new leases and lease updates are recorded. The default value for
+ this parameter is ``"[kea-install-dir]/var/lib/kea/kea-leases4.csv"``.
+
+- ``lfc-interval``: specifies the interval, in seconds, at which the
+ server will perform a lease file cleanup (LFC). This removes
+ redundant (historical) information from the lease file and
+ effectively reduces the lease file size. The cleanup process is
+ described in more detail later in this section. The default
+ value of the ``lfc-interval`` is ``3600``. A value of ``0`` disables the LFC.
+
+- ``max-row-errors``: specifies the number of row errors before the server
+ stops attempting to load a lease file. When the server loads a lease file, it is processed
+ row by row, each row containing a single lease. If a row is flawed and
+ cannot be processed correctly the server logs it, discards the row,
+ and goes on to the next row. This parameter can be used to set a limit on
+ the number of such discards that can occur, after which the server
+ abandons the effort and exits. The default value of ``0`` disables the limit
+ and allows the server to process the entire file, regardless of how many
+ rows are discarded.
+
+An example configuration of the memfile backend is presented below:
+
+::
+
+ "Dhcp4": {
+ "lease-database": {
+ "type": "memfile",
+ "persist": true,
+ "name": "/tmp/kea-leases4.csv",
+ "lfc-interval": 1800,
+ "max-row-errors": 100
+ }
+ }
+
+This configuration selects ``/tmp/kea-leases4.csv`` as the storage
+for lease information and enables persistence (writing lease updates to
+this file). It also configures the backend to perform a periodic cleanup
+of the lease file every 1800 seconds (30 minutes) and sets the maximum number of
+row errors to 100.
+
+Why Is Lease File Cleanup Necessary?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to know how the lease file contents are organized to
+understand why the periodic lease file cleanup is needed. Every time the
+server updates a lease or creates a new lease for a client, the new
+lease information must be recorded in the lease file. For performance
+reasons, the server does not update the existing client's lease in the
+file, as this would potentially require rewriting the entire file.
+Instead, it simply appends the new lease information to the end of the
+file; the previous lease entries for the client are not removed. When
+the server loads leases from the lease file, e.g. at server startup,
+it assumes that the latest lease entry for the client is the valid one.
+Previous entries are discarded, meaning that the server can
+reconstruct accurate information about the leases even though there
+may be many lease entries for each client. However, storing many entries
+for each client results in a bloated lease file and impairs the
+performance of the server's startup and reconfiguration, as it needs to
+process a larger number of lease entries.
+
+Lease file cleanup (LFC) removes all previous entries for each client
+and leaves only the latest ones. The interval at which the cleanup is
+performed is configurable, and it should be selected according to the
+frequency of lease renewals initiated by the clients. The more frequent
+the renewals, the smaller the value of ``lfc-interval`` should be. Note,
+however, that the LFC takes time and thus it is possible (although
+unlikely) that, if the ``lfc-interval`` is too short, a new cleanup may
+be started while the previous one is still running. The server would
+recover from this by skipping the new cleanup when it detected that the
+previous cleanup was still in progress, but it implies that the actual
+cleanups will be triggered more rarely than the configured interval. Moreover,
+triggering a new cleanup adds overhead to the server, which is not
+able to respond to new requests for a short period of time when the new
+cleanup process is spawned. Therefore, it is recommended that the
+``lfc-interval`` value be selected in a way that allows the LFC
+to complete the cleanup before a new cleanup is triggered.
+
+Lease file cleanup is performed by a separate process (in the
+background) to avoid a performance impact on the server process. To
+avoid conflicts between two processes using the same lease
+files, the LFC process starts with Kea opening a new lease file; the
+actual LFC process operates on the lease file that is no longer used by
+the server. There are also other files created as a side effect of the
+lease file cleanup. The detailed description of the LFC process is located later
+in this Kea Administrator's Reference Manual: :ref:`kea-lfc`.
+
+.. _database-configuration4:
+
+Lease Database Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ Lease database access information must be configured for the DHCPv4
+ server, even if it has already been configured for the DHCPv6 server.
+ The servers store their information independently, so each server can
+ use a separate database or both servers can use the same database.
+
+.. note::
+
+ Kea requires the database timezone to match the system timezone.
+ For more details, see :ref:`mysql-database-create` and
+ :ref:`pgsql-database-create`.
+
+Lease database configuration is controlled through the
+``Dhcp4``/``lease-database`` parameters. The database type must be set to
+``memfile``, ``mysql`` or ``postgresql``, e.g.:
+
+::
+
+ "Dhcp4": { "lease-database": { "type": "mysql", ... }, ... }
+
+Next, the name of the database to hold the leases must be set; this is
+the name used when the database was created (see
+:ref:`mysql-database-create` or :ref:`pgsql-database-create`).
+
+For MySQL or PostgreSQL:
+
+::
+
+ "Dhcp4": { "lease-database": { "name": "database-name" , ... }, ... }
+
+If the database is located on a different system from the DHCPv4 server,
+the database host name must also be specified:
+
+::
+
+ "Dhcp4": { "lease-database": { "host": "remote-host-name", ... }, ... }
+
+Normally, the database is on the same machine as the DHCPv4 server.
+In this case, set the value to the empty string:
+
+::
+
+ "Dhcp4": { "lease-database": { "host" : "", ... }, ... }
+
+Should the database use a port other than the default, it may be
+specified as well:
+
+::
+
+ "Dhcp4": { "lease-database": { "port" : 12345, ... }, ... }
+
+Should the database be located on a different system, the administrator may need to
+specify a longer interval for the connection timeout:
+
+::
+
+ "Dhcp4": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... }
+
+The default value of five seconds should be more than adequate for local
+connections. If a timeout is given, though, it should be an integer
+greater than zero.
+
+The maximum number of times the server automatically attempts to
+reconnect to the lease database after connectivity has been lost may be
+specified:
+
+::
+
+ "Dhcp4": { "lease-database": { "max-reconnect-tries" : number-of-tries, ... }, ... }
+
+If the server is unable to reconnect to the database after making the
+maximum number of attempts, the server will exit. A value of 0 (the
+default) disables automatic recovery and the server will exit
+immediately upon detecting a loss of connectivity (MySQL and PostgreSQL
+only).
+
+The number of milliseconds the server waits between attempts to
+reconnect to the lease database after connectivity has been lost may
+also be specified:
+
+::
+
+ "Dhcp4": { "lease-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... }
+
+The default value for MySQL and PostgreSQL is 0, which disables automatic
+recovery and causes the server to exit immediately upon detecting the
+loss of connectivity.
+
+::
+
+ "Dhcp4": { "lease-database": { "on-fail" : "stop-retry-exit", ... }, ... }
+
+The possible values are:
+
+- ``stop-retry-exit`` - disables the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``. This is the default value for the lease backend,
+ the host backend, and the configuration backend.
+
+- ``serve-retry-exit`` - continues the DHCP service while trying to
+ automatically recover lost connections. Shuts down the server on failure
+ after exhausting ``max-reconnect-tries``.
+
+- ``serve-retry-continue`` - continues the DHCP service and does not shut down
+ the server even if the recovery fails. This is the default value for forensic
+ logging.
+
+.. note::
+
+ Automatic reconnection to database backends is configured individually per
+ backend; this allows users to tailor the recovery parameters to each backend
+ they use. We suggest that users enable it either for all backends or none,
+ so behavior is consistent.
+
+ Losing connectivity to a backend for which reconnection is disabled results
+ (if configured) in the server shutting itself down. This includes cases when
+ the lease database backend and the hosts database backend are connected to
+ the same database instance.
+
+ It is highly recommended not to change the ``stop-retry-exit`` default
+ setting for the lease manager, as it is critical for the connection to be
+ active while processing DHCP traffic. Change this only if the server is used
+ exclusively as a configuration tool.
+
+::
+
+ "Dhcp4": { "lease-database": { "retry-on-startup" : true, ... }, ... }
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
+
+The host parameter is used by the MySQL and PostgreSQL backends.
+
+Finally, the credentials of the account under which the server will
+access the database should be set:
+
+::
+
+ "Dhcp4": {
+ "lease-database": {
+ "user": "user-name",
+ "password": "password",
+ ...
+ },
+ ...
+ }
+
+If there is no password to the account, set the password to the empty
+string ``""``. (This is the default.)
+
+.. _tuning-database-timeouts4:
+
+Tuning Database Timeouts
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+In rare cases, reading or writing to the database may hang. This can be
+caused by a temporary network issue, or by misconfiguration of the proxy
+server switching the connection between different database instances.
+These situations are rare, but users have reported
+that Kea sometimes hangs while performing database IO operations.
+Setting appropriate timeout values can mitigate such issues.
+
+MySQL exposes two distinct connection options to configure the read and
+write timeouts. Kea's corresponding ``read-timeout`` and ``write-timeout``
+configuration parameters specify the timeouts in seconds. For example:
+
+::
+
+ "Dhcp4": { "lease-database": { "read-timeout" : 10, "write-timeout": 20, ... }, ... }
+
+
+Setting these parameters to 0 is equivalent to not specifying them, and
+causes the Kea server to establish a connection to the database with the
+MySQL defaults. In this case, Kea waits indefinitely for the completion of
+the read and write operations.
+
+MySQL versions earlier than 5.6 do not support setting timeouts for
+read and write operations. Moreover, the ``read-timeout`` and ``write-timeout``
+parameters can only be specified for the MySQL backend; setting them for
+any other backend database type causes a configuration error.
+
+To set a timeout in seconds for PostgreSQL, use the ``tcp-user-timeout``
+parameter. For example:
+
+::
+
+ "Dhcp4": { "lease-database": { "tcp-user-timeout" : 10, ... }, ... }
+
+
+Specifying this parameter for other backend types causes a configuration
+error.
+
+.. note::
+
+ The timeouts described here are only effective for TCP connections.
+ Please note that the MySQL client library used by the Kea servers
+ typically connects to the database via a UNIX domain socket when the
+ ``host`` parameter is ``localhost``, but establishes a TCP connection
+ for ``127.0.0.1``.
+
+
+.. _hosts4-storage:
+
+Hosts Storage
+-------------
+
+Kea is also able to store information about host reservations in the
+database. The hosts database configuration uses the same syntax as the
+lease database. In fact, the Kea server opens independent connections for
+each purpose, be it lease or hosts information, which gives
+the most flexibility. Kea can keep leases and host reservations
+separately, but can also point to the same database. Currently the
+supported hosts database types are MySQL and PostgreSQL.
+
+The following configuration can be used to configure a
+connection to MySQL:
+
+::
+
+ "Dhcp4": {
+ "hosts-database": {
+ "type": "mysql",
+ "name": "kea",
+ "user": "kea",
+ "password": "secret123",
+ "host": "localhost",
+ "port": 3306
+ }
+ }
+
+Depending on the database configuration, many of the
+parameters may be optional.
+
+Please note that usage of hosts storage is optional. A user can define
+all host reservations in the configuration file, and that is the
+recommended way if the number of reservations is small. However, when
+the number of reservations grows, it is more convenient to use host
+storage. Please note that both storage methods (the configuration file and
+one of the supported databases) can be used together. If hosts are
+defined in both places, the definitions from the configuration file are
+checked first and external storage is checked later, if necessary.
+
+Host information can be placed in multiple stores. Operations
+are performed on the stores in the order they are defined in the
+configuration file, although this leads to a restriction in ordering
+in the case of a host reservation addition; read-only stores must be
+configured after a (required) read-write store, or the addition will
+fail.
+
+.. note::
+
+ Kea requires the database timezone to match the system timezone.
+ For more details, see :ref:`mysql-database-create` and
+ :ref:`pgsql-database-create`.
+
+.. _hosts-databases-configuration4:
+
+DHCPv4 Hosts Database Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hosts database configuration is controlled through the
+``Dhcp4``/``hosts-database`` parameters. If enabled, the type of database must
+be set to ``mysql`` or ``postgresql``.
+
+::
+
+ "Dhcp4": { "hosts-database": { "type": "mysql", ... }, ... }
+
+Next, the name of the database to hold the reservations must be set;
+this is the name used when the lease database was created (see
+:ref:`supported-databases` for instructions on how to set up the
+desired database type):
+
+::
+
+ "Dhcp4": { "hosts-database": { "name": "database-name" , ... }, ... }
+
+If the database is located on a different system than the DHCPv4 server,
+the database host name must also be specified:
+
+::
+
+ "Dhcp4": { "hosts-database": { "host": remote-host-name, ... }, ... }
+
+Normally, the database is on the same machine as the DHCPv4 server.
+In this case, set the value to the empty string:
+
+::
+
+ "Dhcp4": { "hosts-database": { "host" : "", ... }, ... }
+
+Should the database use a port different than the default, it may be
+specified as well:
+
+::
+
+ "Dhcp4": { "hosts-database": { "port" : 12345, ... }, ... }
+
+The maximum number of times the server automatically attempts to
+reconnect to the host database after connectivity has been lost may be
+specified:
+
+::
+
+ "Dhcp4": { "hosts-database": { "max-reconnect-tries" : number-of-tries, ... }, ... }
+
+If the server is unable to reconnect to the database after making the
+maximum number of attempts, the server will exit. A value of 0 (the
+default) disables automatic recovery and the server will exit
+immediately upon detecting a loss of connectivity (MySQL and PostgreSQL
+only).
+
+The number of milliseconds the server waits between attempts to
+reconnect to the host database after connectivity has been lost may also
+be specified:
+
+::
+
+ "Dhcp4": { "hosts-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... }
+
+The default value for MySQL and PostgreSQL is 0, which disables automatic
+recovery and causes the server to exit immediately upon detecting the
+loss of connectivity.
+
+::
+
+ "Dhcp4": { "hosts-database": { "on-fail" : "stop-retry-exit", ... }, ... }
+
+The possible values are:
+
+- ``stop-retry-exit`` - disables the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``. This is the default value for MySQL and PostgreSQL.
+
+- ``serve-retry-exit`` - continues the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``.
+
+- ``serve-retry-continue`` - continues the DHCP service and does not shut down the
+ server even if the recovery fails.
+
+.. note::
+
+ Automatic reconnection to database backends is configured individually per
+ backend. This allows users to tailor the recovery parameters to each backend
+ they use. We suggest that users enable it either for all backends or none,
+ so behavior is consistent.
+
+ Losing connectivity to a backend for which reconnection is disabled results
+ (if configured) in the server shutting itself down. This includes cases when
+ the lease database backend and the hosts database backend are connected to
+ the same database instance.
+
+::
+
+ "Dhcp4": { "hosts-database": { "retry-on-startup" : true, ... }, ... }
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
+Database connection retries are not attempted on startup if the
+:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a
+valid connection to the database to check if JSON format is supported and to
+recount class limits.
+
+Finally, the credentials of the account under which the server will
+access the database should be set:
+
+::
+
+ "Dhcp4": {
+ "hosts-database": {
+ "user": "user-name",
+ "password": "password",
+ ...
+ },
+ ...
+ }
+
+If there is no password to the account, set the password to the empty
+string ``""``. (This is the default.)
+
+The multiple-storage extension uses a similar syntax; a configuration is
+placed into a ``hosts-databases`` list instead of into a ``hosts-database``
+entry, as in:
+
+::
+
+ "Dhcp4": { "hosts-databases": [ { "type": "mysql", ... }, ... ], ... }
+
+If the same host is configured both in-file and in-database, Kea does not issue a warning,
+as it would if both were specified in the same data source.
+Instead, the host configured in-file has priority over the one configured
+in-database.
+
+.. _read-only-database-configuration4:
+
+Using Read-Only Databases for Host Reservations With DHCPv4
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some deployments, the user whose name is specified in the
+database backend configuration may not have write privileges to the
+database. This is often required by the policy within a given network to
+secure the data from being unintentionally modified. In many cases
+administrators have deployed inventory databases, which contain
+substantially more information about the hosts than just the static
+reservations assigned to them. The inventory database can be used to
+create a view of a Kea hosts database and such a view is often
+read-only.
+
+Kea host-database backends operate with an implicit configuration to
+both read from and write to the database. If the user does not
+have write access to the host database, the backend will fail to start
+and the server will refuse to start (or reconfigure). However, if access
+to a read-only host database is required for retrieving reservations
+for clients and/or assigning specific addresses and options, it is
+possible to explicitly configure Kea to start in "read-only" mode. This
+is controlled by the ``readonly`` boolean parameter as follows:
+
+::
+
+ "Dhcp4": { "hosts-database": { "readonly": true, ... }, ... }
+
+Setting this parameter to ``false`` configures the database backend to
+operate in "read-write" mode, which is also the default configuration if
+the parameter is not specified.
+
+.. note::
+
+ The ``readonly`` parameter is only supported for MySQL and
+ PostgreSQL databases.
+
+
+Tuning Database Timeouts for Hosts Storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+See :ref:`tuning-database-timeouts4`.
+
+.. _dhcp4-interface-configuration:
+
+Interface Configuration
+-----------------------
+
+The DHCPv4 server must be configured to listen on specific network
+interfaces. The simplest network interface configuration tells the
+server to listen on all available interfaces:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "*" ]
+ },
+ ...
+ }
+
+The asterisk plays the role of a wildcard and means "listen on all
+interfaces." However, it is usually a good idea to explicitly specify
+interface names:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ]
+ },
+ ...
+ }
+
+
+It is possible to use an interface wildcard (*) concurrently
+with explicit interface names:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3", "*" ]
+ },
+ ...
+ }
+
+This format should only be used when it is
+desired to temporarily override a list of interface names and listen on
+all interfaces.
+
+Some deployments of DHCP servers require that the servers listen on
+interfaces with multiple IPv4 addresses configured. In these situations,
+the address to use can be selected by appending an IPv4 address to the
+interface name in the following manner:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ]
+ },
+ ...
+ }
+
+
+Should the server be required to listen on multiple IPv4 addresses
+assigned to the same interface, multiple addresses can be specified for
+an interface as in the example below:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1/10.0.0.1", "eth1/10.0.0.2" ]
+ },
+ ...
+ }
+
+
+Alternatively, if the server should listen on all addresses for the
+particular interface, an interface name without any address should be
+specified.
+
+Kea supports responding to directly connected clients which do not have
+an address configured. This requires the server to inject the hardware
+address of the destination into the data-link layer of the packet
+being sent to the client. The DHCPv4 server uses raw sockets to
+achieve this, and builds the entire IP/UDP stack for the outgoing
+packets. The downside of raw socket use, however, is that incoming and
+outgoing packets bypass the firewalls (e.g. iptables).
+
+Handling traffic on multiple IPv4 addresses assigned to the same
+interface can be a challenge, as raw sockets are bound to the
+interface. When the DHCP server is configured to use the raw socket on
+an interface to receive DHCP traffic, advanced packet filtering
+techniques (e.g. the BPF) must be used to receive unicast traffic on
+the desired addresses assigned to the interface. Whether clients use
+the raw socket or the UDP socket depends on whether they are directly
+connected (raw socket) or relayed (either raw or UDP socket).
+
+Therefore, in deployments where the server does not need to provision
+the directly connected clients and only receives the unicast packets
+from the relay agents, the Kea server should be configured to use UDP
+sockets instead of raw sockets. The following configuration
+demonstrates how this can be achieved:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "dhcp-socket-type": "udp"
+ },
+ ...
+ }
+
+
+The ``dhcp-socket-type`` parameter specifies that the IP/UDP sockets will be
+opened on all interfaces on which the server listens, i.e. "eth1" and
+"eth3" in this example. If ``dhcp-socket-type`` is set to ``raw``, it
+configures the server to use raw sockets instead. If the
+``dhcp-socket-type`` value is not specified, the default value ``raw``
+is used.
+
+Using UDP sockets automatically disables the reception of broadcast
+packets from directly connected clients. This effectively means that UDP
+sockets can be used for relayed traffic only. When using raw sockets,
+both the traffic from the directly connected clients and the relayed
+traffic are handled.
+
+Caution should be taken when configuring the server
+to open multiple raw sockets on the interface with several IPv4
+addresses assigned. If the directly connected client sends the message
+to the broadcast address, all sockets on this link will receive this
+message and multiple responses will be sent to the client. Therefore,
+the configuration with multiple IPv4 addresses assigned to the interface
+should not be used when the directly connected clients are operating on
+that link. To use a single address on such an interface, the
+"interface-name/address" notation should be used.
+
+.. note::
+
+ Specifying the value ``raw`` as the socket type does not guarantee
+ that raw sockets will be used! The use of raw sockets to handle
+ traffic from the directly connected clients is currently
+ supported on Linux and BSD systems only. If raw sockets are not
+ supported on the particular OS in use, the server issues a warning and
+ fall back to using IP/UDP sockets.
+
+In a typical environment, the DHCP server is expected to send back a
+response on the same network interface on which the query was received.
+This is the default behavior. However, in some deployments it is desired
+that the outbound (response) packets be sent as regular traffic and
+the outbound interface be determined by the routing tables. This
+kind of asymmetric traffic is uncommon, but valid. Kea supports a
+parameter called ``outbound-interface`` that controls this behavior. It
+supports two values: the first one, ``same-as-inbound``, tells Kea to
+send back the response on the same interface where the query packet was
+received. This is the default behavior. The second parameter, ``use-routing``,
+tells Kea to send regular UDP packets and let the kernel's routing table
+determine the most appropriate interface. This only works when
+``dhcp-socket-type`` is set to ``udp``. An example configuration looks
+as follows:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "dhcp-socket-type": "udp",
+ "outbound-interface": "use-routing"
+ },
+ ...
+ }
+
+Interfaces are re-detected at each reconfiguration. This behavior can be
+disabled by setting the ``re-detect`` value to ``false``, for instance:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "re-detect": false
+ },
+ ...
+ }
+
+
+Note that interfaces are not re-detected during :isccmd:`config-test`.
+
+Usually loopback interfaces (e.g. the ``lo`` or ``lo0`` interface) are not
+configured, but if a loopback interface is explicitly configured and
+IP/UDP sockets are specified, the loopback interface is accepted.
+
+For example, this setup can be used to run Kea in a FreeBSD jail having only a
+loopback interface, to service a relayed DHCP request:
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "lo0" ],
+ "dhcp-socket-type": "udp"
+ },
+ ...
+ }
+
+Kea binds the service sockets for each interface on startup. If another
+process is already using a port, then Kea logs the message and suppresses an
+error. DHCP service runs, but it is unavailable on some interfaces.
+
+The "service-sockets-require-all" option makes Kea require all sockets to
+be successfully bound. If any opening fails, Kea interrupts the
+initialization and exits with a non-zero status. (Default is false).
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "service-sockets-require-all": true
+ },
+ ...
+ }
+
+Sometimes, immediate interruption isn't a good choice. The port can be
+unavailable only temporary. In this case, retrying the opening may resolve
+the problem. Kea provides two options to specify the retrying:
+``service-sockets-max-retries`` and ``service-sockets-retry-wait-time``.
+
+The first defines a maximal number of retries that Kea makes to open a socket.
+The zero value (default) means that the Kea doesn't retry the process.
+
+The second defines a wait time (in milliseconds) between attempts. The default
+value is 5000 (5 seconds).
+
+::
+
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "service-sockets-max-retries": 5,
+ "service-sockets-retry-wait-time": 5000
+ },
+ ...
+ }
+
+If "service-sockets-max-retries" is non-zero and "service-sockets-require-all"
+is false, then Kea retries the opening (if needed) but does not fail if any
+socket is still not opened.
+
+.. _dhcpinform-unicast-issues:
+
+Issues With Unicast Responses to DHCPINFORM
+-------------------------------------------
+
+The use of UDP sockets has certain benefits in deployments where the
+server receives only relayed traffic; these benefits are mentioned in
+:ref:`dhcp4-interface-configuration`. From the
+administrator's perspective it is often desirable to configure the
+system's firewall to filter out unwanted traffic, and the use of UDP
+sockets facilitates this. However, the administrator must also be aware
+of the implications related to filtering certain types of traffic, as it
+may impair the DHCP server's operation.
+
+In this section we focus on the case when the server receives the
+DHCPINFORM message from the client via a relay. According to `RFC
+2131 <https://tools.ietf.org/html/rfc2131>`__, the server should unicast
+the DHCPACK response to the address carried in the ``ciaddr`` field. When
+the UDP socket is in use, the DHCP server relies on the low-level
+functions of an operating system to build the data link, IP, and UDP
+layers of the outgoing message. Typically, the OS first uses ARP to
+obtain the client's link-layer address to be inserted into the frame's
+header, if the address is not cached from a previous transaction that
+the client had with the server. When the ARP exchange is successful, the
+DHCP message can be unicast to the client, using the obtained address.
+
+Some system administrators block ARP messages in their network, which
+causes issues for the server when it responds to the DHCPINFORM
+messages because the server is unable to send the DHCPACK if the
+preceding ARP communication fails. Since the OS is entirely responsible
+for the ARP communication and then sending the DHCP packet over the
+wire, the DHCP server has no means to determine that the ARP exchange
+failed and the DHCP response message was dropped. Thus, the server does
+not log any error messages when the outgoing DHCP response is dropped.
+At the same time, all hooks pertaining to the packet-sending operation
+will be called, even though the message never reaches its destination.
+
+Note that the issue described in this section is not observed when
+raw sockets are in use, because, in this case, the DHCP server builds
+all the layers of the outgoing message on its own and does not use ARP.
+Instead, it inserts the value carried in the ``chaddr`` field of the
+DHCPINFORM message into the link layer.
+
+Server administrators willing to support DHCPINFORM messages via relays
+should not block ARP traffic in their networks, or should use raw sockets
+instead of UDP sockets.
+
+.. _ipv4-subnet-id:
+
+IPv4 Subnet Identifier
+----------------------
+
+The subnet identifier (subnet ID) is a unique number associated with a particular
+subnet. In principle, it is used to associate clients' leases with their
+respective subnets. The server configuration should contain unique and stable
+identifiers for all subnets. When a subnet identifier is not specified for a
+subnet, it is automatically assigned by the configuration mechanism. The identifiers
+are assigned starting at 1 and are monotonically increased for each subsequent
+subnet: 1, 2, 3, ....
+
+If there are multiple subnets configured with auto-generated identifiers
+and one of them is removed, the subnet identifiers may be renumbered.
+For example: if there are four subnets and the third is removed, the
+last subnet will be assigned the identifier that the third subnet had
+before removal. As a result, the leases stored in the lease database for
+subnet 3 are now associated with subnet 4, something that may have
+unexpected consequences. It is one of the reasons why auto-generated subnet
+identifiers are deprecated starting from Kea version 2.4.0.
+
+.. note::
+
+ The auto-generation of the subnet identifiers will be removed in a future
+ release. Starting from Kea 2.4.0, a subnet without an ``id`` entry
+ or with the zero value raises a warning at the configuration time.
+
+.. note::
+
+ Subnet IDs must be greater than zero and less than 4294967295.
+
+The following configuration assigns the specified subnet identifier
+to a newly configured subnet:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "id": 1024,
+ ...
+ }
+ ]
+ }
+
+This identifier will not change for this subnet unless the ``id``
+parameter is removed or set to 0. The value of 0 forces auto-generation
+of the subnet identifier.
+
+.. _ipv4-subnet-prefix:
+
+IPv4 Subnet Prefix
+------------------
+
+The subnet prefix is the second way to identify a subnet. Kea can
+accept non-canonical subnet addresses; for instance,
+this configuration is accepted:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.1/24",
+ ...
+ }
+ ]
+ }
+
+This works even if there is another subnet with the "192.0.2.0/24" prefix;
+only the textual form of subnets are compared to avoid duplicates.
+
+.. note::
+
+ Abuse of this feature can lead to incorrect subnet selection
+ (see :ref:`dhcp4-subnet-selection`).
+
+.. _dhcp4-address-config:
+
+Configuration of IPv4 Address Pools
+-----------------------------------
+
+The main role of a DHCPv4 server is address assignment. For this, the
+server must be configured with at least one subnet and one pool of
+dynamic addresses to be managed. For example, assume that the server is
+connected to a network segment that uses the 192.0.2.0/24 prefix. The
+administrator of that network decides that addresses from the range
+192.0.2.10 to 192.0.2.20 are going to be managed by the DHCPv4 server.
+Such a configuration can be achieved in the following way:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ { "pool": "192.0.2.10 - 192.0.2.20" }
+ ],
+ ...
+ }
+ ]
+ }
+
+Note that ``subnet`` is defined as a simple string, but the ``pools``
+parameter is actually a list of pools; for this reason, the pool
+definition is enclosed in square brackets, even though only one range of
+addresses is specified.
+
+Each ``pool`` is a structure that contains the parameters that describe
+a single pool. Currently there is only one parameter, ``pool``, which
+gives the range of addresses in the pool.
+
+It is possible to define more than one pool in a subnet; continuing the
+previous example, further assume that 192.0.2.64/26 should also be
+managed by the server. It could be written as 192.0.2.64 to 192.0.2.127,
+or it can be expressed more simply as 192.0.2.64/26. Both
+formats are supported by ``Dhcp4`` and can be mixed in the pool list. For
+example, the following pools could be defined:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ { "pool": "192.0.2.10-192.0.2.20" },
+ { "pool": "192.0.2.64/26" }
+ ],
+ ...
+ }
+ ],
+ ...
+ }
+
+White space in pool definitions is ignored, so spaces before and after
+the hyphen are optional. They can be used to improve readability.
+
+The number of pools is not limited, but for performance reasons it is
+recommended to use as few as possible.
+
+The server may be configured to serve more than one subnet. To add a
+second subnet, use a command similar to the following:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ ...
+ },
+ {
+ "subnet": "192.0.3.0/24",
+ "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ],
+ ...
+ },
+ {
+ "subnet": "192.0.4.0/24",
+ "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ],
+ ...
+ }
+ ]
+ }
+
+When configuring a DHCPv4 server using prefix/length notation, please
+pay attention to the boundary values. When specifying that the server
+can use a given pool, it is also able to allocate the first
+(typically a network address) and the last (typically a broadcast
+address) address from that pool. In the aforementioned example of pool
+192.0.3.0/24, both the 192.0.3.0 and 192.0.3.255 addresses may be
+assigned as well. This may be invalid in some network configurations. To
+avoid this, use the ``min-max`` notation.
+
+In a subnet whose prefix length is less than 24, users may wish to exclude all
+addresses ending in .0 and .255 from being dynamically allocated. For
+instance, in the subnet 10.0.0.0/8, an administrator may wish to exclude 10.x.y.0
+and 10.x.y.255 for all
+values of x and y, even though only 10.0.0.0 and 10.255.255.255 must be
+excluded according to RFC standards. The ``exclude-first-last-24`` configuration
+compatibility flag (:ref:`dhcp4-compatibility`) does this
+automatically, rather than requiring explicit configuration of many pools or
+reservations for fake hosts. When ``true``, it applies only to subnets of
+24 prefix length or smaller i.e. larger address space; the default is ``false``.
+
+In this case, "exclude" means to skip these addresses in the free address pickup
+routine of the allocation engine; if a client explicitly requests or
+has a host reservation for an address in .0 or .255, it will get it.
+
+.. note::
+
+ Here are some liberties and limits to the values that subnets and pools can
+ take in unusual Kea configurations:
+
+ +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+
+ | Kea configuration case | Allowed | Comment |
+ +=============================================================+=========+======================================================================================+
+ | Overlapping subnets | Yes | Administrator should consider how clients are matched to these subnets. |
+ +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+
+ | Overlapping pools in one subnet | No | Startup error: DHCP4_PARSER_FAIL |
+ +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+
+ | Overlapping address pools in different subnets | Yes | Specifying the same address pool in different subnets can be used as an equivalent |
+ | | | of the global address pool. In that case, the server can assign addresses from the |
+ | | | same range regardless of the client's subnet. If an address from such a pool is |
+ | | | assigned to a client in one subnet, the same address will be renewed for this |
+ | | | client if it moves to another subnet. Another client in a different subnet will |
+ | | | not be assigned an address already assigned to the client in any of the subnets. |
+ +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+
+ | Pools not matching the subnet prefix | No | Startup error: DHCP4_PARSER_FAIL |
+ +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+
+
+.. _dhcp4-t1-t2-times:
+
+Sending T1 (Option 58) and T2 (Option 59)
+-----------------------------------------
+
+According to `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__,
+servers should send values for T1 and T2 that are 50% and 87.5% of the
+lease lifetime, respectively. By default, :iscman:`kea-dhcp4` does not send
+either value; it can be configured to send values that are either specified
+explicitly or that are calculated as percentages of the lease time. The
+server's behavior is governed by a combination of configuration
+parameters, two of which have already been mentioned.
+To send specific, fixed values use the following two parameters:
+
+- ``renew-timer`` - specifies the value of T1 in seconds.
+
+- ``rebind-timer`` - specifies the value of T2 in seconds.
+
+The server only sends T2 if it is less than the valid lease time. T1
+is only sent if T2 is being sent and T1 is less than T2; or T2
+is not being sent and T1 is less than the valid lease time.
+
+Calculating the values is controlled by the following three parameters.
+
+- ``calculate-tee-times`` - when true, T1 and T2 are calculated as
+ percentages of the valid lease time. It defaults to false.
+
+- ``t1-percent`` - the percentage of the valid lease time to use for
+ T1. It is expressed as a real number between 0.0 and 1.0 and must be
+ less than ``t2-percent``. The default value is 0.50, per RFC 2131.
+
+- ``t2-percent`` - the percentage of the valid lease time to use for
+ T2. It is expressed as a real number between 0.0 and 1.0 and must be
+ greater than ``t1-percent``. The default value is .875, per RFC 2131.
+
+.. note::
+
+ In the event that both explicit values are specified and
+ ``calculate-tee-times`` is true, the server will use the explicit values.
+ Administrators with a setup where some subnets or shared-networks
+ use explicit values and some use calculated values must
+ not define the explicit values at any level higher than where they
+ will be used. Inheriting them from too high a scope, such as
+ global, will cause them to have explicit values at every level underneath
+ (shared-networks and subnets), effectively disabling calculated
+ values.
+
+.. _dhcp4-std-options:
+
+Standard DHCPv4 Options
+-----------------------
+
+One of the major features of the DHCPv4 server is the ability to provide
+configuration options to clients. Most of the options are sent by the
+server only if the client explicitly requests them using the Parameter
+Request List option. Those that do not require inclusion in the
+Parameter Request List option are commonly used options, e.g. "Domain
+Server", and options which require special behavior, e.g. "Client FQDN",
+which is returned to the client if the client has included this option
+in its message to the server.
+
+:ref:`dhcp4-std-options-list` comprises the list of the
+standard DHCPv4 options whose values can be configured using the
+configuration structures described in this section. This table excludes
+the options which require special processing and thus cannot be
+configured with fixed values. The last column of the table
+indicates which options can be sent by the server even when they are not
+requested in the Parameter Request List option, and those which are sent
+only when explicitly requested.
+
+The following example shows how to configure the addresses of DNS
+servers, which is one of the most frequently used options. Options
+specified in this way are considered global and apply to all configured
+subnets.
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.1, 192.0.2.2"
+ },
+ ...
+ ]
+ }
+
+
+Note that either ``name`` or ``code`` is required; there is no need to
+specify both. ``space`` has a default value of ``dhcp4``, so this can be skipped
+as well if a regular (not encapsulated) DHCPv4 option is defined.
+Finally, ``csv-format`` defaults to ``true``, so it too can be skipped, unless
+the option value is specified as a hexadecimal string. Therefore,
+the above example can be simplified to:
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.2.1, 192.0.2.2"
+ },
+ ...
+ ]
+ }
+
+
+Defined options are added to the response when the client requests them,
+with a few exceptions which are always added. To enforce the addition of
+a particular option, set the ``always-send`` flag to ``true`` as in:
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.2.1, 192.0.2.2",
+ "always-send": true
+ },
+ ...
+ ]
+ }
+
+
+The effect is the same as if the client added the option code in the
+Parameter Request List option (or its equivalent for vendor options):
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.2.1, 192.0.2.2",
+ "always-send": true
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "subnet": "192.0.3.0/24",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.3.1, 192.0.3.2"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+
+In the example above, the ``domain-name-servers`` option respects the global
+``always-send`` flag and is always added to responses, but for subnet
+``192.0.3.0/24``, the value is taken from the subnet-level option data
+specification.
+
+Contrary to ``always-send``, if the ``never-send`` flag is set to
+``true`` for a particular option, the server does not add it to the response.
+The effect is the same as if the client removed the option code in the
+Parameter Request List option (or its equivalent for vendor options):
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.2.1, 192.0.2.2"
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "subnet": "192.0.3.0/24",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "never-send": true
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+In the example above, the ``domain-name-servers`` option is never added to
+responses on subnet ``192.0.3.0/24``. ``never-send`` has precedence over
+``always-send``, so if both are ``true`` the option is not added.
+
+.. note::
+
+ The ``always-send`` and ``never-send`` flags are sticky, meaning
+ they do not follow the usual configuration inheritance rules.
+ Instead, if they are enabled at least once along the configuration
+ inheritance chain, they are applied - even if they are
+ disabled in other places which would normally receive a higher priority.
+ For instance, if one of the flags is enabled in the global scope,
+ but disabled at the subnet level, it is enabled,
+ disregarding the subnet-level setting.
+
+.. note::
+
+ The ``never-send`` flag is less powerful than :ischooklib:`libdhcp_flex_option.so`;
+ for instance, it has no effect on options managed by the server itself.
+ Both ``always-send`` and ``never-send`` have no effect on options
+ which cannot be requested, for instance from a custom space.
+
+The ``name`` parameter specifies the option name. For a list of
+currently supported names, see :ref:`dhcp4-std-options-list`
+below. The ``code`` parameter specifies the option code, which must
+match one of the values from that list. The next line specifies the
+option space, which must always be set to ``dhcp4`` as these are standard
+DHCPv4 options. For other option spaces, including custom option spaces,
+see :ref:`dhcp4-option-spaces`. The next line specifies the format in
+which the data will be entered; use of CSV (comma-separated values) is
+recommended. The sixth line gives the actual value to be sent to
+clients. The data parameter is specified as normal text, with values separated by
+commas if more than one value is allowed.
+
+Options can also be configured as hexadecimal values. If ``csv-format``
+is set to ``false``, option data must be specified as a hexadecimal string.
+The following commands configure the ``domain-name-servers`` option for all
+subnets with the following addresses: 192.0.3.1 and 192.0.3.2. Note that
+``csv-format`` is set to ``false``.
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": false,
+ "data": "C0 00 03 01 C0 00 03 02"
+ },
+ ...
+ ],
+ ...
+ }
+
+Kea supports the following formats when specifying hexadecimal data:
+
+- ``Delimited octets`` - one or more octets separated by either colons or
+ spaces (":" or " "). While each octet may contain one or two digits,
+ we strongly recommend always using two digits. Valid examples are
+ "ab:cd:ef" and "ab cd ef".
+
+- ``String of digits`` - a continuous string of hexadecimal digits with
+ or without a "0x" prefix. Valid examples are "0xabcdef" and "abcdef".
+
+Care should be taken to use proper encoding when using hexadecimal
+format; Kea's ability to validate data correctness in hexadecimal is
+limited.
+
+It is also possible to specify data for binary options as
+a single-quoted text string within double quotes as shown (note that
+``csv-format`` must be set to ``false``):
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "user-class",
+ "code": 77,
+ "space": "dhcp4",
+ "csv-format": false,
+ "data": "'convert this text to binary'"
+ },
+ ...
+ ],
+ ...
+ }
+
+Most of the parameters in the ``option-data`` structure are optional and
+can be omitted in some circumstances, as discussed in :ref:`dhcp4-option-data-defaults`.
+
+It is possible to specify or override options on a per-subnet basis. If
+clients connected to most subnets are expected to get the same
+values of a given option, administrators should use global options. On the other
+hand, if different values are used in each subnet, it does not make sense
+to specify global option values; rather, only
+subnet-specific ones should be set.
+
+The following commands override the global DNS servers option for a
+particular subnet, setting a single DNS server with address 192.0.2.3:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.3"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+In some cases it is useful to associate some options with an address
+pool from which a client is assigned a lease. Pool-specific option
+values override subnet-specific and global option values; it
+is not possible to prioritize assignment of pool-specific
+options via the order of pool declarations in the server
+configuration.
+
+The following configuration snippet demonstrates how to specify the DNS
+servers option, which is assigned to a client only if the client
+obtains an address from the given pool:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "pools": [
+ {
+ "pool": "192.0.2.1 - 192.0.2.200",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "192.0.2.3"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Options can also be specified in class or host-reservation scope. The
+current Kea options precedence order is (from most important to least): host
+reservation, pool, subnet, shared network, class, global.
+
+When a data field is a string and that string contains the comma (``,``;
+U+002C) character, the comma must be escaped with two backslashes (``\\,``;
+U+005C). This double escape is required because both the routine
+splitting of CSV data into fields and JSON use the same escape character; a
+single escape (``\,``) would make the JSON invalid. For example, the string
+"foo,bar" must be represented as:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "pools": [
+ {
+ "option-data": [
+ {
+ "name": "boot-file-name",
+ "data": "foo\\,bar"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Some options are designated as arrays, which means that more than one
+value is allowed. For example, the option ``time-servers``
+allows the specification of more than one IPv4 address, enabling clients
+to obtain the addresses of multiple NTP servers.
+
+:ref:`dhcp4-custom-options` describes the
+configuration syntax to create custom option definitions (formats).
+Creation of custom definitions for standard options is generally not
+permitted, even if the definition being created matches the actual
+option format defined in the RFCs. However, there is an exception to this rule
+for standard options for which Kea currently does not provide a
+definition. To use such options, a server administrator must
+create a definition as described in
+:ref:`dhcp4-custom-options` in the ``dhcp4`` option space. This
+definition should match the option format described in the relevant RFC,
+but the configuration mechanism allows any option format as there is
+currently no way to validate it.
+
+The currently supported standard DHCPv4 options are listed in
+the table below. "Name" and "Code" are the
+values that should be used as a name/code in the option-data structures.
+"Type" designates the format of the data; the meanings of the various
+types are given in :ref:`dhcp-types`.
+
+.. _dhcp4-std-options-list:
+
+.. table:: List of standard DHCPv4 options configurable by an administrator
+
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | Name | Code | Type | Array? | Returned if |
+ | | | | | not |
+ | | | | | requested? |
+ +========================================+======+===========================+=============+=============+
+ | time-offset | 2 | int32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | routers | 3 | ipv4-address | true | true |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | time-servers | 4 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | name-servers | 5 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | domain-name-servers | 6 | ipv4-address | true | true |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | log-servers | 7 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | cookie-servers | 8 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | lpr-servers | 9 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | impress-servers | 10 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | resource-location-servers | 11 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | boot-size | 13 | uint16 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | merit-dump | 14 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | domain-name | 15 | fqdn | false | true |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | swap-server | 16 | ipv4-address | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | root-path | 17 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | extensions-path | 18 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | ip-forwarding | 19 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | non-local-source-routing | 20 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | policy-filter | 21 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | max-dgram-reassembly | 22 | uint16 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | default-ip-ttl | 23 | uint8 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | path-mtu-aging-timeout | 24 | uint32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | path-mtu-plateau-table | 25 | uint16 | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | interface-mtu | 26 | uint16 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | all-subnets-local | 27 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | broadcast-address | 28 | ipv4-address | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | perform-mask-discovery | 29 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | mask-supplier | 30 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | router-discovery | 31 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | router-solicitation-address | 32 | ipv4-address | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | static-routes | 33 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | trailer-encapsulation | 34 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | arp-cache-timeout | 35 | uint32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | ieee802-3-encapsulation | 36 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | default-tcp-ttl | 37 | uint8 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | tcp-keepalive-interval | 38 | uint32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | tcp-keepalive-garbage | 39 | boolean | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nis-domain | 40 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nis-servers | 41 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | ntp-servers | 42 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | vendor-encapsulated-options | 43 | empty | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netbios-name-servers | 44 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netbios-dd-server | 45 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netbios-node-type | 46 | uint8 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netbios-scope | 47 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | font-servers | 48 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | x-display-manager | 49 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | dhcp-option-overload | 52 | uint8 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | dhcp-server-identifier | 54 | ipv4-address | false | true |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | dhcp-message | 56 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | dhcp-max-message-size | 57 | uint16 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | vendor-class-identifier | 60 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nwip-domain-name | 62 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nwip-suboptions | 63 | binary | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nisplus-domain-name | 64 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nisplus-servers | 65 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | tftp-server-name | 66 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | boot-file-name | 67 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | mobile-ip-home-agent | 68 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | smtp-server | 69 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | pop-server | 70 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nntp-server | 71 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | www-server | 72 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | finger-server | 73 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | irc-server | 74 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | streettalk-server | 75 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | streettalk-directory-assistance-server | 76 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | user-class | 77 | binary | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | slp-directory-agent | 78 | record (boolean, | true | false |
+ | | | ipv4-address) | | |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | slp-service-scope | 79 | record (boolean, string) | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nds-server | 85 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nds-tree-name | 86 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | nds-context | 87 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | bcms-controller-names | 88 | fqdn | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | bcms-controller-address | 89 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | client-system | 93 | uint16 | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | client-ndi | 94 | record (uint8, uint8, | false | false |
+ | | | uint8) | | |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | uuid-guid | 97 | record (uint8, binary) | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | uap-servers | 98 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | geoconf-civic | 99 | binary | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | pcode | 100 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | tcode | 101 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v6-only-preferred | 108 | uint32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netinfo-server-address | 112 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | netinfo-server-tag | 113 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-captive-portal | 114 | string | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | auto-config | 116 | uint8 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | name-service-search | 117 | uint16 | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | domain-search | 119 | fqdn | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | classless-static-route | 121 | internal | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | vivco-suboptions | 124 | record (uint32, binary) | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | vivso-suboptions | 125 | uint32 | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | pana-agent | 136 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-lost | 137 | fqdn | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | capwap-ac-v4 | 138 | ipv4-address | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | sip-ua-cs-domains | 141 | fqdn | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-sztp-redirect | 143 | tuple | true | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | rdnss-selection | 146 | record (uint8, | true | false |
+ | | | ipv4-address, | | |
+ | | | ipv4-address, fqdn) | | |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-portparams | 159 | record (uint8, psid) | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-dnr | 162 | record (uint16, uint16, | false | false |
+ | | | uint8, fqdn, binary) | | |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | option-6rd | 212 | record (uint8, uint8, | true | false |
+ | | | ipv6-address, | | |
+ | | | ipv4-address) | | |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+ | v4-access-domain | 213 | fqdn | false | false |
+ +----------------------------------------+------+---------------------------+-------------+-------------+
+
+.. note::
+
+ The ``default-url`` option was replaced with ``v4-captive-portal`` in Kea 2.1.2, as introduced by
+ `RFC 8910 <https://tools.ietf.org/html/rfc8910>`_. The new option has exactly the same format as the
+ old one. The general perception is that ``default-url`` was seldom used. If you used it and migrating,
+ please replace ``default-url`` with ``v4-captive-portal`` and your configuration will continue to work
+ as before.
+
+Kea also supports other options than those listed above; the following options
+are returned by the Kea engine itself and in general should not be configured
+manually.
+
+.. table:: List of standard DHCPv4 options managed by Kea on its own and not directly configurable by an administrator
+
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | Name | Code | Type | Description |
+ +================================+=======+=======================================+===================================================================+
+ | subnet-mask | 1 | ipv4-address | calculated automatically, based on subnet definition. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | host-name | 12 | string | sent by client, generally governed by the DNS configuration. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-requested-address | 50 | ipv4-address | may be sent by the client and the server should not set it. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-lease-time | 51 | uint32 | set automatically based on the ``valid-lifetime`` parameter. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-message-type | 53 | string | sent by clients and servers. Set by the Kea engine depending on |
+ | | | | the situation and should never be configured explicitly. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-parameter-request-list | 55 | uint8 array | sent by clients and should never be sent by the server. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-renewal-time | 58 | uint32 | governed by ``renew-timer`` parameter. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-rebinding-time | 59 | uint32 | governed by ``rebind-timer`` parameter. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-client-identifier | 61 | binary | sent by client, echoed back with the value sent by the client. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | fqdn | 81 | record (uint8, uint8, uint8, fqdn) | part of the DDNS and D2 configuration. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | dhcp-agent-options | 82 | empty | sent by the relay agent. This is an empty container option; see |
+ | | | | RAI option detail later in this section. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | authenticate | 90 | binary | sent by client, Kea does not yet validate it. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | client-last-transaction-time | 91 | uint32 | sent by client, server does not set it. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | associated-ip | 92 | ipv4-address array | sent by client, server responds with list of addresses. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+ | subnet-selection | 118 | ipv4-address | if present in client's messages, will be used in the subnet |
+ | | | | selection process. |
+ +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+
+
+The following table lists all option types used in the previous two tables with a description of
+what values are accepted for them.
+
+.. _dhcp-types:
+
+.. table:: List of standard DHCP option types
+
+ +-----------------+-------------------------------------------------------+
+ | Name | Meaning |
+ +=================+=======================================================+
+ | binary | An arbitrary string of bytes, specified as a set |
+ | | of hexadecimal digits. |
+ +-----------------+-------------------------------------------------------+
+ | boolean | A boolean value with allowed |
+ | | values true or false. |
+ +-----------------+-------------------------------------------------------+
+ | empty | No value; data is carried in |
+ | | sub-options. |
+ +-----------------+-------------------------------------------------------+
+ | fqdn | Fully qualified domain name (e.g. |
+ | | www.example.com). |
+ +-----------------+-------------------------------------------------------+
+ | ipv4-address | IPv4 address in the usual |
+ | | dotted-decimal notation (e.g. |
+ | | 192.0.2.1). |
+ +-----------------+-------------------------------------------------------+
+ | ipv6-address | IPv6 address in the usual colon |
+ | | notation (e.g. 2001:db8::1). |
+ +-----------------+-------------------------------------------------------+
+ | ipv6-prefix | IPv6 prefix and prefix length |
+ | | specified using CIDR notation, |
+ | | e.g. 2001:db8:1::/64. This data |
+ | | type is used to represent an |
+ | | 8-bit field conveying a prefix |
+ | | length and the variable length |
+ | | prefix value. |
+ +-----------------+-------------------------------------------------------+
+ | psid | PSID and PSID length separated by |
+ | | a slash, e.g. 3/4 specifies |
+ | | PSID=3 and PSID length=4. In the |
+ | | wire format it is represented by |
+ | | an 8-bit field carrying PSID |
+ | | length (in this case equal to 4) |
+ | | and the 16-bits-long PSID value |
+ | | field (in this case equal to |
+ | | "0011000000000000b" using binary |
+ | | notation). Allowed values for a |
+ | | PSID length are 0 to 16. See `RFC |
+ | | 7597 <https://tools.ietf.org/html/rfc7597>`__ |
+ | | for details about the PSID wire |
+ | | representation. |
+ +-----------------+-------------------------------------------------------+
+ | record | Structured data that may be |
+ | | comprised of any types (except |
+ | | "record" and "empty"). The array |
+ | | flag applies to the last field |
+ | | only. |
+ +-----------------+-------------------------------------------------------+
+ | string | Any text. Please note that Kea |
+ | | silently discards any |
+ | | terminating/trailing nulls from |
+ | | the end of "string" options when |
+ | | unpacking received packets. This |
+ | | is in keeping with `RFC 2132, |
+ | | Section |
+ | | 2 <https://tools.ietf.org/html/rfc2132#section-2>`__. |
+ +-----------------+-------------------------------------------------------+
+ | tuple | A length encoded as an 8-bit (16-bit |
+ | | for DHCPv6) unsigned integer |
+ | | followed by a string of this |
+ | | length. |
+ +-----------------+-------------------------------------------------------+
+ | uint8 | An 8-bit unsigned integer with |
+ | | allowed values 0 to 255. |
+ +-----------------+-------------------------------------------------------+
+ | uint16 | A 16-bit unsigned integer with |
+ | | allowed values 0 to 65535. |
+ +-----------------+-------------------------------------------------------+
+ | uint32 | A 32-bit unsigned integer with |
+ | | allowed values 0 to 4294967295. |
+ +-----------------+-------------------------------------------------------+
+ | int8 | An 8-bit signed integer with allowed |
+ | | values -128 to 127. |
+ +-----------------+-------------------------------------------------------+
+ | int16 | A 16-bit signed integer with |
+ | | allowed values -32768 to 32767. |
+ +-----------------+-------------------------------------------------------+
+ | int32 | A 32-bit signed integer with |
+ | | allowed values -2147483648 to |
+ | | 2147483647. |
+ +-----------------+-------------------------------------------------------+
+
+Kea also supports the Relay Agent Information (RAI, defined in
+`RFC 3046 <https://tools.ietf.org/html/rfc3046>`_) option, sometimes referred to as the relay option, agent
+option, or simply option 82. The option itself is just a container and does not convey any information
+on its own. The following table contains a list of RAI sub-options that Kea can understand. The RAI
+and its sub-options are inserted by the relay agent and received by Kea; there is no need for Kea
+to be configured with those options. Kea's classification and flex-id in host reservations can be
+used to process those and other options no listed in the table below.
+
+.. table:: List of RAI sub-options that Kea can understand
+
+ +--------------------+------+----------------------------------------------------------------------+
+ | Name | Code | Comment |
+ +====================+======+======================================================================+
+ | circuit-id | 1 | Used when host-reservation-identifiers is set to `circuit-id`. |
+ +--------------------+------+----------------------------------------------------------------------+
+ | remote-id | 2 | Can be used with flex-id to identify hosts. |
+ +--------------------+------+----------------------------------------------------------------------+
+ | link-selection | 5 | If present, used to select the appropriate subnet. |
+ +--------------------+------+----------------------------------------------------------------------+
+ | subscriber-id | 6 | Can be used with flex-id to identify hosts. |
+ +--------------------+------+----------------------------------------------------------------------+
+ | server-id-override | 11 | If sent by the relay, Kea accepts it as the `server-id`. |
+ +--------------------+------+----------------------------------------------------------------------+
+ | relay-id | 12 | Identifies the relay |
+ +--------------------+------+----------------------------------------------------------------------+
+ | relay-port | 19 | If sent by the relay, Kea sends back its responses to this port. |
+ +--------------------+------+----------------------------------------------------------------------+
+
+All other RAI sub-options (including those not listed here) can be used in client classification to
+classify incoming packets to specific classes and/or by :ischooklib:`libdhcp_flex_id.so` to
+construct a unique device identifier. For more information about expressions used in client
+classification, and flex-id, see :ref:`classify`. The RAI sub-options can be
+referenced using ``relay4[option-code].hex``. For example, to classify packets based on the
+``remote-id`` (sub-option code 2), one would use ``relay4[2].hex``. An example client class that
+would include all packets with a specific ``remote-id`` value would looks as follows:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "remote-id-1020304",
+ "test": "relay4[2].hex == 0x01020304",
+ ...
+ }
+ ],
+ ...
+ }
+
+Classes may be used to segregate traffic into a relatively small number of groups, which then
+can be used to select specific subnets, pools and extra options and more. If per host behavior
+is necessary, using host reservations with flex-id is strongly recommended.
+
+.. _dhcp4-custom-options:
+
+Custom DHCPv4 Options
+---------------------
+
+Kea supports custom (non-standard) DHCPv4 options. Let's say that we want
+to define a new DHCPv4 option called ``foo``, which will have code 222
+and will convey a single, unsigned, 32-bit integer value.
+Such an option can be defined by putting the following entry in the configuration file:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "foo",
+ "code": 222,
+ "type": "uint32",
+ "array": false,
+ "record-types": "",
+ "space": "dhcp4",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The ``false`` value of the ``array`` parameter determines that the
+option does NOT comprise an array of ``uint32`` values but is, instead, a
+single value. Two other parameters have been left blank:
+``record-types`` and ``encapsulate``. The former specifies the
+comma-separated list of option data fields, if the option comprises a
+record of data fields. The ``record-types`` value should be non-empty if
+``type`` is set to "record"; otherwise it must be left blank. The latter
+parameter specifies the name of the option space being encapsulated by
+the particular option. If the particular option does not encapsulate any
+option space, the parameter should be left blank. Note that the ``option-def``
+configuration statement only defines the format of an option and does
+not set its value(s).
+
+The ``name``, ``code``, and ``type`` parameters are required; all others
+are optional. The ``array`` parameter default value is ``false``. The
+``record-types`` and ``encapsulate`` parameters default values are blank
+(``""``). The default ``space`` is ``dhcp4``.
+
+Once the new option format is defined, its value is set in the same way
+as for a standard option. For example, the following commands set a
+global value that applies to all subnets.
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "foo",
+ "code": 222,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "12345"
+ },
+ ...
+ ],
+ ...
+ }
+
+New options can take more complex forms than the simple use of primitives
+(uint8, string, ipv4-address, etc.); it is possible to define an option
+comprising a number of existing primitives.
+
+For example, say we want to define a new option that will consist of
+an IPv4 address, followed by an unsigned 16-bit integer, followed by a
+boolean value, followed by a text string. Such an option could be
+defined in the following way:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "bar",
+ "code": 223,
+ "space": "dhcp4",
+ "type": "record",
+ "array": false,
+ "record-types": "ipv4-address, uint16, boolean, string",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The ``type`` parameter is set to ``"record"`` to indicate that the option
+contains multiple values of different types. These types are given as a
+comma-separated list in the ``record-types`` field and should be ones
+from those listed in :ref:`dhcp-types`.
+
+The option's values are set in an ``option-data`` statement as follows:
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "bar",
+ "space": "dhcp4",
+ "code": 223,
+ "csv-format": true,
+ "data": "192.0.2.100, 123, true, Hello World"
+ }
+ ],
+ ...
+ }
+
+The ``csv-format`` parameter is set to ``true`` to indicate that the ``data``
+field comprises a comma-separated list of values. The values in ``data`` must
+correspond to the types set in the ``record-types`` field of the option
+definition.
+
+When ``array`` is set to ``true`` and ``type`` is set to ``"record"``, the
+last field is an array, i.e. it can contain more than one value, as in:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "bar",
+ "code": 223,
+ "space": "dhcp4",
+ "type": "record",
+ "array": true,
+ "record-types": "ipv4-address, uint16",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The new option content is one IPv4 address followed by one or more 16-bit
+unsigned integers.
+
+.. note::
+
+ In general, boolean values are specified as ``true`` or ``false``,
+ without quotes. Some specific boolean parameters may also accept
+ ``"true"``, ``"false"``, ``0``, ``1``, ``"0"``, and ``"1"``.
+
+.. note::
+
+ Numbers can be specified in decimal or hexadecimal format. The
+ hexadecimal format can be either plain (e.g. abcd) or prefixed with
+ 0x (e.g. 0xabcd).
+
+.. _dhcp4-private-opts:
+
+DHCPv4 Private Options
+----------------------
+
+Options with a code between 224 and 254 are reserved for private use.
+They can be defined at the global scope or at the client-class local
+scope; this allows option definitions to be used depending on context,
+and option data to be set accordingly. For instance, to configure an old
+PXEClient vendor:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "pxeclient",
+ "test": "option[vendor-class-identifier].text == 'PXEClient'",
+ "option-def": [
+ {
+ "name": "configfile",
+ "code": 209,
+ "type": "string"
+ }
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+As the Vendor-Specific Information (VSI) option (code 43) has a vendor-specific
+format, i.e. can carry either raw binary value or sub-options, this
+mechanism is also available for this option.
+
+In the following example taken from a real configuration, two vendor
+classes use option 43 for different and incompatible purposes:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "cookie",
+ "code": 1,
+ "type": "string",
+ "space": "APC"
+ },
+ {
+ "name": "mtftp-ip",
+ "code": 1,
+ "type": "ipv4-address",
+ "space": "PXE"
+ },
+ ...
+ ],
+ "client-classes": [
+ {
+ "name": "APC",
+ "test": "option[vendor-class-identifier].text == 'APC'",
+ "option-def": [
+ {
+ "name": "vendor-encapsulated-options",
+ "type": "empty",
+ "encapsulate": "APC"
+ }
+ ],
+ "option-data": [
+ {
+ "name": "cookie",
+ "space": "APC",
+ "data": "1APC"
+ },
+ {
+ "name": "vendor-encapsulated-options"
+ },
+ ...
+ ],
+ ...
+ },
+ {
+ "name": "PXE",
+ "test": "option[vendor-class-identifier].text == 'PXE'",
+ "option-def": [
+ {
+ "name": "vendor-encapsulated-options",
+ "type": "empty",
+ "encapsulate": "PXE"
+ }
+ ],
+ "option-data": [
+ {
+ "name": "mtftp-ip",
+ "space": "PXE",
+ "data": "0.0.0.0"
+ },
+ {
+ "name": "vendor-encapsulated-options"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+The definition used to decode a VSI option is:
+
+1. The local definition of a client class the incoming packet belongs
+ to;
+
+2. If none, the global definition;
+
+3. If none, the last-resort definition described in the next section,
+ :ref:`dhcp4-vendor-opts` (backward-compatible with previous Kea versions).
+
+.. note::
+
+ This last-resort definition for the Vendor-Specific Information
+ option (code 43) is not compatible with a raw binary value. When
+ there are known cases where a raw binary value will be used, a
+ client class must be defined with both a classification expression
+ matching these cases and an option definition for the VSI option with
+ a binary type and no encapsulation.
+
+.. note::
+
+ By default, in the Vendor-Specific Information option (code 43),
+ sub-option code 0 and 255 mean PAD and END respectively, according to
+ `RFC 2132 <https://tools.ietf.org/html/rfc2132>`_. In other words, the
+ sub-option code values of 0 and 255 are reserved. Kea does, however,
+ allow users to define sub-option codes from 0 to 255. If
+ sub-options with codes 0 and/or 255 are defined, bytes with that value are
+ no longer treated as a PAD or an END, but as the sub-option code
+ when parsing a VSI option in an incoming query.
+
+ Option 43 input processing (also called unpacking) is deferred so that it
+ happens after classification. This means clients cannot be classified
+ using option 43 sub-options. The definition used to unpack option 43
+ is determined as follows:
+
+ - If defined at the global scope, this definition is used.
+ - If defined at client class scope and the packet belongs to this
+ class, the client class definition is used.
+ - If not defined at global scope nor in a client class to which the
+ packet belongs, the built-in last resort definition is used. This
+ definition only says the sub-option space is
+ ``"vendor-encapsulated-options-space"``.
+
+ The output definition selection is a bit simpler:
+
+ - If the packet belongs to a client class which defines the option
+ 43, use this definition.
+ - If defined at the global scope, use this definition.
+ - Otherwise, use the built-in last-resort definition.
+
+ Since they use a specific/per vendor option space, sub-options
+ are defined at the global scope.
+
+.. note::
+
+ Option definitions in client classes are allowed only for this
+ limited option set (codes 43 and from 224 to 254), and only for
+ DHCPv4.
+
+.. _dhcp4-vendor-opts:
+
+DHCPv4 Vendor-Specific Options
+------------------------------
+
+Currently there are two option spaces defined for :iscman:`kea-dhcp4`:
+``dhcp4`` (for the top-level DHCPv4 options) and
+``"vendor-encapsulated-options-space"``, which is empty by default but in
+which options can be defined. Those options are carried in the
+Vendor-Specific Information option (code 43). The following examples
+show how to define an option ``foo`` with code 1 that
+comprises an IPv4 address, an unsigned 16-bit integer, and a string. The
+``foo`` option is conveyed in a Vendor-Specific Information option.
+
+The first step is to define the format of the option:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "foo",
+ "code": 1,
+ "space": "vendor-encapsulated-options-space",
+ "type": "record",
+ "array": false,
+ "record-types": "ipv4-address, uint16, string",
+ "encapsulate": ""
+ }
+ ],
+ ...
+ }
+
+Note that the option space is set to ``"vendor-encapsulated-options-space"``.
+Once the option format is defined, the next step is to define actual values
+for that option:
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "foo",
+ "space": "vendor-encapsulated-options-space",
+ "code": 1,
+ "csv-format": true,
+ "data": "192.0.2.3, 123, Hello World"
+ }
+ ],
+ ...
+ }
+
+In this example, we also include the Vendor-Specific Information option, which
+conveys our sub-option ``foo``. This is required; otherwise, the option
+will not be included in messages sent to the client.
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "vendor-encapsulated-options"
+ }
+ ],
+ ...
+ }
+
+Alternatively, the option can be specified using its code.
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "code": 43
+ }
+ ],
+ ...
+ }
+
+Another popular option that is often somewhat imprecisely called the "vendor
+option" is option 125. Its proper name is the "vendor-independent
+vendor-specific information option" or "vivso". The idea behind vivso options
+is that each vendor has its own unique set of options with their own custom
+formats. The vendor is identified by a 32-bit unsigned integer called
+``enterprise-number`` or ``vendor-id``.
+
+
+The standard spaces defined in Kea and their options are:
+
+- ``vendor-4491``: Cable Television Laboratories, Inc. for DOCSIS3 options:
+
++-------------+--------------+------------------------------------------------------------------------+
+| option code | option name | option description |
++=============+==============+========================================================================+
+| 1 | oro | ORO (or Option Request Option), used by clients to request a list of |
+| | | options they are interested in. |
++-------------+--------------+------------------------------------------------------------------------+
+| 2 | tftp-servers | a list of IPv4 addresses of TFTP servers to be used by the cable modem |
++-------------+--------------+------------------------------------------------------------------------+
+
+In Kea, each vendor is represented by its own vendor space. Since there are
+hundreds of vendors and they sometimes use different option definitions for
+different hardware, it is impossible for Kea to support them all natively.
+Fortunately, it is easy to define support for new vendor options. As an
+example, the Genexis home gateway device requires the vivso 125 option to be
+sent with a sub-option 2 that contains a string with the TFTP server URL. To
+support such a device, three steps are needed: first, establish option
+definitions that explain how the option is supposed to be formed; second,
+define option values; and third, tell Kea when to send those
+specific options, via client classification.
+
+An example snippet of a configuration could look similar to the
+following:
+
+::
+
+ "Dhcp4": {
+ // First, we need to define that the sub-option 2 in vivso option for
+ // vendor-id 25167 has a specific format (it's a plain string in this example).
+ // After this definition, we can specify values for option tftp.
+ "option-def": [
+ {
+ // We define a short name, so the option can be referenced by name.
+ // The option has code 2 and resides within vendor space 25167.
+ // Its data is a plain string.
+ "name": "tftp",
+ "code": 2,
+ "space": "vendor-25167",
+ "type": "string"
+ }
+ ],
+
+ "client-classes": [
+ {
+ // We now need to tell Kea how to recognize when to use vendor space 25167.
+ // Usually we can use a simple expression, such as checking if the device
+ // sent a vivso option with specific vendor-id, e.g. "vendor[4491].exists".
+ // Unfortunately, Genexis is a bit unusual in this aspect, because it
+ // doesn't send vivso. In this case we need to look into the vendor class
+ // (option code 60) and see if there's a specific string that identifies
+ // the device. Alternatively, one can make use of the automated `VENDOR_CLASS_`
+ // client class and replace "name" and "test" with `"name": "VENDOR_CLASS_HMC1000"`
+ // and no test expression.
+ "name": "cpe_genexis",
+ "test": "substring(option[60].hex,0,7) == 'HMC1000'",
+
+ // Once the device is recognized, we want to send two options:
+ // the vivso option with vendor-id set to 25167, and a sub-option 2.
+ "option-data": [
+ {
+ "name": "vivso-suboptions",
+ "data": "25167"
+ },
+
+ // The sub-option 2 value is defined as any other option. However,
+ // we want to send this sub-option 2, even when the client didn't
+ // explicitly request it (often there is no way to do that for
+ // vendor options). Therefore we use always-send to force Kea
+ // to always send this option when 25167 vendor space is involved.
+ {
+ "name": "tftp",
+ "space": "vendor-25167",
+ "data": "tftp://192.0.2.1/genexis/HMC1000.v1.3.0-R.img",
+ "always-send": true
+ }
+ ]
+ }
+ ]
+ }
+
+By default, Kea sends back only those options that are requested by a client,
+unless there are protocol rules that tell the DHCP server to always send an
+option. This approach works nicely in most cases and avoids problems with
+clients refusing responses with options they do not understand. However, the
+situation with vendor options is more complex, as they are not requested the
+same way as other options, are not well-documented in official RFCs, or vary by
+vendor.
+
+Some vendors (such as DOCSIS, identified by vendor option 4491) have a mechanism
+to request specific vendor options and Kea is able to honor those (sub-option 1).
+Unfortunately, for many other vendors, such as Genexis (25167, discussed above),
+Kea does not have such a mechanism, so it cannot send any sub-options on its own.
+To solve this issue, we devised the concept of persistent options. Kea can be
+told to always send options, even if the client did not request them. This can
+be achieved by adding ``"always-send": true`` to the option data entry. Note
+that in this particular case an option is defined in vendor space 25167. With
+``always-send`` enabled, the option is sent every time there is a need to deal
+with vendor space 25167.
+
+This is also how :iscman:`kea-dhcp4` can be configured to send multiple vendor options
+from different vendors, along with each of their specific vendor ID.
+If these options need to be sent by the server regardless of whether the client
+specified any enterprise number, ``"always-send": true`` must be configured
+for the suboptions that will be included in the ``vivso-suboptions`` option (code 125).
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ # Typically DHCPv4 clients will send a Parameter Request List option (code 55) for
+ # vivso-suboptions (code 125), and that is enough for Kea to understand that it needs to
+ # send the option. These options still need to be defined in the configuration, one per
+ # each vendor, but they don't need "always-send" enabled in that case. For misbehaving
+ # clients that to do not explicitly request it, one may alternatively set "always-send"
+ # to true for them as well. This is referring to the following two entries in option-data.
+ {
+ "name": "vivso-suboptions",
+ "space": "dhcp4",
+ "data": "2234"
+ },
+ {
+ "name": "vivso-suboptions",
+ "space": "dhcp4",
+ "data": "3561"
+ },
+ {
+ "always-send": true,
+ "data": "tagged",
+ "name": "tag",
+ "space": "vendor-2234"
+ },
+ {
+ "always-send": true,
+ "data": "https://example.com:1234/path",
+ "name": "url",
+ "space": "vendor-3561"
+ }
+ ],
+ "option-def": [
+ {
+ "code": 22,
+ "name": "tag",
+ "space": "vendor-2234",
+ "type": "string"
+ },
+ {
+ "code": 11,
+ "name": "url",
+ "space": "vendor-3561",
+ "type": "string"
+ }
+ ]
+ }
+
+Another possibility is to redefine the option; see :ref:`dhcp4-private-opts`.
+
+Kea comes with several example configuration files. Some of them showcase
+how to configure options 60 and 43. See ``doc/examples/kea4/vendor-specific.json``
+and ``doc/examples/kea4/vivso.json`` in the Kea sources.
+
+.. note::
+
+ :iscman:`kea-dhcp4` is able to recognize multiple Vendor Class Identifier
+ options (code 60) with different vendor IDs in the client requests and to
+ send multiple vivso options (code 125) in the responses, one for each vendor.
+
+ :iscman:`kea-dhcp4` honors DOCSIS sub-option 1 (ORO) and adds only requested options
+ if this sub-option is present in the client request.
+
+ Currently only one vendor is supported for the ``vivco-suboptions``
+ (code 124) option. Specifying multiple enterprise numbers within a single
+ option instance or multiple options with different enterprise numbers is not
+ supported.
+
+.. _dhcp4-option-spaces:
+
+Nested DHCPv4 Options (Custom Option Spaces)
+--------------------------------------------
+
+It is sometimes useful to define a completely new option space, such as
+when a user creates a new option in the standard option space
+(``dhcp4``) and wants this option to convey sub-options. Since they are in
+a separate space, sub-option codes have a separate numbering scheme
+and may overlap with the codes of standard options.
+
+Note that the creation of a new option space is not required when
+defining sub-options for a standard option, because one is created by
+default if the standard option is meant to convey any sub-options (see
+:ref:`dhcp4-vendor-opts`).
+
+If we want a DHCPv4 option called ``container`` with code 222,
+that conveys two sub-options with codes 1 and 2, we first need to
+define the new sub-options:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "subopt1",
+ "code": 1,
+ "space": "isc",
+ "type": "ipv4-address",
+ "record-types": "",
+ "array": false,
+ "encapsulate": ""
+ },
+ {
+ "name": "subopt2",
+ "code": 2,
+ "space": "isc",
+ "type": "string",
+ "record-types": "",
+ "array": false,
+ "encapsulate": ""
+ }
+ ],
+ ...
+ }
+
+Note that we have defined the options to belong to a new option space
+(in this case, ``"isc"``).
+
+The next step is to define a regular DHCPv4 option with the desired code
+and specify that it should include options from the new option space:
+
+::
+
+ "Dhcp4": {
+ "option-def": [
+ {
+ "name": "container",
+ "code": 222,
+ "space": "dhcp4",
+ "type": "empty",
+ "array": false,
+ "record-types": "",
+ "encapsulate": "isc"
+ },
+ ...
+ ],
+ ...
+ }
+
+The name of the option space in which the sub-options are defined is set
+in the ``encapsulate`` field. The ``type`` field is set to ``"empty"``, to
+indicate that this option does not carry any data other than
+sub-options.
+
+Finally, we can set values for the new options:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "subopt1",
+ "code": 1,
+ "space": "isc",
+ "data": "192.0.2.3"
+ },
+ {
+ "name": "subopt2",
+ "code": 2,
+ "space": "isc",
+ "data": "Hello world"
+ },
+ {
+ "name": "container",
+ "code": 222,
+ "space": "dhcp4"
+ }
+ ]
+ }
+ }
+
+It is possible to create an option which carries some data in
+addition to the sub-options defined in the encapsulated option space.
+For example, if the ``container`` option from the previous example were
+required to carry a uint16 value as well as the sub-options, the
+``type`` value would have to be set to ``"uint16"`` in the option
+definition. (Such an option would then have the following data
+structure: DHCP header, uint16 value, sub-options.) The value specified
+with the ``data`` parameter — which should be a valid integer enclosed
+in quotes, e.g. ``"123"`` — would then be assigned to the ``uint16`` field in
+the ``container`` option.
+
+.. _dhcp4-option-data-defaults:
+
+Unspecified Parameters for DHCPv4 Option Configuration
+------------------------------------------------------
+
+In many cases it is not required to specify all parameters for an option
+configuration, and the default values can be used. However, it is
+important to understand the implications of not specifying some of them,
+as it may result in configuration errors. The list below explains the
+behavior of the server when a particular parameter is not explicitly
+specified:
+
+- ``name`` - the server requires either an option name or an option code to
+ identify an option. If this parameter is unspecified, the option code
+ must be specified.
+
+- ``code`` - the server requires either an option name or an option code to
+ identify an option; this parameter may be left unspecified if the
+ ``name`` parameter is specified. However, this also requires that the
+ particular option have a definition (either as a standard option or
+ an administrator-created definition for the option using an
+ ``option-def`` structure), as the option definition associates an
+ option with a particular name. It is possible to configure an option
+ for which there is no definition (unspecified option format).
+ Configuration of such options requires the use of the option code.
+
+- ``space`` - if the option space is unspecified it defaults to
+ ``dhcp4``, which is an option space holding standard DHCPv4 options.
+
+- ``data`` - if the option data is unspecified it defaults to an empty
+ value. The empty value is mostly used for the options which have no
+ payload (boolean options), but it is legal to specify empty values
+ for some options which carry variable-length data and for which the
+ specification allows a length of 0. For such options, the data
+ parameter may be omitted in the configuration.
+
+- ``csv-format`` - if this value is not specified, the server
+ assumes that the option data is specified as a list of comma-separated
+ values to be assigned to individual fields of the DHCP option.
+
+.. _dhcp4-support-for-long-options:
+
+Support for Long Options
+------------------------
+
+The :iscman:`kea-dhcp4` server partially supports long options (RFC3396).
+Since Kea 2.1.6, the server accepts configuring long options and sub-options
+(longer than 255 bytes). The options and sub-options are stored internally
+in their unwrapped form and they can be processed as usual using the parser
+language. On send, the server splits long options and sub-options into multiple
+options and sub-options, using the respective option code.
+
+::
+
+ {
+ "option-def": [
+ {
+ "array": false,
+ "code": 240,
+ "encapsulate": "",
+ "name": "my-option",
+ "space": "dhcp4",
+ "type": "string"
+ }
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 240,
+ "name": "my-option",
+ "csv-format": true,
+ "data": "data \
+ -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \
+ -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \
+ -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \
+ -data",
+ "space": "dhcp4"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+.. note::
+
+ In the example above, the data has been wrapped into several lines for clarity,
+ but Kea does not support wrapping in the configuration file.
+
+This example illustrates configuring a custom long option (exceeding 255 octets)
+in a reservation. When sending a response, the server splits this option
+into two options, each with the code 240.
+
+.. note::
+
+ Currently the server does not support storing long options in databases,
+ either host reservations or the configuration backend.
+
+The server is also able to receive packets with split options (options using
+the same option code) and to fuse the data chunks into one option. This is
+also supported for sub-options if each sub-option data chunk also contains the
+sub-option code and sub-option length.
+
+.. _dhcp4-stateless-configuration:
+
+Stateless Configuration of DHCPv4 Clients
+-----------------------------------------
+
+The DHCPv4 server supports stateless client configuration, whereby
+the client has an IP address configured (e.g. using manual
+configuration) and only contacts the server to obtain other
+configuration parameters, such as addresses of DNS servers. To
+obtain the stateless configuration parameters, the client sends the
+DHCPINFORM message to the server with the ``ciaddr`` set to the address
+that the client is currently using. The server unicasts the DHCPACK
+message to the client that includes the stateless configuration
+("yiaddr" not set).
+
+The server responds to the DHCPINFORM when the client is associated
+with a subnet defined in the server's configuration. An example subnet
+configuration looks like this:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "data": "192.0.2.200,192.0.2.201",
+ "csv-format": true,
+ "space": "dhcp4"
+ }
+ ]
+ }
+ ]
+ }
+
+This subnet specifies the single option which will be included in the
+DHCPACK message to the client in response to DHCPINFORM. The
+subnet definition does not require the address pool configuration if it
+will be used solely for stateless configuration.
+
+This server will associate the subnet with the client if one of the
+following conditions is met:
+
+- The DHCPINFORM is relayed and the ``giaddr`` matches the configured
+ subnet.
+
+- The DHCPINFORM is unicast from the client and the ``ciaddr`` matches the
+ configured subnet.
+
+- The DHCPINFORM is unicast from the client and the ``ciaddr`` is not set,
+ but the source address of the IP packet matches the configured
+ subnet.
+
+- The DHCPINFORM is not relayed and the IP address on the interface on
+ which the message is received matches the configured subnet.
+
+.. _dhcp4-client-classifier:
+
+Client Classification in DHCPv4
+-------------------------------
+
+The DHCPv4 server includes support for client classification. For a
+deeper discussion of the classification process, see :ref:`classify`.
+
+In certain cases it is useful to configure the server to differentiate
+between DHCP client types and treat them accordingly. Client
+classification can be used to modify the behavior of almost any part of
+DHCP message processing. Kea currently offers client classification
+via private options and option 43 deferred unpacking; subnet selection;
+pool selection; assignment of different options; and, for cable modems,
+specific options for use with the TFTP server address and the boot file
+field.
+
+Kea can be instructed to limit access to given subnets based on class
+information. This is particularly useful for cases where two types of
+devices share the same link and are expected to be served from two
+different subnets. The primary use case for such a scenario is cable
+networks, where there are two classes of devices: the cable modem
+itself, which should be handed a lease from subnet A; and all other
+devices behind the modem, which should get leases from subnet B. That
+segregation is essential to prevent overly curious end-users from playing
+with their cable modems. For details on how to set up class restrictions
+on subnets, see :ref:`classification-subnets`.
+
+When subnets belong to a shared network, the classification applies to
+subnet selection but not to pools; that is, a pool in a subnet limited to a
+particular class can still be used by clients which do not belong to the
+class, if the pool they are expected to use is exhausted. The limit
+on access based on class information is also available at the pool
+level within a subnet: see :ref:`classification-pools`. This is
+useful when segregating clients belonging to the same subnet into
+different address ranges.
+
+In a similar way, a pool can be constrained to serve only known clients,
+i.e. clients which have a reservation, using the built-in ``KNOWN`` or
+``UNKNOWN`` classes. Addresses can be assigned to registered clients
+without giving a different address per reservation: for instance, when
+there are not enough available addresses. The determination whether
+there is a reservation for a given client is made after a subnet is
+selected, so it is not possible to use ``KNOWN``/``UNKNOWN`` classes to select a
+shared network or a subnet.
+
+The process of classification is conducted in five steps. The first step
+is to assess an incoming packet and assign it to zero or more classes.
+The second step is to choose a subnet, possibly based on the class
+information. When the incoming packet is in the special class ``DROP``,
+it is dropped and a debug message logged.
+The next step is to evaluate class expressions depending on
+the built-in ``KNOWN``/``UNKNOWN`` classes after host reservation lookup,
+using them for pool selection and assigning classes from host
+reservations. The list of required classes is then built and each class
+of the list has its expression evaluated; when it returns ``true``, the
+packet is added as a member of the class. The last step is to assign
+options, again possibly based on the class information. More complete
+and detailed information is available in :ref:`classify`.
+
+There are two main methods of classification. The first is automatic and
+relies on examining the values in the vendor class options or the
+existence of a host reservation. Information from these options is
+extracted, and a class name is constructed from it and added to the
+class list for the packet. The second method specifies an expression that is
+evaluated for each packet. If the result is ``true``, the packet is a
+member of the class.
+
+.. note::
+
+ The new ``early-global-reservations-lookup`` global parameter flag
+ enables a lookup for global reservations before the subnet selection
+ phase. This lookup is similar to the general lookup described above
+ with two differences:
+
+ - the lookup is limited to global host reservations
+
+ - the ``UNKNOWN`` class is never set
+
+.. note::
+
+ Care should be taken with client classification, as it is easy for
+ clients that do not meet class criteria to be denied all service.
+
+Setting Fixed Fields in Classification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible to specify that clients belonging to a particular class
+should receive packets with specific values in certain fixed fields. In
+particular, three fixed fields are supported: ``next-server`` (conveys
+an IPv4 address, which is set in the ``siaddr`` field), ``server-hostname``
+(conveys a server hostname, can be up to 64 bytes long, and is sent in
+the ``sname`` field) and ``boot-file-name`` (conveys the configuration file,
+can be up to 128 bytes long, and is sent using the ``file`` field).
+
+Obviously, there are many ways to assign clients to specific classes,
+but for PXE clients the client architecture type option (code 93)
+seems to be particularly suited to make the distinction. The following
+example checks whether the client identifies itself as a PXE device with
+architecture EFI x86-64, and sets several fields if it does. See
+`Section 2.1 of RFC
+4578 <https://tools.ietf.org/html/rfc4578#section-2.1>`__) or the
+client documentation for specific values.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "ipxe_efi_x64",
+ "test": "option[93].hex == 0x0009",
+ "next-server": "192.0.2.254",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null"
+ },
+ ...
+ ],
+ ...
+ }
+
+If an incoming packet is matched to multiple classes, then the
+value used for each field will come from the first class that
+specifies the field, in the order the classes are assigned to the
+packet.
+
+.. note::
+
+ The classes are ordered as specified in the configuration.
+
+Using Vendor Class Information in Classification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server checks whether an incoming packet includes the vendor class
+identifier option (60). If it does, the content of that option is
+prepended with ``VENDOR_CLASS_``, and it is interpreted as a class. For
+example, modern cable modems send this option with value
+``docsis3.0``, so the packet belongs to the class
+``VENDOR_CLASS_docsis3.0``.
+
+.. note::
+
+ Certain special actions for clients in ``VENDOR_CLASS_docsis3.0`` can be
+ achieved by defining ``VENDOR_CLASS_docsis3.0`` and setting its
+ ``next-server`` and ``boot-file-name`` values appropriately.
+
+This example shows a configuration using an automatically generated
+``VENDOR_CLASS_`` class. The administrator of the network has decided that
+addresses from the range 192.0.2.10 to 192.0.2.20 are going to be managed by
+the Dhcp4 server and only clients belonging to the DOCSIS 3.0 client
+class are allowed to use that pool.
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "client-class": "VENDOR_CLASS_docsis3.0"
+ }
+ ],
+ ...
+ }
+
+Defining and Using Custom Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following example shows how to configure a class using an expression
+and a subnet using that class. This configuration defines the class
+named ``Client_foo``. It is comprised of all clients whose client IDs
+(option 61) start with the string ``foo``. Members of this class will be
+given addresses from 192.0.2.10 to 192.0.2.20 and the addresses of their
+DNS servers set to 192.0.2.1 and 192.0.2.2.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "substring(option[61].hex,0,3) == 'foo'",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": true,
+ "data": "192.0.2.1, 192.0.2.2"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "client-class": "Client_foo"
+ },
+ ...
+ ],
+ ...
+ }
+
+.. _dhcp4-required-class:
+
+Required Classification
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases it is useful to limit the scope of a class to a
+shared network, subnet, or pool. There are two parameters which are used
+to limit the scope of the class by instructing the server to evaluate test
+expressions when required.
+
+The first one is the per-class ``only-if-required`` flag, which is ``false``
+by default. When it is set to ``true``, the test expression of the class
+is not evaluated at the reception of the incoming packet but later, and
+only if the class evaluation is required.
+
+The second is ``require-client-classes``, which takes a list of class
+names and is valid in shared-network, subnet, and pool scope. Classes in
+these lists are marked as required and evaluated after selection of this
+specific shared network/subnet/pool and before output-option processing.
+
+In this example, a class is assigned to the incoming packet when the
+specified subnet is used:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "member('ALL')",
+ "only-if-required": true
+ },
+ ...
+ ],
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "require-client-classes": [ "Client_foo" ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Required evaluation can be used to express complex dependencies like
+subnet membership. It can also be used to reverse the
+precedence; if ``option-data`` is set in a subnet, it takes precedence
+over ``option-data`` in a class. If ``option-data`` is moved to a
+required class and required in the subnet, a class evaluated earlier
+may take precedence.
+
+Required evaluation is also available at the shared-network and pool levels.
+The order in which required classes are considered is: shared-network,
+subnet, and pool, i.e. in the reverse order from the way in which
+``option-data`` is processed.
+
+.. note::
+
+ Vendor-Identifying Vendor Options are a special case: for all other
+ options an option is identified by its code point, but ``vivco-suboptions``
+ (124) and ``vivso-suboptions`` (125) are identified by the pair of
+ code point and vendor identifier. This has no visible effect for
+ ``vivso-suboptions``, whose value is the vendor identifier, but it
+ is different for ``vivco-suboptions``, where the value is a record
+ with the vendor identifier and a binary value. For instance, in:
+
+::
+
+ "Dhcp4": {
+ "option-data": [
+ {
+ "name": "vivco-suboptions",
+ "always-send": true,
+ "data": "1234, 03666f6f"
+ },
+ {
+ "name": "vivco-suboptions",
+ "always-send": true,
+ "data": "5678, 03626172"
+ },
+ ...
+ ],
+ ...
+ }
+
+The first ``option-data`` entry does not hide the second one, because
+vendor identifiers (1234 and 5678) are different: the responses will carry
+two instances of the ``vivco-suboptions`` option, each for a different vendor.
+
+.. _dhcp4-ddns-config:
+
+DDNS for DHCPv4
+---------------
+
+As mentioned earlier, :iscman:`kea-dhcp4` can be configured to generate requests
+to the DHCP-DDNS server, :iscman:`kea-dhcp-ddns`, (referred to herein as "D2") to
+update DNS entries. These requests are known as NameChangeRequests or
+NCRs. Each NCR contains the following information:
+
+1. Whether it is a request to add (update) or remove DNS entries.
+
+2. Whether the change requests forward DNS updates (A records), reverse
+ DNS updates (PTR records), or both.
+
+3. The Fully Qualified Domain Name (FQDN), lease address, and DHCID
+ (information identifying the client associated with the FQDN).
+
+DDNS-related parameters are split into two groups:
+
+1. Connectivity Parameters
+
+ These are parameters which specify where and how :iscman:`kea-dhcp4` connects to
+ and communicates with D2. These parameters can only be specified
+ within the top-level ``dhcp-ddns`` section in the :iscman:`kea-dhcp4`
+ configuration. The connectivity parameters are listed below:
+
+ - ``enable-updates``
+ - ``server-ip``
+ - ``server-port``
+ - ``sender-ip``
+ - ``sender-port``
+ - ``max-queue-size``
+ - ``ncr-protocol``
+ - ``ncr-format"``
+
+2. Behavioral Parameters
+
+ These parameters influence behavior such as how client host names and
+ FQDN options are handled. They have been moved out of the ``dhcp-ddns``
+ section so that they may be specified at the global, shared-network,
+ and/or subnet levels. Furthermore, they are inherited downward from global to
+ shared-network to subnet. In other words, if a parameter is not specified at
+ a given level, the value for that level comes from the level above it.
+ The behavioral parameters are as follows:
+
+ - ``ddns-send-updates``
+ - ``ddns-override-no-update``
+ - ``ddns-override-client-update``
+ - ``ddns-replace-client-name"``
+ - ``ddns-generated-prefix``
+ - ``ddns-qualifying-suffix``
+ - ``ddns-update-on-renew``
+ - ``ddns-conflict-resolution-mode``
+ - ``ddns-ttl-percent``
+ - ``hostname-char-set``
+ - ``hostname-char-replacement``
+
+.. note::
+
+ For backward compatibility, configuration parsing still recognizes
+ the original behavioral parameters specified in ``dhcp-ddns``,
+ by translating the parameter into its global equivalent. If a
+ parameter is specified both globally and in ``dhcp-ddns``, the latter
+ value is ignored. In either case, a log is emitted explaining
+ what has occurred. Specifying these values within ``dhcp-ddns`` is
+ deprecated and support for it will be removed.
+
+The default configuration and values would appear as follows:
+
+::
+
+ "Dhcp4": {
+ "dhcp-ddns": {
+ // Connectivity parameters
+ "enable-updates": false,
+ "server-ip": "127.0.0.1",
+ "server-port":53001,
+ "sender-ip":"",
+ "sender-port":0,
+ "max-queue-size":1024,
+ "ncr-protocol":"UDP",
+ "ncr-format":"JSON"
+ },
+
+ // Behavioral parameters (global)
+ "ddns-send-updates": true,
+ "ddns-override-no-update": false,
+ "ddns-override-client-update": false,
+ "ddns-replace-client-name": "never",
+ "ddns-generated-prefix": "myhost",
+ "ddns-qualifying-suffix": "",
+ "ddns-update-on-renew": false,
+ "ddns-conflict-resolution-mode": "check-with-dhcid",
+ "hostname-char-set": "",
+ "hostname-char-replacement": "",
+ ...
+ }
+
+There are two parameters which determine if :iscman:`kea-dhcp4`
+can generate DDNS requests to D2: the existing ``dhcp-ddns:enable-updates``
+parameter, which now only controls whether :iscman:`kea-dhcp4` connects to D2;
+and the new behavioral parameter, ``ddns-send-updates``, which determines
+whether DDNS updates are enabled at a given level (i.e. global, shared-network,
+or subnet). The following table shows how the two parameters function
+together:
+
+.. table:: Enabling and disabling DDNS updates
+
+ +-----------------+--------------------+-------------------------------------+
+ | dhcp-ddns: | Global | Outcome |
+ | enable-updates | ddns-send-updates | |
+ +=================+====================+=====================================+
+ | false (default) | false | no updates at any scope |
+ +-----------------+--------------------+-------------------------------------+
+ | false | true (default) | no updates at any scope |
+ +-----------------+--------------------+-------------------------------------+
+ | true | false | updates only at scopes with |
+ | | | a local value of ``true`` for |
+ | | | ``ddns-enable-updates`` |
+ +-----------------+--------------------+-------------------------------------+
+ | true | true | updates at all scopes except those |
+ | | | with a local value of ``false`` |
+ | | | for ``ddns-enable-updates`` |
+ +-----------------+--------------------+-------------------------------------+
+
+Kea 1.9.1 added two new parameters; the first is ``ddns-update-on-renew``.
+Normally, when leases are renewed, the server only updates DNS if the DNS
+information for the lease (e.g. FQDN, DNS update direction flags) has changed.
+Setting ``ddns-update-on-renew`` to ``true`` instructs the server to always update
+the DNS information when a lease is renewed, even if its DNS information has not
+changed. This allows Kea to "self-heal" if it was previously unable
+to add DNS entries or they were somehow lost by the DNS server.
+
+.. note::
+
+ Setting ``ddns-update-on-renew`` to ``true`` may impact performance, especially
+ for servers with numerous clients that renew often.
+
+The second parameter added in Kea 1.9.1 is ``ddns-use-conflict-resolution``. This
+boolean parameter was passed through to D2 and enabled or disabled conflict resolution
+as described in `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__. Beginning with
+Kea 2.5.0, it is deprecated and replaced by ``ddns-conflict-resolution-mode`` which
+offers four modes of conflict resolution-related behavior:
+
+ - ``check-with-dhcid`` - The default mode, it instructs D2 to carry out RFC
+ 4703-compliant conflict resolution. Existing DNS entries may only be
+ overwritten if they have a DHCID record and it matches the client's DHCID.
+ This is equivalent to ``ddns-use-conflict-resolution``: true;
+
+ - ``no-check-with-dhcid`` - Existing DNS entries may be overwritten by any
+ client, whether or not those entries include a DHCID record. The new entries
+ will include a DHCID record for the client to whom they belong.
+ This is equivalent to ``ddns-use-conflict-resolution``: false;
+
+ - ``check-exists-with-dhcid`` - Existing DNS entries may only be overwritten
+ if they have a DHCID record. The DHCID record need not match the client's DHCID.
+ This mode provides a way to protect static DNS entries (those that do not have
+ a DHCID record) while allowing dynamic entries (those that do have a DHCID
+ record) to be overwritten by any client. This behavior was not supported
+ prior to Kea 2.4.0.
+
+ - ``no-check-without-dhcid`` - Existing DNS entries may be overwritten by
+ any client. New entries will not include DHCID records. This behavior was
+ not supported prior to Kea 2.4.0.
+
+.. note::
+
+ For backward compatibility, ddns-use-conflict-resolution is still accepted in
+ JSON configuration. The server will replace the value internally, with the
+ ``ddns-conflict-resolution-mode`` and an appropriate value: `
+ `check-with-dhcid`` for ``true`` and ``no-check-with-dhcid`` for ``false``.
+
+.. note::
+
+ Setting ``ddns-conflict-resolution-mode`` to any value other than
+ ``check-with-dhcid`` disables the one or more overwrite safeguards
+ that the rules of conflict resolution (from
+ `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__) are intended to
+ prevent. This means that existing entries for an FQDN or an
+ IP address made for Client-A can be deleted or replaced by entries
+ for Client-B. Furthermore, there are two scenarios by which entries
+ for multiple clients for the same key (e.g. FQDN or IP) can be created.
+
+ 1. Client-B uses the same FQDN as Client-A but a different IP address.
+ In this case, the forward DNS entries (A and DHCID RRs) for
+ Client-A will be deleted as they match the FQDN and new entries for
+ Client-B will be added. The reverse DNS entries (PTR and DHCID RRs)
+ for Client-A, however, will not be deleted as they belong to a different
+ IP address, while new entries for Client-B will still be added.
+
+ 2. Client-B uses the same IP address as Client-A but a different FQDN.
+ In this case the reverse DNS entries (PTR and DHCID RRs) for Client-A
+ will be deleted as they match the IP address, and new entries for
+ Client-B will be added. The forward DNS entries (A and DHCID RRs)
+ for Client-A, however, will not be deleted, as they belong to a different
+ FQDN, while new entries for Client-B will still be added.
+
+ Disabling conflict resolution should be done only after careful review of
+ specific use cases. The best way to avoid unwanted DNS entries is to
+ always ensure lease changes are processed through Kea, whether they are
+ released, expire, or are deleted via the :isccmd:`lease4-del` command, prior to
+ reassigning either FQDNs or IP addresses. Doing so causes :iscman:`kea-dhcp4`
+ to generate DNS removal requests to D2.
+
+The DNS entries Kea creates contain a value for TTL (time to live).
+The :iscman:`kea-dhcp4` server calculates that value based on
+`RFC 4702, Section 5 <https://tools.ietf.org/html/rfc4702#section-5>`__,
+which suggests that the TTL value be 1/3 of the lease's lifetime, with
+a minimum value of 10 minutes.
+
+The parameter ``ddns-ttl-percent``, when specified,
+causes the TTL to be calculated as a simple percentage of the lease's
+lifetime, using the parameter's value as the percentage. It is specified
+as a decimal percent (e.g. .25, .75, 1.00) and may be specified at the
+global, shared-network, and subnet levels. By default it is unspecified.
+
+.. _dhcpv4-d2-io-config:
+
+DHCP-DDNS Server Connectivity
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For NCRs to reach the D2 server, :iscman:`kea-dhcp4` must be able to communicate
+with it. :iscman:`kea-dhcp4` uses the following configuration parameters to
+control this communication:
+
+- ``enable-updates`` - Enables connectivity to :iscman:`kea-dhcp-ddns` such that DDNS
+ updates can be constructed and sent.
+ It must be ``true`` for NCRs to be generated and sent to D2.
+ It defaults to ``false``.
+
+- ``server-ip`` - This is the IP address on which D2 listens for requests. The
+ default is the local loopback interface at address 127.0.0.1.
+ Either an IPv4 or IPv6 address may be specified.
+
+- ``server-port`` - This is the port on which D2 listens for requests. The default
+ value is ``53001``.
+
+- ``sender-ip`` - This is the IP address which :iscman:`kea-dhcp4` uses to send requests to
+ D2. The default value is blank, which instructs :iscman:`kea-dhcp4` to select a
+ suitable address.
+
+- ``sender-port`` - This is the port which :iscman:`kea-dhcp4` uses to send requests to D2.
+ The default value of ``0`` instructs :iscman:`kea-dhcp4` to select a suitable port.
+
+- ``max-queue-size`` - This is the maximum number of requests allowed to queue
+ while waiting to be sent to D2. This value guards against requests
+ accumulating uncontrollably if they are being generated faster than
+ they can be delivered. If the number of requests queued for
+ transmission reaches this value, DDNS updating is turned off
+ until the queue backlog has been sufficiently reduced. The intent is
+ to allow the :iscman:`kea-dhcp4` server to continue lease operations without
+ running the risk that its memory usage grows without limit. The
+ default value is ``1024``.
+
+- ``ncr-protocol`` - This specifies the socket protocol to use when sending requests to
+ D2. Currently only UDP is supported.
+
+- ``ncr-format`` - This specifies the packet format to use when sending requests to D2.
+ Currently only JSON format is supported.
+
+By default, :iscman:`kea-dhcp-ddns` is assumed to be running on the same machine
+as :iscman:`kea-dhcp4`, and all of the default values mentioned above should be
+sufficient. If, however, D2 has been configured to listen on a different
+address or port, these values must be altered accordingly. For example, if
+D2 has been configured to listen on 192.168.1.10 port 900, the following
+configuration is required:
+
+::
+
+ "Dhcp4": {
+ "dhcp-ddns": {
+ "server-ip": "192.168.1.10",
+ "server-port": 900,
+ ...
+ },
+ ...
+ }
+
+.. _dhcpv4-d2-rules-config:
+
+When Does the :iscman:`kea-dhcp4` Server Generate a DDNS Request?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :iscman:`kea-dhcp4` server follows the behavior prescribed for DHCP servers in
+`RFC 4702 <https://tools.ietf.org/html/rfc4702>`__. It is important to keep
+in mind that :iscman:`kea-dhcp4` makes the initial decision of when and what to
+update and forwards that information to D2 in the form of NCRs. Carrying
+out the actual DNS updates and dealing with such things as conflict
+resolution are within the purview of D2 itself
+(see :ref:`dhcp-ddns-server`). This section describes when :iscman:`kea-dhcp4`
+generates NCRs and the configuration parameters that can be used to
+influence this decision. It assumes that both the connectivity parameter
+``enable-updates`` and the behavioral parameter ``ddns-send-updates``,
+are ``true``.
+
+In general, :iscman:`kea-dhcp4` generates DDNS update requests when:
+
+1. A new lease is granted in response to a DHCPREQUEST;
+
+2. An existing lease is renewed but the FQDN associated with it has
+ changed; or
+
+3. An existing lease is released in response to a DHCPRELEASE.
+
+In the second case, lease renewal, two DDNS requests are issued: one
+request to remove entries for the previous FQDN, and a second request to
+add entries for the new FQDN. In the third case, a lease release - a
+single DDNS request - to remove its entries will be made.
+
+As for the first case, the decisions involved when granting a new lease are
+more complex. When a new lease is granted, :iscman:`kea-dhcp4` generates a
+DDNS update request if the DHCPREQUEST contains either the FQDN option
+(code 81) or the Host Name option (code 12). If both are present, the
+server uses the FQDN option.
+By default, :iscman:`kea-dhcp4` respects the FQDN N and S flags
+specified by the client as shown in the following table:
+
+.. table:: Default FQDN flag behavior
+
+ +------------+-----------------+-----------------+-------------+
+ | Client | Client Intent | Server Response | Server |
+ | Flags:N-S | | | Flags:N-S-O |
+ +============+=================+=================+=============+
+ | 0-0 | Client wants to | Server | 1-0-0 |
+ | | do forward | generates | |
+ | | updates, server | reverse-only | |
+ | | should do | request | |
+ | | reverse updates | | |
+ +------------+-----------------+-----------------+-------------+
+ | 0-1 | Server should | Server | 0-1-0 |
+ | | do both forward | generates | |
+ | | and reverse | request to | |
+ | | updates | update both | |
+ | | | directions | |
+ +------------+-----------------+-----------------+-------------+
+ | 1-0 | Client wants no | Server does not | 1-0-0 |
+ | | updates done | generate a | |
+ | | | request | |
+ +------------+-----------------+-----------------+-------------+
+
+The first row in the table above represents "client delegation." Here
+the DHCP client states that it intends to do the forward DNS updates and
+the server should do the reverse updates. By default, :iscman:`kea-dhcp4`
+honors the client's wishes and generates a DDNS request to the D2 server
+to update only reverse DNS data. The parameter
+``ddns-override-client-update`` can be used to instruct the server to
+override client delegation requests. When this parameter is ``true``,
+:iscman:`kea-dhcp4` disregards requests for client delegation and generates a
+DDNS request to update both forward and reverse DNS data. In this case,
+the N-S-O flags in the server's response to the client will be 0-1-1
+respectively.
+
+(Note that the flag combination N=1, S=1 is prohibited according to `RFC
+4702 <https://tools.ietf.org/html/rfc4702>`__. If such a combination is
+received from the client, the packet will be dropped by :iscman:`kea-dhcp4`.)
+
+To override client delegation, set the following values in the
+configuration file:
+
+::
+
+ "Dhcp4": {
+ "ddns-override-client-update": true,
+ ...
+ }
+
+The third row in the table above describes the case in which the client
+requests that no DNS updates be done. The parameter
+``ddns-override-no-update`` can be used to instruct the server to disregard
+the client's wishes. When this parameter is ``true``, :iscman:`kea-dhcp4`
+generates DDNS update requests to :iscman:`kea-dhcp-ddns` even if the client
+requests that no updates be done. The N-S-O flags in the server's response to
+the client will be 0-1-1.
+
+To override client delegation, issue the following commands:
+
+::
+
+ "Dhcp4": {
+ "ddns-override-no-update": true,
+ ...
+ }
+
+The :iscman:`kea-dhcp4` server always generates DDNS update requests if the
+client request only contains the Host Name option. In addition, it includes
+an FQDN option in the response to the client with the FQDN N-S-O flags
+set to 0-1-0, respectively. The domain name portion of the FQDN option
+is the name submitted to D2 in the DDNS update request.
+
+.. _dhcpv4-fqdn-name-generation:
+
+:iscman:`kea-dhcp4` Name Generation for DDNS Update Requests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each NameChangeRequest must of course include the fully qualified domain
+name whose DNS entries are to be affected. :iscman:`kea-dhcp4` can be configured
+to supply a portion or all of that name, based on what it receives
+from the client in the DHCPREQUEST.
+
+The default rules for constructing the FQDN that will be used for DNS
+entries are:
+
+1. If the DHCPREQUEST contains the client FQDN option, take the
+ candidate name from there; otherwise, take it from the Host Name
+ option.
+
+2. If the candidate name is a partial (i.e. unqualified) name, then add
+ a configurable suffix to the name and use the result as the FQDN.
+
+3. If the candidate name provided is empty, generate an FQDN using a
+ configurable prefix and suffix.
+
+4. If the client provides neither option, then take no DNS action.
+
+These rules can be amended by setting the ``ddns-replace-client-name``
+parameter, which provides the following modes of behavior:
+
+- ``never`` - use the name the client sent. If the client sent no name,
+ do not generate one. This is the default mode.
+
+- ``always`` - replace the name the client sent. If the client sent no
+ name, generate one for the client.
+
+- ``when-present`` - replace the name the client sent. If the client
+ sent no name, do not generate one.
+
+- ``when-not-present`` - use the name the client sent. If the client
+ sent no name, generate one for the client.
+
+.. note::
+
+ In early versions of Kea, this parameter was a boolean and permitted only
+ values of ``true`` and ``false``. Boolean values have been deprecated
+ and are no longer accepted. Administrators currently using booleans
+ must replace them with the desired mode name. A value of ``true``
+ maps to ``when-present``, while ``false`` maps to ``never``.
+
+For example, to instruct :iscman:`kea-dhcp4` to always generate the FQDN for a
+client, set the parameter ``ddns-replace-client-name`` to ``always`` as
+follows:
+
+::
+
+ "Dhcp4": {
+ "ddns-replace-client-name": "always",
+ ...
+ }
+
+The prefix used in the generation of an FQDN is specified by the
+``ddns-generated-prefix`` parameter. The default value is "myhost". To alter
+its value, simply set it to the desired string:
+
+::
+
+ "Dhcp4": {
+ "ddns-generated-prefix": "another.host",
+ ...
+ }
+
+The suffix used when generating an FQDN, or when qualifying a partial
+name, is specified by the ``ddns-qualifying-suffix`` parameter. It is
+strongly recommended that the user supply a value for the qualifying
+suffix when DDNS updates are enabled. For obvious reasons, we cannot
+supply a meaningful default.
+
+::
+
+ "Dhcp4": {
+ "ddns-qualifying-suffix": "foo.example.org",
+ ...
+ }
+
+When qualifying a partial name, :iscman:`kea-dhcp4` constructs the name in the
+format:
+
+``[candidate-name].[ddns-qualifying-suffix].``
+
+where ``candidate-name`` is the partial name supplied in the DHCPREQUEST.
+For example, if the FQDN domain name value is "some-computer" and the
+``ddns-qualifying-suffix`` is "example.com", the generated FQDN is:
+
+``some-computer.example.com.``
+
+When generating the entire name, :iscman:`kea-dhcp4` constructs the name in
+the format:
+
+``[ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix].``
+
+where ``address-text`` is simply the lease IP address converted to a
+hyphenated string. For example, if the lease address is 172.16.1.10, the
+qualifying suffix is "example.com", and the default value is used for
+``ddns-generated-prefix``, the generated FQDN is:
+
+``myhost-172-16-1-10.example.com.``
+
+.. _dhcp4-host-name-sanitization:
+
+Sanitizing Client Host Name and FQDN Names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some DHCP clients may provide values in the Host Name
+option (option code 12) or FQDN option (option code 81) that contain undesirable
+characters. It is possible to configure :iscman:`kea-dhcp4` to sanitize these
+values. The most typical use case is ensuring that only characters that
+are permitted by RFC 1035 be included: A-Z, a-z, 0-9, and "-". This may be
+accomplished with the following two parameters:
+
+- ``hostname-char-set`` - a regular expression describing the invalid
+ character set. This can be any valid, regular expression using POSIX
+ extended expression syntax. Embedded nulls (0x00) are always
+ considered an invalid character to be replaced (or omitted).
+ The default is ``"[^A-Za-z0-9.-]"``. This matches any character that is not
+ a letter, digit, dot, hyphen, or null.
+
+- ``hostname-char-replacement`` - a string of zero or more characters
+ with which to replace each invalid character in the host name. An empty
+ string causes invalid characters to be OMITTED rather than replaced.
+ The default is ``""``.
+
+The following configuration replaces anything other than a letter,
+digit, dot, or hyphen with the letter "x":
+::
+
+ "Dhcp4": {
+ "hostname-char-set": "[^A-Za-z0-9.-]",
+ "hostname-char-replacement": "x",
+ ...
+ }
+
+Thus, a client-supplied value of "myhost-$[123.org" would become
+"myhost-xx123.org". Sanitizing is performed only on the portion of the
+name supplied by the client, and it is performed before applying a
+qualifying suffix (if one is defined and needed).
+
+.. note::
+
+ Name sanitizing is meant to catch the more common cases of invalid
+ characters through a relatively simple character-replacement scheme.
+ It is difficult to devise a scheme that works well in all cases, for
+ both Host Name and FQDN options.
+ Administrators who find they have clients with odd corner cases of
+ character combinations that cannot be readily handled with this
+ mechanism should consider writing a hook that can carry out
+ sufficiently complex logic to address their needs.
+
+ If clients include domain names in the Host Name option and the administrator
+ wants these preserved, they need to make sure that the dot, ".",
+ is considered a valid character by the ``hostname-char-set`` expression,
+ such as this: ``"[^A-Za-z0-9.-]"``. This does not affect dots in FQDN
+ Option values.
+ When scrubbing FQDNs, dots are treated as delimiters and used to separate
+ the option value into individual domain labels that are scrubbed and
+ then re-assembled.
+
+ If clients are sending values that differ only by characters
+ considered as invalid by the ``hostname-char-set``, be aware that
+ scrubbing them will yield identical values. In such cases, DDNS
+ conflict rules will permit only one of them to register the name.
+
+ Finally, given the latitude clients have in the values they send, it
+ is virtually impossible to guarantee that a combination of these two
+ parameters will always yield a name that is valid for use in DNS. For
+ example, using an empty value for ``hostname-char-replacement`` could
+ yield an empty domain label within a name, if that label consists
+ only of invalid characters.
+
+.. note::
+
+ It is possible to specify ``hostname-char-set``
+ and/or ``hostname-char-replacement`` at the global scope. This allows
+ host names to be sanitized without requiring a ``dhcp-ddns`` entry. When
+ a ``hostname-char`` parameter is defined at both the global scope and
+ in a ``dhcp-ddns`` entry, the second (local) value is used.
+
+ For the ability to generate host names procedurally, based on an expression, and
+ for the ability to skip DDNS updates on a per-client basis, or fine-tuning various
+ DNS update aspects, the :iscman:`kea-dhcp4` can load the premium hook library
+ `libdhcp_ddns_tuning.so` which is available from ISC. Please refer to
+ :ref:`hooks-ddns-tuning` documentation for the configuration options.
+
+.. _dhcp4-next-server:
+
+Next Server (``siaddr``)
+------------------------
+
+In some cases, clients want to obtain configuration from a TFTP server.
+Although there is a dedicated option for it, some devices may use the
+``siaddr`` field in the DHCPv4 packet for that purpose. That specific field
+can be configured using the ``next-server`` directive. It is possible to
+define it in the global scope or for a given subnet only. If both are
+defined, the subnet value takes precedence. The value in the subnet can be
+set to "0.0.0.0", which means that ``next-server`` should not be sent. It
+can also be set to an empty string, which is equivalent to it
+not being defined at all; that is, it uses the global value.
+
+The ``server-hostname`` (which conveys a server hostname, can be up to
+64 bytes long, and is in the ``sname`` field) and
+``boot-file-name`` (which conveys the configuration file, can be up to
+128 bytes long, and is sent using the ``file`` field) directives are
+handled the same way as ``next-server``.
+
+::
+
+ "Dhcp4": {
+ "next-server": "192.0.2.123",
+ "boot-file-name": "/dev/null",
+ "subnet4": [
+ {
+ "next-server": "192.0.2.234",
+ "server-hostname": "some-name.example.org",
+ "boot-file-name": "bootfile.efi",
+ ...
+ }
+ ],
+ ...
+ }
+
+.. _dhcp4-echo-client-id:
+
+Echoing Client-ID (RFC 6842)
+----------------------------
+
+The original DHCPv4 specification (`RFC
+2131 <https://tools.ietf.org/html/rfc2131>`__) states that the DHCPv4
+server must not send back client-id options when responding to clients.
+However, in some cases that results in confused clients that do not have a MAC
+address or client-id; see `RFC
+6842 <https://tools.ietf.org/html/rfc6842>`__ for details. That behavior
+changed with the publication of `RFC
+6842 <https://tools.ietf.org/html/rfc6842>`__, which updated `RFC
+2131 <https://tools.ietf.org/html/rfc2131>`__. That update states that
+the server must send the client-id if the client sent it, and that is Kea's
+default behavior. However, in some cases older devices that do not
+support `RFC 6842 <https://tools.ietf.org/html/rfc6842>`__ may refuse to
+accept responses that include the client-id option. To enable backward
+compatibility, an optional configuration parameter has been introduced.
+To configure it, use the following configuration statement:
+
+::
+
+ "Dhcp4": {
+ "echo-client-id": false,
+ ...
+ }
+
+.. _dhcp4-match-client-id:
+
+Using Client Identifier and Hardware Address
+--------------------------------------------
+
+The DHCP server must be able to identify the client from which it
+receives the message and distinguish it from other clients. There are
+many reasons why this identification is required; the most important
+ones are:
+
+- When the client contacts the server to allocate a new lease, the
+ server must store the client identification information in the lease
+ database as a search key.
+
+- When the client tries to renew or release the existing lease, the
+ server must be able to find the existing lease entry in the database
+ for this client, using the client identification information as a
+ search key.
+
+- Some configurations use static reservations for the IP addresses and
+ other configuration information. The server's administrator uses
+ client identification information to create these static assignments.
+
+- In dual-stack networks there is often a need to correlate the lease
+ information stored in DHCPv4 and DHCPv6 servers for a particular
+ host. Using common identification information by the DHCPv4 and
+ DHCPv6 clients allows the network administrator to achieve this
+ correlation and better administer the network. Beginning with
+ release 2.1.2, Kea supports DHCPv6 DUIDs embedded within DHCPv4
+ Client Identifier options as described in
+ `RFC 4361 <https://tools.ietf.org/html/rfc4361>`__.
+
+DHCPv4 uses two distinct identifiers which are placed by the client in
+the queries sent to the server and copied by the server to its responses
+to the client: ``chaddr`` and ``client-identifier``. The former was
+introduced as a part of the BOOTP specification and it is also used by
+DHCP to carry the hardware address of the interface used to send the
+query to the server (MAC address for the Ethernet). The latter is
+carried in the client-identifier option, introduced in `RFC
+2132 <https://tools.ietf.org/html/rfc2132>`__.
+
+`RFC 2131 <https://tools.ietf.org/html/rfc2131>`__ indicates that the
+server may use both of these identifiers to identify the client but the
+client identifier, if present, takes precedence over ``chaddr``. One of
+the reasons for this is that the client identifier is independent from the
+hardware used by the client to communicate with the server. For example,
+if the client obtained the lease using one network card and then the
+network card is moved to another host, the server will wrongly identify
+this host as the one which obtained the lease. Moreover, `RFC
+4361 <https://tools.ietf.org/html/rfc4361>`__ gives the recommendation
+to use a DUID (see `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__,
+the DHCPv6 specification) carried as a client identifier when dual-stack
+networks are in use to provide consistent identification information for
+the client, regardless of the type of protocol it is using. Kea adheres to
+these specifications, and the client identifier by default takes
+precedence over the value carried in the ``chaddr`` field when the server
+searches, creates, updates, or removes the client's lease.
+
+When the server receives a DHCPDISCOVER or DHCPREQUEST message from the
+client, it tries to find out if the client already has a lease in the
+database; if it does, the server hands out that lease rather than allocates a new one.
+Each lease in the lease database is associated with the client
+identifier and/or ``chaddr``. The server first uses the client
+identifier (if present) to search for the lease; if one is found, the
+server treats this lease as belonging to the client, even if the
+current ``chaddr`` and the ``chaddr`` associated with the lease do not
+match. This facilitates the scenario when the network card on the client
+system has been replaced and thus the new MAC address appears in the
+messages sent by the DHCP client. If the server fails to find the lease
+using the client identifier, it performs another lookup using the
+``chaddr``. If this lookup returns no result, the client is considered to
+not have a lease and a new lease is created.
+
+A common problem reported by network operators is that poor client
+implementations do not use stable client identifiers, instead generating
+a new client identifier each time the client connects to the network.
+Another well-known case is when the client changes its client
+identifier during the multi-stage boot process (PXE). In such cases,
+the MAC address of the client's interface remains stable, and using the
+``chaddr`` field to identify the client guarantees that the particular
+system is considered to be the same client, even though its client
+identifier changes.
+
+To address this problem, Kea includes a configuration option which
+enables client identification using ``chaddr`` only. This instructs the
+server to ignore the client identifier during lease lookups and allocations
+for a particular subnet. Consider the following simplified server configuration:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "match-client-id": true,
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.10.0/24",
+ "pools": [ { "pool": "192.0.2.23-192.0.2.87" } ],
+ "match-client-id": false
+ },
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "pools": [ { "pool": "10.0.0.23-10.0.2.99" } ]
+ }
+ ]
+ }
+ }
+
+The ``match-client-id`` parameter is a boolean value which controls this
+behavior. The default value of ``true`` indicates that the server will use
+the client identifier for lease lookups and ``chaddr`` if the first lookup
+returns no results. ``false`` means that the server will only use
+the ``chaddr`` to search for the client's lease. Whether the DHCID for DNS
+updates is generated from the client identifier or ``chaddr`` is
+controlled through the same parameter.
+
+The ``match-client-id`` parameter may appear both in the global
+configuration scope and/or under any subnet declaration. In the example
+shown above, the effective value of the ``match-client-id`` will be
+``false`` for the subnet 192.0.10.0/24, because the subnet-specific
+setting of the parameter overrides the global value of the parameter.
+The effective value of the ``match-client-id`` for the subnet 10.0.0.0/8
+will be set to ``true``, because the subnet declaration lacks this
+parameter and the global setting is by default used for this subnet. In
+fact, the global entry for this parameter could be omitted in this case,
+because ``true`` is the default value.
+
+It is important to understand what happens when the client obtains its
+lease for one setting of the ``match-client-id`` and then renews it when
+the setting has been changed. First, consider the case when the client
+obtains the lease and the ``match-client-id`` is set to ``true``. The
+server stores the lease information, including the client identifier
+(if supplied) and ``chaddr``, in the lease database. When the setting is
+changed and the client renews the lease, the server will determine that
+it should use the ``chaddr`` to search for the existing lease. If the
+client has not changed its MAC address, the server should successfully
+find the existing lease. The client identifier associated with the
+returned lease will be ignored and the client will be allowed to use this lease.
+When the lease is renewed only the ``chaddr`` will be recorded for this lease,
+according to the new server setting.
+
+In the second case, the client has the lease with only a ``chaddr`` value
+recorded. When the ``match-client-id`` setting is changed to ``true``,
+the server will first try to use the client identifier to find the
+existing client's lease. This will return no results because the client
+identifier was not recorded for this lease. The server will then use
+the ``chaddr`` and the lease will be found. If the lease appears to have
+no client identifier recorded, the server will assume that this lease
+belongs to the client and that it was created with the previous setting
+of the ``match-client-id``. However, if the lease contains a client
+identifier which is different from the client identifier used by the
+client, the lease will be assumed to belong to another client and a
+new lease will be allocated.
+
+For a more visual representation of how Kea recognizes the same client,
+check :ref:`uml-recognizing-same-client`.
+
+.. _dhcp4-authoritative:
+
+Authoritative DHCPv4 Server Behavior
+------------------------------------
+
+The original DHCPv4 specification (`RFC
+2131 <https://tools.ietf.org/html/rfc2131>`__) states that if a client
+requests an address in the INIT-REBOOT state of which the server has no
+knowledge, the server must remain silent, except if the server knows
+that the client has requested an IP address from the wrong network. By
+default, Kea follows the behavior of the ISC ``dhcpd`` daemon instead of the
+specification and also remains silent if the client requests an IP
+address from the wrong network, because configuration information about
+a given network segment is not known to be correct. Kea only rejects a
+client's DHCPREQUEST with a DHCPNAK message if it already has a lease
+for the client with a different IP address. Administrators can
+override this behavior through the boolean ``authoritative`` (``false``
+by default) setting.
+
+In authoritative mode, ``authoritative`` set to ``true``, Kea always
+rejects INIT-REBOOT requests from unknown clients with DHCPNAK messages.
+The ``authoritative`` setting can be specified in global,
+shared-network, and subnet configuration scope and is automatically
+inherited from the parent scope, if not specified. All subnets in a
+shared-network must have the same ``authoritative`` setting.
+
+.. _dhcp4-dhcp4o6-config:
+
+DHCPv4-over-DHCPv6: DHCPv4 Side
+-------------------------------
+
+The support of DHCPv4-over-DHCPv6 transport is described in `RFC
+7341 <https://tools.ietf.org/html/rfc7341>`__ and is implemented using
+cooperating DHCPv4 and DHCPv6 servers. This section is about the
+configuration of the DHCPv4 side (the DHCPv6 side is described in
+:ref:`dhcp6-dhcp4o6-config`).
+
+.. note::
+
+ DHCPv4-over-DHCPv6 support is experimental and the details of the
+ inter-process communication may change; for instance, the
+ support of port relay (RFC 8357) introduced an incompatible change.
+ Both the DHCPv4 and DHCPv6 sides should be running the same version of Kea.
+
+The ``dhcp4o6-port`` global parameter specifies the first of the two
+consecutive ports of the UDP sockets used for the communication between
+the DHCPv6 and DHCPv4 servers. The DHCPv4 server is bound to ::1 on
+``port`` + 1 and connected to ::1 on ``port``.
+
+With DHCPv4-over-DHCPv6, the DHCPv4 server does not have access to
+several of the identifiers it would normally use to select a subnet. To
+address this issue, three new configuration entries are available; the
+presence of any of these allows the subnet to be used with
+DHCPv4-over-DHCPv6. These entries are:
+
+- ``4o6-subnet``: takes a prefix (i.e., an IPv6 address followed by a
+ slash and a prefix length) which is matched against the source
+ address.
+
+- ``4o6-interface-id``: takes a relay interface ID option value.
+
+- ``4o6-interface``: takes an interface name which is matched against
+ the incoming interface name.
+
+ISC tested the following configuration:
+
+::
+
+ {
+
+ # DHCPv4 conf
+ "Dhcp4": {
+
+ "interfaces-config": {
+ "interfaces": [ "eno33554984" ]
+ },
+
+ "lease-database": {
+ "type": "memfile",
+ "name": "leases4"
+ },
+
+ "valid-lifetime": 4000,
+
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.10.10.0/24",
+ "4o6-interface": "eno33554984",
+ "4o6-subnet": "2001:db8:1:1::/64",
+ "pools": [ { "pool": "10.10.10.100 - 10.10.10.199" } ]
+ }
+ ],
+
+ "dhcp4o6-port": 6767,
+
+ "loggers": [
+ {
+ "name": "kea-dhcp4",
+ "output-options": [
+ {
+ "output": "/tmp/kea-dhcp4.log"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 0
+ }
+ ]
+ }
+
+ }
+
+.. _sanity-checks4:
+
+Sanity Checks in DHCPv4
+-----------------------
+
+An important aspect of a well-running DHCP system is an assurance that
+the data remains consistent; however, in some cases it may be convenient
+to tolerate certain inconsistent data. For example, a network
+administrator who temporarily removes a subnet from a configuration
+would not want all the leases associated with it to disappear from the
+lease database. Kea has a mechanism to implement sanity checks for situations
+like this.
+
+Kea supports a configuration scope called ``sanity-checks``.
+A parameter, called ``lease-checks``,
+governs the verification carried out when a new lease is loaded from a
+lease file. This mechanism permits Kea to attempt to correct inconsistent data.
+
+Every subnet has a ``subnet-id`` value; this is how Kea internally
+identifies subnets. Each lease has a ``subnet-id`` parameter as well, which
+identifies the subnet it belongs to. However, if the configuration has
+changed, it is possible that a lease could exist with a ``subnet-id`` but
+without any subnet that matches it. Also, it is possible that the
+subnet's configuration has changed and the ``subnet-id`` now belongs to a
+subnet that does not match the lease.
+
+Kea's corrective algorithm first
+checks to see if there is a subnet with the ``subnet-id`` specified by the
+lease. If there is, it verifies whether the lease belongs to that
+subnet. If not, depending on the ``lease-checks`` setting, the lease is
+discarded, a warning is displayed, or a new subnet is selected for the
+lease that matches it topologically.
+
+There are five levels which are supported:
+
+- ``none`` - do no special checks; accept the lease as is.
+
+- ``warn`` - if problems are detected display a warning, but
+ accept the lease data anyway. This is the default value.
+
+- ``fix`` - if a data inconsistency is discovered, try to
+ correct it. If the correction is not successful, insert the incorrect data
+ anyway.
+
+- ``fix-del`` - if a data inconsistency is discovered, try to
+ correct it. If the correction is not successful, reject the lease.
+ This setting ensures the data's correctness, but some
+ incorrect data may be lost. Use with care.
+
+- ``del`` - if any inconsistency is
+ detected, reject the lease. This is the strictest mode; use with care.
+
+This feature is currently implemented for the memfile backend. The
+sanity check applies to the lease database in memory, not to the lease file,
+i.e. inconsistent leases will stay in the lease file.
+
+An example configuration that sets this parameter looks as follows:
+
+::
+
+ "Dhcp4": {
+ "sanity-checks": {
+ "lease-checks": "fix-del"
+ },
+ ...
+ }
+
+.. _dhcp4-store-extended-info:
+
+Storing Extended Lease Information
+----------------------------------
+
+To support such features as DHCP Leasequery
+(`RFC 4388 <https://tools.ietf.org/html/rfc4388>`__),
+additional information must be stored with each lease. Because the amount
+of information for each lease has ramifications in terms of
+performance and system resource consumption, storage of this additional
+information is configurable through the ``store-extended-info`` parameter.
+It defaults to ``false`` and may be set at the global, shared-network, and
+subnet levels.
+
+::
+
+ "Dhcp4": {
+ "store-extended-info": true,
+ ...
+ }
+
+When set to ``true``, information relevant to the DHCPREQUEST asking for the lease is
+added into the lease's user-context as a map element labeled "ISC". Since
+Kea version 2.3.2, when the DHCPREQUEST received contains the option
+(DHCP Option 82), the map contains the ``relay-agent-info`` map
+with the content option (DHCP Option 82) in the ``sub-options`` entry and,
+when present, the ``remote-id`` and ``relay-id`` options.
+Since DHCPREQUESTs sent as renewals are not likely to contain this
+information, the values taken from the last DHCPREQUEST that did contain it are
+retained on the lease. The lease's user-context looks something like this:
+
+::
+
+ { "ISC": { "relay-agent-info": { "sub-options": "0x0104AABBCCDD" } } }
+
+Or with remote and relay sub-options:
+
+::
+
+ {
+ "ISC": {
+ "relay-agent-info": {
+ "sub-options": "0x02030102030C03AABBCC",
+ "remote-id": "03010203",
+ "relay-id": "AABBCC"
+ }
+ }
+ }
+
+.. note::
+
+ It is possible that other hook libraries are already using ``user-context``.
+ Enabling ``store-extended-info`` should not interfere with any other ``user-context``
+ content, as long as it does not also use an element labeled "ISC". In other
+ words, ``user-context`` is intended to be a flexible container serving multiple
+ purposes. As long as no other purpose also writes an "ISC" element to
+ ``user-context`` there should not be a conflict.
+
+Extended lease information is also subject to configurable sanity checking.
+The parameter in the ``sanity-checks`` scope is named ``extended-info-checks``
+and supports these levels:
+
+- ``none`` - do no check nor upgrade. This level should be used only when
+ extended info is not used at all or when no badly formatted extended
+ info, including using the old format, is expected.
+
+- ``fix`` - fix some common inconsistencies and upgrade extended info
+ using the old format to the new one. It is the default level and is
+ convenient when the Leasequery hook library is not loaded.
+
+- ``strict`` - fix all inconsistencies which have an impact on the (Bulk)
+ Leasequery hook library.
+
+- ``pedantic`` - enforce full conformance to the format produced by the
+ Kea code; for instance, no extra entries are allowed with the exception
+ of ``comment``.
+
+.. note::
+
+ This feature is currently implemented only for the memfile
+ backend. The sanity check applies to the lease database in memory,
+ not to the lease file, i.e. inconsistent leases stay in the lease
+ file.
+
+.. _dhcp4-multi-threading-settings:
+
+Multi-Threading Settings
+------------------------
+
+The Kea server can be configured to process packets in parallel using multiple
+threads. These settings can be found under the ``multi-threading`` structure and are
+represented by:
+
+- ``enable-multi-threading`` - use multiple threads to process packets in
+ parallel. The default is ``true``.
+
+- ``thread-pool-size`` - specify the number of threads to process packets in
+ parallel. It may be set to ``0`` (auto-detect), or any positive number that
+ explicitly sets the thread count. The default is ``0``.
+
+- ``packet-queue-size`` - specify the size of the queue used by the thread
+ pool to process packets. It may be set to ``0`` (unlimited), or any positive
+ number that explicitly sets the queue size. The default is ``64``.
+
+An example configuration that sets these parameters looks as follows:
+
+::
+
+ "Dhcp4": {
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "thread-pool-size": 4,
+ "packet-queue-size": 16
+ },
+ ...
+ }
+
+Multi-Threading Settings With Different Database Backends
+---------------------------------------------------------
+
+The Kea DHCPv4 server is benchmarked by ISC to determine which settings
+give the best performance. Although this section describes our results, they are merely
+recommendations and are very dependent on the particular hardware used
+for benchmarking. We strongly advise that administrators run their own performance benchmarks.
+
+A full report of performance results for the latest stable Kea version can be found
+`here <https://reports.kea.isc.org/>`_.
+This includes hardware and benchmark scenario descriptions, as well as
+current results.
+
+After enabling multi-threading, the number of threads is set by the ``thread-pool-size``
+parameter. Results from our experiments show that the best settings for
+:iscman:`kea-dhcp4` are:
+
+- ``thread-pool-size``: 4 when using ``memfile`` for storing leases.
+
+- ``thread-pool-size``: 12 or more when using ``mysql`` for storing leases.
+
+- ``thread-pool-size``: 8 when using ``postgresql``.
+
+Another very important parameter is ``packet-queue-size``; in our benchmarks we
+used it as a multiplier of ``thread-pool-size``. The actual setting strongly depends
+on ``thread-pool-size``.
+
+We saw the best results in our benchmarks with the following settings:
+
+- ``packet-queue-size``: 7 * ``thread-pool-size`` when using ``memfile`` for
+ storing leases; in our case it was 7 * 4 = 28. This means that at any given
+ time, up to 28 packets could be queued.
+
+- ``packet-queue-size``: 66 * ``thread-pool-size`` when using ``mysql`` for
+ storing leases; in our case it was 66 * 12 = 792. This means that up to
+ 792 packets could be queued.
+
+- ``packet-queue-size``: 11 * ``thread-pool-size`` when using ``postgresql`` for
+ storing leases; in our case it was 11 * 8 = 88.
+
+IPv6-Only Preferred Networks
+----------------------------
+
+`RFC8925 <https://tools.ietf.org/html/rfc8925>`_, recently published by the IETF,
+specifies a DHCPv4 option to indicate that a host supports an IPv6-only mode and is willing to
+forgo obtaining an IPv4 address if the network provides IPv6 connectivity. The general idea is that
+a network administrator can enable this option to signal to compatible dual-stack devices that
+IPv6 connectivity is available and they can shut down their IPv4 stack. The new option
+``v6-only-preferred`` content is a 32-bit unsigned integer and specifies for how long the device
+should disable its stack. The value is expressed in seconds.
+
+The RFC mentions the ``V6ONLY_WAIT`` timer. This is implemented in Kea by setting the value of
+the ``v6-only-preferred`` option. This follows the usual practice of setting options; the
+option value can be specified on the pool, subnet, shared network, or global levels, or even
+via host reservations.
+
+There is no special processing involved; it follows the standard Kea option processing
+regime. The option is not sent back unless the client explicitly requests it. For example, to
+enable the option for the whole subnet, the following configuration can be used:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ "subnet": "192.0.2.0/24",
+ "option-data": [
+ {
+ // This will make the v6-only capable devices to disable their
+ // v4 stack for half an hour and then try again
+ "name": "v6-only-preferred",
+ "data": "1800"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+Lease Caching
+-------------
+
+Clients that attempt multiple renewals in a short period can cause the server to update
+and write to the database frequently, resulting in a performance impact
+on the server. The cache parameters instruct the DHCP server to avoid
+updating leases too frequently, thus avoiding this behavior. Instead,
+the server assigns the same lease (i.e. reuses it) with no
+modifications except for CLTT (Client Last Transmission Time), which
+does not require disk operations.
+
+The two parameters are the ``cache-threshold`` double and the
+``cache-max-age`` integer; they have no default setting, i.e. the lease caching
+feature must be explicitly enabled. These parameters can be configured
+at the global, shared-network, and subnet levels. The subnet level has
+precedence over the shared-network level, while the global level is used
+as a last resort. For example:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ "subnet": "192.0.2.0/24",
+ "cache-threshold": .25,
+ "cache-max-age": 600,
+ "valid-lifetime": 2000,
+ ...
+ }
+ ],
+ ...
+ }
+
+When an already-assigned lease can fulfill a client query:
+
+ - any important change, e.g. for DDNS parameter, hostname, or
+ valid lifetime reduction, makes the lease not reusable.
+
+ - lease age, i.e. the difference between the creation or last modification
+ time and the current time, is computed (elapsed duration).
+
+ - if ``cache-max-age`` is explicitly configured, it is compared with the lease age;
+ leases that are too old are not reusable. This means that the value 0
+ for ``cache-max-age`` disables the lease cache feature.
+
+ - if ``cache-threshold`` is explicitly configured and is between 0.0 and 1.0,
+ it expresses the percentage of the lease valid lifetime which is
+ allowed for the lease age. Values below and including 0.0 and
+ values greater than 1.0 disable the lease cache feature.
+
+In our example, a lease with a valid lifetime of 2000 seconds can be
+reused if it was committed less than 500 seconds ago. With a lifetime
+of 3000 seconds, a maximum age of 600 seconds applies.
+
+In outbound client responses (e.g. DHCPACK messages), the
+``dhcp-lease-time`` option is set to the reusable valid lifetime,
+i.e. the expiration date does not change. Other options based on the
+valid lifetime e.g. ``dhcp-renewal-time`` and ``dhcp-rebinding-time``,
+also depend on the reusable lifetime.
+
+Temporary Allocation on DHCPDISCOVER
+------------------------------------
+
+By default, :iscman:`kea-dhcp4` does not allocate or store a lease when offering an address
+to a client in response to a DHCPDISCOVER. In general, :iscman:`kea-dhcp4` can fulfill client
+demands faster by deferring lease allocation and storage until it receives DHCPREQUESTs
+for them. Release 2.3.6 added a new parameter to :iscman:`kea-dhcp4`, ``offer-lifetime``, which
+(when not zero) instructs the server to allocate and persist a lease when generating a
+DHCPOFFER. In addition:
+
+- The persisted lease's lifetime is equal to ``offer-lifetime`` (in seconds).
+
+- The lifetime sent to the client in the DHCPOFFER via option 51 is still based
+ on ``valid-lifetime``. This avoids issues with clients that may reject offers whose
+ lifetimes they perceive as too short.
+
+- DDNS updates are not performed. As with the default behavior, those updates occur on DHCPREQUEST.
+
+- Updates are not sent to HA peers.
+
+- Assigned lease statistics are incremented.
+
+- Expiration processing and reclamation behave just as they do for leases allocated
+ during DHCPREQUEST processing.
+
+- Lease caching, if enabled, is honored.
+
+- In sites running multiple instances of :iscman:`kea-dhcp4` against a single, shared lease store, races
+ for given address values are lost during DHCPDISCOVER processing rather than during DHCPREQUEST
+ processing. Servers that lose the race for the address simply do not respond to the client,
+ rather than NAK them. The client in turn simply retries its DHCPDISCOVER. This should reduce
+ the amount of traffic such conflicts incur.
+
+- Clients repeating DHCPDISCOVERs are offered the same address each time.
+
+An example subnet configuration is shown below:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ "subnet": "192.0.2.0/24",
+ "offer-lifetime": 60,
+ "valid-lifetime": 2000,
+ ...
+ }
+ ],
+ ...
+ }
+
+Here ``offer-lifetime`` has been configured to be 60 seconds, with a ``valid-lifetime``
+of 2000 seconds. This instructs :iscman:`kea-dhcp4` to persist leases for 60 seconds when
+sending them back in DHCPOFFERs, and then extend them to 2000 seconds when clients
+DHCPREQUEST them.
+
+The value, which defaults to 0, is supported at the global, shared-network, subnet,
+and class levels. Choosing an appropriate value for ``offer-lifetime`` is extremely
+site-dependent, but a value between 60 and 120 seconds is a reasonable starting
+point.
+
+.. _dnr4-options:
+
+DNR (Discovery of Network-designated Resolvers) Options for DHCPv4
+------------------------------------------------------------------
+
+One of the more recently added options is the Discovery of
+Network-designated Resolvers or DNR option,
+introduced in `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The goal of that RFC is
+to provide a way to communicate location of DNS resolvers available over means other than
+the classic DNS over UDP over port 53. At the time of this writing, the supported technologies
+are DoT (DNS-over-TLS), DoH (DNS-over-HTTPS), and DoQ (DNS-over-QUIC), but the option was
+designed to be extensible to accommodate other protocols in the future.
+
+The DHCPv4 option and its corresponding DHCPv6 options are almost exactly the same,
+with the exception of cardinality. Only one DHCPv4 option is allowed, while for DHCPv6
+multiple options are allowed. To be able to convey multiple entries, the DHCPv4 is an
+array that allows multiple DNS instances. Each instance is logically equal to one
+DHCPv6 option, except the minor difference of using IPv4 rather than IPv6 addresses.
+
+For detailed example how to configure DNR option, see :ref:`dnr6-options`.
+The only difference for DNR DHCPv4 options configuration is that it allows
+to configure more than one DNR instance and the DNR instances are separated
+with the "pipe" (``0x7C``) character.
+For each DNR Instance comma delimited fields must be provided in the following order:
+
+- Service Priority (mandatory),
+- ADN FQDN (mandatory),
+- IP address(es) (optional - if more than one - they must be space-separated)
+- SvcParams as a set of key=value pairs (optional - if more than one - they must be space-separated;
+ to provide more than one alpn-id separate them with double backslash escaped comma like in the
+ example below).
+
+Example usage:
+
+::
+
+ {
+ "name": "v4-dnr",
+ // 2 DNR Instances:
+ // - Service priority 2, ADN, resolver IPv4 address and Service Parameters
+ // - Service priority 3, ADN - this is ADN-only mode as per RFC9463 3.1.6
+ "data": "2, resolver.example., 10.0.5.6, alpn=dot\\,doq port=8530 | 3, fooexp.resolver.example."
+ }
+
+
+.. note::
+
+ Note that whenever "comma" or "pipe" characters need to be used not as the delimiters, they must be escaped with
+ double backslash (``\\,`` or ``\\|``). E.g. one must use escaped commas when configuring more than one ``ALPN``
+ protocol to separate them. One might want to use "pipe" (``0x7C``) character in ``dohpath`` Service Parameter,
+ as it is allowed in URI. In that case it must be escaped with double backslash.
+
+Examples for DNR DHCPv4 options are provided in the Kea sources in
+`all-options.json` in the `doc/examples/kea4` directory.
+
+
+.. _host-reservation-v4:
+
+Host Reservations in DHCPv4
+===========================
+
+There are many cases where it is useful to provide a configuration on a
+per-host basis. The most obvious one is to reserve a specific, static
+address for exclusive use by a given client (host); the returning client
+receives the same address from the server every time, and other
+clients generally do not receive that address. Host
+reservations are also convenient when a host has
+specific requirements, e.g. a printer that needs additional DHCP
+options. Yet another possible use case is to define unique names for
+hosts.
+
+There may be cases when a new reservation has been made for a
+client for an address currently in use by another client. We call this
+situation a "conflict."
+These conflicts get resolved automatically over time, as described in
+subsequent sections. Once a conflict is resolved, the correct client will
+receive the reserved configuration when it renews.
+
+Host reservations are defined as parameters for each subnet. Each host
+must have its own unique identifier, such as the hardware/MAC
+address. There is an optional ``reservations`` array in the ``subnet4``
+structure; each element in that array is a structure that holds
+information about reservations for a single host. In particular, the
+structure has an identifier that uniquely identifies a host. In
+the DHCPv4 context, the identifier is usually a hardware or MAC address.
+In most cases an IP address will be specified. It is also possible to
+specify a hostname, host-specific options, or fields carried within the
+DHCPv4 message such as ``siaddr``, ``sname``, or ``file``.
+
+.. note::
+
+ The reserved address must be within the subnet.
+
+The following example shows how to reserve addresses for specific hosts
+in a subnet:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
+ "subnet": "192.0.2.0/24",
+ "interface": "eth0",
+ "reservations": [
+ {
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "ip-address": "192.0.2.202"
+ },
+ {
+ "duid": "0a:0b:0c:0d:0e:0f",
+ "ip-address": "192.0.2.100",
+ "hostname": "alice-laptop"
+ },
+ {
+ "circuit-id": "'charter950'",
+ "ip-address": "192.0.2.203"
+ },
+ {
+ "client-id": "01:11:22:33:44:55:66",
+ "ip-address": "192.0.2.204"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+The first entry reserves the 192.0.2.202 address for the client that
+uses a MAC address of 1a:1b:1c:1d:1e:1f. The second entry reserves the
+address 192.0.2.100 and the hostname of "alice-laptop" for the client
+using a DUID 0a:0b:0c:0d:0e:0f. (If DNS updates are planned,
+it is strongly recommended that the hostnames be unique.) The
+third example reserves address 192.0.3.203 for a client whose request
+would be relayed by a relay agent that inserts a ``circuit-id`` option with
+the value "charter950". The fourth entry reserves address 192.0.2.204
+for a client that uses a client identifier with value
+01:11:22:33:44:55:66.
+
+The above example is used for illustrational purposes only; in actual
+deployments it is recommended to use as few types as possible
+(preferably just one). See :ref:`reservations4-tuning` for a detailed discussion of this
+point.
+
+Making a reservation for a mobile host that may visit multiple subnets
+requires a separate host definition in each subnet that host is expected to
+visit. It is not possible to define multiple host definitions with the
+same hardware address in a single subnet. Multiple host definitions with
+the same hardware address are valid if each is in a different subnet.
+
+Adding host reservations incurs a performance penalty. In principle, when
+a server that does not support host reservation responds to a query, it
+needs to check whether there is a lease for a given address being
+considered for allocation or renewal. The server that does support host
+reservation has to perform additional checks: not only whether the
+address is currently used (i.e., if there is a lease for it), but also
+whether the address could be used by someone else (i.e., if there is a
+reservation for it). That additional check incurs extra overhead.
+
+.. _reservation4-types:
+
+Address Reservation Types
+-------------------------
+
+In a typical Kea scenario there is an IPv4 subnet defined, e.g.
+192.0.2.0/24, with a certain part of it dedicated for dynamic allocation
+by the DHCPv4 server. That dynamic part is referred to as a dynamic pool
+or simply a pool. In principle, a host reservation can reserve any
+address that belongs to the subnet. The reservations that specify
+addresses that belong to configured pools are called "in-pool
+reservations." In contrast, those that do not belong to dynamic pools
+are called "out-of-pool reservations." There is no formal difference in
+the reservation syntax and both reservation types are handled uniformly.
+
+Kea supports global host reservations. These are reservations that are
+specified at the global level within the configuration and that do not
+belong to any specific subnet. Kea still matches inbound client
+packets to a subnet as before, but when the subnet's reservation mode is
+set to "global", Kea looks for host reservations only among the
+global reservations defined. Typically, such reservations would be used
+to reserve hostnames for clients which may move from one subnet to
+another.
+
+.. note::
+
+ Global reservations, while useful in certain circumstances, have aspects
+ that must be given due consideration when using them. Please see
+ :ref:`reservation4-conflict` for more details.
+
+.. note::
+
+ Since Kea 1.9.1, reservation mode has been replaced by three
+ boolean flags, ``reservations-global``, ``reservations-in-subnet``,
+ and ``reservations-out-of-pool``, which allow the configuration of
+ host reservations both globally and in a subnet. In such cases a subnet
+ host reservation has preference over a global reservation
+ when both exist for the same client.
+
+.. _reservation4-conflict:
+
+Conflicts in DHCPv4 Reservations
+--------------------------------
+
+As reservations and lease information are stored separately, conflicts
+may arise. Consider the following series of events: the server has
+configured the dynamic pool of addresses from the range of 192.0.2.10 to
+192.0.2.20. Host A requests an address and gets 192.0.2.10. Now the
+system administrator decides to reserve address 192.0.2.10 for Host B.
+In general, reserving an address that is currently assigned to someone
+else is not recommended, but there are valid use cases where such an
+operation is warranted.
+
+The server now has a conflict to resolve. If Host B boots up and
+requests an address, the server cannot immediately assign the reserved
+address 192.0.2.10. A naive approach would to be immediately remove the
+existing lease for Host A and create a new one for Host B. That would
+not solve the problem, though, because as soon as Host B gets the
+address, it will detect that the address is already in use (by Host A) and
+will send a DHCPDECLINE message. Therefore, in this situation, the
+server has to temporarily assign a different address from the dynamic
+pool (not matching what has been reserved) to Host B.
+
+When Host A renews its address, the server will discover that the
+address being renewed is now reserved for another host - Host B.
+The server will inform Host A that it is no longer allowed to
+use it by sending a DHCPNAK message. The server will not remove the
+lease, though, as there's a small chance that the DHCPNAK will not be delivered if
+the network is lossy. If that happens, the client will not receive any
+responses, so it will retransmit its DHCPREQUEST packet. Once the
+DHCPNAK is received by Host A, it will revert to server discovery and
+will eventually get a different address. Besides allocating a new lease,
+the server will also remove the old one. As a result, address 192.0.2.10
+will become free.
+
+When Host B tries to renew its temporarily assigned
+address, the server will detect that it has a valid lease, but will note
+that there is a reservation for a different address. The server will
+send DHCPNAK to inform Host B that its address is no longer usable, but
+will keep its lease (again, the DHCPNAK may be lost, so the server will
+keep it until the client returns for a new address). Host B will revert
+to the server discovery phase and will eventually send a DHCPREQUEST
+message. This time the server will find that there is a reservation for
+that host and that the reserved address 192.0.2.10 is not used, so it
+will be granted. It will also remove the lease for the temporarily
+assigned address that Host B previously obtained.
+
+This recovery will succeed, even if other hosts attempt to get the
+reserved address. If Host C requests the address 192.0.2.10 after the
+reservation is made, the server will either offer a different address
+(when responding to DHCPDISCOVER) or send DHCPNAK (when responding to
+DHCPREQUEST).
+
+This mechanism allows the server to fully recover from a case
+where reservations conflict with existing leases; however, this procedure
+takes roughly as long as the value set for ``renew-timer``. The
+best way to avoid such a recovery is not to define new reservations that
+conflict with existing leases. Another recommendation is to use
+out-of-pool reservations; if the reserved address does not belong to a
+pool, there is no way that other clients can get it.
+
+.. note::
+
+ The conflict-resolution mechanism does not work for global
+ reservations. Although the global address reservations feature may be useful
+ in certain settings, it is generally recommended not to use
+ global reservations for addresses. Administrators who do choose
+ to use global reservations must manually ensure that the reserved
+ addresses are not in dynamic pools.
+
+.. _reservation4-hostname:
+
+Reserving a Hostname
+--------------------
+
+When the reservation for a client includes the ``hostname``, the server
+returns this hostname to the client in the Client FQDN or Hostname
+option. The server responds with the Client FQDN option only if the
+client has included the Client FQDN option in its message to the server. The
+server responds with the Hostname option if the client included
+the Hostname option in its message to the server, or if the client
+requested the Hostname option using the Parameter Request List option.
+The server returns the Hostname option even if it is not configured
+to perform DNS updates. The reserved hostname always takes precedence
+over the hostname supplied by the client or the autogenerated (from the
+IPv4 address) hostname.
+
+The server qualifies the reserved hostname with the value of the
+``ddns-qualifying-suffix`` parameter. For example, the following subnet
+configuration:
+
+.. code-block:: json
+
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
+ "ddns-qualifying-suffix": "example.isc.org.",
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "hostname": "alice-laptop"
+ }
+ ]
+ }
+ ],
+ "dhcp-ddns": {
+ "enable-updates": true
+ }
+ }
+
+will result in the "alice-laptop.example.isc.org." hostname being assigned to
+the client using the MAC address "aa:bb:cc:dd:ee:ff". If the
+``ddns-qualifying-suffix`` is not specified, the default (empty) value will
+be used, and in this case the value specified as a ``hostname`` will be
+treated as a fully qualified name. Thus, by leaving the
+``ddns-qualifying-suffix`` empty it is possible to qualify hostnames for
+different clients with different domain names:
+
+.. code-block:: json
+
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "hostname": "alice-laptop.isc.org."
+ },
+ {
+ "hw-address": "12:34:56:78:99:AA",
+ "hostname": "mark-desktop.example.org."
+ }
+ ]
+ }
+ ],
+ "dhcp-ddns": {
+ "enable-updates": true
+ }
+ }
+
+The above example results in the assignment of the
+"alice-laptop.isc.org." hostname to the client using the MAC
+address "aa:bb:cc:dd:ee:ff", and the hostname "mark-desktop.example.org."
+to the client using the MAC address "12:34:56:78:99:AA".
+
+.. _reservation4-options:
+
+Including Specific DHCPv4 Options in Reservations
+-------------------------------------------------
+
+Kea offers the ability to specify options on a per-host basis. These
+options follow the same rules as any other options. These can be
+standard options (see :ref:`dhcp4-std-options`),
+custom options (see :ref:`dhcp4-custom-options`),
+or vendor-specific options (see :ref:`dhcp4-vendor-opts`). The following
+example demonstrates how standard options can be defined:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "ip-address": "192.0.2.1",
+ "option-data": [
+ {
+ "name": "cookie-servers",
+ "data": "10.1.1.202,10.1.1.203"
+ },
+ {
+ "name": "log-servers",
+ "data": "10.1.1.200,10.1.1.201"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+ ],
+ ...
+ }
+
+Vendor-specific options can be reserved in a similar manner:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "ip-address": "10.0.0.7",
+ "option-data": [
+ {
+ "name": "vivso-suboptions",
+ "data": "4491"
+ },
+ {
+ "name": "tftp-servers",
+ "space": "vendor-4491",
+ "data": "10.1.1.202,10.1.1.203"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+ ],
+ ...
+ }
+
+Options defined at the host level have the highest priority. In other words,
+if there are options defined with the same type on the global, subnet,
+class, and host levels, the host-specific values are used.
+
+.. _reservation4-message-fields:
+
+Reserving Next Server, Server Hostname, and Boot File Name
+----------------------------------------------------------
+
+BOOTP/DHCPv4 messages include "siaddr", "sname", and "file" fields. Even
+though DHCPv4 includes corresponding options, such as option 66 and
+option 67, some clients may not support these options. For this reason,
+server administrators often use the "siaddr", "sname", and "file" fields
+instead.
+
+With Kea, it is possible to make static reservations for these DHCPv4
+message fields:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "next-server": "10.1.1.2",
+ "server-hostname": "server-hostname.example.org",
+ "boot-file-name": "/tmp/bootfile.efi"
+ }
+ ],
+ ...
+ }
+ ],
+ ...
+ }
+
+Note that those parameters can be specified in combination with other
+parameters for a reservation, such as a reserved IPv4 address. These
+parameters are optional; a subset of them can be specified, or all
+of them can be omitted.
+
+.. _reservation4-client-classes:
+
+Reserving Client Classes in DHCPv4
+----------------------------------
+
+:ref:`classification-using-expressions` explains how to configure
+the server to assign classes to a client, based on the content of the
+options that this client sends to the server. Host reservation
+mechanisms also allow for the static assignment of classes to clients.
+The definitions of these classes are placed in the Kea configuration file or
+a database. The following configuration snippet shows how to specify that
+a client belongs to the classes ``reserved-class1`` and ``reserved-class2``. Those
+classes are associated with specific options sent to the clients which belong
+to them.
+
+::
+
+ {
+ "client-classes": [
+ {
+ "name": "reserved-class1",
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "10.0.0.200"
+ }
+ ]
+ },
+ {
+ "name": "reserved-class2",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "10.0.0.201"
+ }
+ ]
+ }
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+
+ "client-classes": [ "reserved-class1", "reserved-class2" ]
+
+ }
+ ]
+ }
+ ]
+ }
+
+In some cases the host reservations can be used in conjunction with client
+classes specified within the Kea configuration. In particular, when a
+host reservation exists for a client within a given subnet, the "KNOWN"
+built-in class is assigned to the client. Conversely, when there is no
+static assignment for the client, the "UNKNOWN" class is assigned to the
+client. Class expressions within the Kea configuration file can
+refer to "KNOWN" or "UNKNOWN" classes using the "member" operator.
+For example:
+
+::
+
+ {
+ "client-classes": [
+ {
+ "name": "dependent-class",
+ "test": "member('KNOWN')",
+ "only-if-required": true
+ }
+ ]
+ }
+
+The ``only-if-required`` parameter is needed here to force evaluation
+of the class after the lease has been allocated and thus the reserved
+class has been also assigned.
+
+.. note::
+
+ The classes specified in non-global host reservations
+ are assigned to the processed packet after all classes with the
+ ``only-if-required`` parameter set to ``false`` have been evaluated.
+ This means that these classes must not depend on the
+ statically assigned classes from the host reservations. If
+ such a dependency is needed, the ``only-if-required`` parameter must
+ be set to ``true`` for the dependent classes. Such classes are
+ evaluated after the static classes have been assigned to the packet.
+ This, however, imposes additional configuration overhead, because
+ all classes marked as ``only-if-required`` must be listed in the
+ ``require-client-classes`` list for every subnet where they are used.
+
+.. note::
+
+ Client classes specified within the Kea configuration file may
+ depend on the classes specified within the global host reservations.
+ In such a case the ``only-if-required`` parameter is not needed.
+ Refer to :ref:`pool-selection-with-class-reservations4` and
+ :ref:`subnet-selection-with-class-reservations4`
+ for specific use cases.
+
+.. _reservations4-mysql-pgsql:
+
+Storing Host Reservations in MySQL or PostgreSQL
+------------------------------------------------
+
+Kea can store host reservations in MySQL or PostgreSQL.
+See :ref:`hosts4-storage` for information on how to
+configure Kea to use reservations stored in MySQL or PostgreSQL.
+Kea provides a dedicated hook for managing reservations in a
+database; section :ref:`hooks-host-cmds` provides detailed information.
+The `Kea wiki
+<https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands#23-host-reservations-hr-management>`__
+provides some examples of how to conduct common host reservation
+operations.
+
+.. note::
+
+ In Kea, the maximum length of an option specified per-host-reservation is
+ arbitrarily set to 4096 bytes.
+
+.. _reservations4-tuning:
+
+Fine-Tuning DHCPv4 Host Reservation
+-----------------------------------
+
+The host reservation capability introduces additional restrictions for
+the allocation engine (the component of Kea that selects an address for
+a client) during lease selection and renewal. In particular, three major
+checks are necessary. First, when selecting a new lease, it is not
+sufficient for a candidate lease to simply not be in use by another DHCP
+client; it also must not be reserved for another client. Similarly, when
+renewing a lease, an additional check must be performed to see whether
+the address being renewed is reserved for another client. Finally, when
+a host renews an address, the server must check whether there is a
+reservation for this host, which would mean the existing (dynamically allocated)
+address should be revoked and the reserved one be used instead.
+
+Some of those checks may be unnecessary in certain deployments, and not
+performing them may improve performance. The Kea server provides the
+``reservation-mode`` configuration parameter to select the types of
+reservations allowed for a particular subnet. Each reservation type has
+different constraints for the checks to be performed by the server when
+allocating or renewing a lease for the client. Although ``reservation-mode``
+was deprecated in Kea 1.9.1, it is still available; the allowed values are:
+
+- ``all`` - enables both in-pool and out-of-pool host reservation
+ types. This setting is the default value, and is the safest and most
+ flexible. However, as all checks are conducted, it is also the slowest.
+ It does not check against global reservations.
+
+- ``out-of-pool`` - allows only out-of-pool host reservations. With
+ this setting in place, the server assumes that all host
+ reservations are for addresses that do not belong to the dynamic
+ pool. Therefore, it can skip the reservation checks when dealing with
+ in-pool addresses, thus improving performance. Do not use this mode
+ if any reservations use in-pool addresses. Caution is advised
+ when using this setting; Kea does not sanity-check the reservations
+ against ``reservation-mode`` and misconfiguration may cause problems.
+
+- ``global`` - allows only global host reservations. With this setting
+ in place, the server searches for reservations for a client only
+ among the defined global reservations. If an address is specified,
+ the server skips the reservation checks carried out in
+ other modes, thus improving performance. Caution is advised when
+ using this setting; Kea does not sanity-check reservations when
+ ``global`` is set, and misconfiguration may cause problems.
+
+- ``disabled`` - host reservation support is disabled. As there are no
+ reservations, the server skips all checks. Any reservations
+ defined are completely ignored. As checks are skipped, the
+ server may operate faster in this mode.
+
+Since Kea 1.9.1, the ``reservation-mode`` parameter is replaced by the
+``reservations-global``, ``reservations-in-subnet``, and
+``reservations-out-of-pool`` flags.
+The flags can be activated independently and can produce various combinations,
+some of which were not supported by the deprecated ``reservation-mode``.
+
+The ``reservation-mode`` parameter can be specified at:
+
+- global level: ``.Dhcp4["reservation-mode"]`` (lowest priority: gets overridden
+ by all others)
+
+- subnet level: ``.Dhcp4.subnet4[]["reservation-mode"]`` (low priority)
+
+- shared-network level: ``.Dhcp4["shared-networks"][]["reservation-mode"]``
+ (high priority)
+
+- shared-network subnet-level:
+ ``.Dhcp4["shared-networks"][].subnet4[]["reservation-mode"]`` (highest
+ priority: overrides all others)
+
+To decide which ``reservation-mode`` to choose, the
+following decision diagram may be useful:
+
+::
+
+ O
+ |
+ v
+ +-----------------------------+------------------------------+
+ | Is per-host configuration needed, such as |
+ | reserving specific addresses, |
+ | assigning specific options or |
+ | assigning packets to specific classes on per-device basis? |
+ +-+-----------------+----------------------------------------+
+ | |
+ no| yes|
+ | | +--------------------------------------+
+ | | | For all given hosts, |
+ +--> "disabled" +-->+ can the reserved resources |
+ | be used in all configured subnets? |
+ +--------+---------------------------+-+
+ | |
+ +----------------------------+ |no |yes
+ | Is | | |
+ | at least one reservation +<--+ "global" <--+
+ | used to reserve addresses? |
+ +-+------------------------+-+
+ | |
+ no| yes| +---------------------------+
+ | | | Is high leases-per-second |
+ +--> "out-of-pool" +-->+ performance or efficient |
+ ^ | resource usage |
+ | | (CPU ticks, RAM usage, |
+ | | database roundtrips) |
+ | | important to your setup? |
+ | +-+----------------+--------+
+ | | |
+ | yes| no|
+ | | |
+ | +-------------+ |
+ | | |
+ | | +----------------------+ |
+ | | | Can it be guaranteed | |
+ | +-->+ that the reserved | |
+ | | addresses | |
+ | | aren't part of the | |
+ | | pools configured | |
+ | | in the respective | |
+ | | subnet? | |
+ | +-+------------------+-+ |
+ | | | |
+ | yes| no| |
+ | | | V
+ +----------------+ +--> "all"
+
+An example configuration that disables reservations looks as follows:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "192.0.2.10-192.0.2.100"
+ }
+ ],
+ "reservation-mode": "disabled",
+ "subnet": "192.0.2.0/24"
+ }
+ ]
+ }
+ }
+
+An example configuration using global reservations is shown below:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservation-mode": "global",
+ "reservations": [
+ {
+ "hostname": "host-one",
+ "hw-address": "01:bb:cc:dd:ee:ff"
+ },
+ {
+ "hostname": "host-two",
+ "hw-address": "02:bb:cc:dd:ee:ff"
+ }
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "192.0.2.10-192.0.2.100"
+ }
+ ],
+ "subnet": "192.0.2.0/24"
+ }
+ ]
+ }
+ }
+
+The meaning of the reservation flags are:
+
+- ``reservations-global``: fetch global reservations.
+
+- ``reservations-in-subnet``: fetch subnet reservations. For a shared network
+ this includes all subnet members of the shared network.
+
+- ``reservations-out-of-pool``: this makes sense only when the
+ ``reservations-in-subnet`` flag is ``true``. When ``reservations-out-of-pool``
+ is ``true``, the server assumes that all host reservations are for addresses
+ that do not belong to the dynamic pool. Therefore, it can skip the reservation
+ checks when dealing with in-pool addresses, thus improving performance.
+ The server will not assign reserved addresses that are inside the dynamic
+ pools to the respective clients. This also means that the addresses matching
+ the respective reservations from inside the dynamic pools (if any) can be
+ dynamically assigned to any client.
+
+The ``disabled`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": false,
+ "reservations-in-subnet": false
+ }
+ }
+
+The ``global`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": true,
+ "reservations-in-subnet": false
+ }
+ }
+
+The ``out-of-pool`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": false,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": true
+ }
+ }
+
+And the ``all`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": false,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": false
+ }
+ }
+
+To activate both ``global`` and ``all``, the following combination can be used:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": true,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": false
+ }
+ }
+
+To activate both ``global`` and ``out-of-pool``, the following combination can
+be used:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations-global": true,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": true
+ }
+ }
+
+Enabling ``out-of-pool`` and disabling ``in-subnet`` at the same time
+is not recommended because ``out-of-pool`` applies to host reservations in a
+subnet, which are fetched only when the ``in-subnet`` flag is ``true``.
+
+The parameter can be specified at the global, subnet, and shared-network
+levels.
+
+An example configuration that disables reservations looks as follows:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "reservations-global": false,
+ "reservations-in-subnet": false,
+ "subnet": "192.0.2.0/24",
+ "id": 1
+ }
+ ]
+ }
+ }
+
+An example configuration using global reservations is shown below:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "reservations": [
+ {
+ "hostname": "host-one",
+ "hw-address": "01:bb:cc:dd:ee:ff"
+ },
+ {
+ "hostname": "host-two",
+ "hw-address": "02:bb:cc:dd:ee:ff"
+ }
+ ],
+ "reservations-global": true,
+ "reservations-in-subnet": false,
+ "subnet4": [
+ {
+ "pools": [
+ {
+ "pool": "192.0.2.10-192.0.2.100"
+ }
+ ],
+ "subnet": "192.0.2.0/24",
+ "id": 1
+ }
+ ]
+ }
+ }
+
+For more details regarding global reservations, see :ref:`global-reservations4`.
+
+Another aspect of host reservations is the different types of
+identifiers. Kea currently supports four types of identifiers:
+``hw-address``, ``duid``, ``client-id``, and ``circuit-id``. This is beneficial from a
+usability perspective; however, there is one drawback. For each incoming
+packet, Kea has to extract each identifier type and then query the
+database to see if there is a reservation by this particular identifier.
+If nothing is found, the next identifier is extracted and the next query
+is issued. This process continues until either a reservation is found or
+all identifier types have been checked. Over time, with an increasing
+number of supported identifier types, Kea would become slower and
+slower.
+
+To address this problem, a parameter called
+``host-reservation-identifiers`` is available. It takes a list of
+identifier types as a parameter. Kea checks only those identifier
+types enumerated in ``host-reservation-identifiers``. From a performance
+perspective, the number of identifier types should be kept to a minimum,
+ideally one. If the deployment uses several reservation types, please
+enumerate them from most- to least-frequently used, as this increases
+the chances of Kea finding the reservation using the fewest queries. An
+example of a ``host-reservation-identifiers`` configuration looks as follows:
+
+::
+
+ {
+ "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ],
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ ...
+ }
+ ],
+ ...
+ }
+
+If not specified, the default value is:
+
+::
+
+ "host-reservation-identifiers": [ "hw-address", "duid", "circuit-id", "client-id" ]
+
+.. note::
+
+ As soon as a host reservation is found the search is stopped so
+ when a client has two host reservations using different enabled
+ identifier types the first is always returned and the second
+ ignored. In other words, this is usually a configuration mistake.
+ In rare cases when having two reservations for the same host makes sense,
+ you can control which of those will be used by ordering the list of
+ identifier types in `host-reservation-identifiers`.
+
+
+.. _global-reservations4:
+
+Global Reservations in DHCPv4
+-----------------------------
+
+In some deployments, such as mobile, clients can roam within the network
+and certain parameters must be specified regardless of the client's
+current location. To meet such a need, Kea offers a global reservation
+mechanism. The idea behind it is that regular host
+reservations are tied to specific subnets, by using a specific
+subnet ID. Kea can specify a global reservation that can be used in
+every subnet that has global reservations enabled.
+
+This feature can be used to assign certain parameters, such as hostname
+or other dedicated, host-specific options. It can also be used to assign
+addresses.
+
+An address assigned via global host reservation must be feasible for the
+subnet the server selects for the client. In other words, the address must
+lie within the subnet; otherwise, it is ignored and the server will
+attempt to dynamically allocate an address. If the selected subnet
+belongs to a shared network, the server checks for feasibility against
+the subnet's siblings, selecting the first in-range subnet. If no such
+subnet exists, the server falls back to dynamically allocating the address.
+
+.. note::
+
+ Prior to release 2.3.5, the server did not perform feasibility checks on
+ globally reserved addresses, which allowed the server to be configured to
+ hand out nonsensical leases for arbitrary address values. Later versions
+ of Kea perform these checks.
+
+To use global host reservations, a configuration similar to the
+following can be used:
+
+::
+
+ "Dhcp4": {
+ # This specifies global reservations.
+ # They will apply to all subnets that
+ # have global reservations enabled.
+
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "hostname": "hw-host-dynamic"
+ },
+ {
+ "hw-address": "01:02:03:04:05:06",
+ "hostname": "hw-host-fixed",
+
+ # Use of IP addresses in global reservations is risky.
+ # If used outside of a matching subnet, such as 192.0.1.0/24,
+ # it will result in a broken configuration being handed
+ # to the client.
+ "ip-address": "192.0.1.77"
+ },
+ {
+ "duid": "01:02:03:04:05",
+ "hostname": "duid-host"
+ },
+ {
+ "circuit-id": "'charter950'",
+ "hostname": "circuit-id-host"
+ },
+ {
+ "client-id": "01:11:22:33:44:55:66",
+ "hostname": "client-id-host"
+ }
+ ],
+ "valid-lifetime": 600,
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/24",
+ # It is replaced by the "reservations-global",
+ # "reservations-in-subnet", and "reservations-out-of-pool"
+ # parameters.
+ # "reservation-mode": "global",
+ # Specify if the server should look up global reservations.
+ "reservations-global": true,
+ # Specify if the server should look up in-subnet reservations.
+ "reservations-in-subnet": false,
+ # Specify if the server can assume that all reserved addresses
+ # are out-of-pool. It can be ignored because "reservations-in-subnet"
+ # is false.
+ # "reservations-out-of-pool": false,
+ "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ]
+ }
+ ]
+ }
+
+When using database backends, the global host reservations are
+distinguished from regular reservations by using a ``subnet-id`` value of
+0.
+
+.. _pool-selection-with-class-reservations4:
+
+Pool Selection with Client Class Reservations
+---------------------------------------------
+
+Client classes can be specified in the Kea configuration file and/or via
+host reservations. The classes specified in the Kea configuration file are
+evaluated immediately after receiving the DHCP packet and therefore can be
+used to influence subnet selection using the ``client-class`` parameter
+specified in the subnet scope. The classes specified within the host
+reservations are fetched and assigned to the packet after the server has
+already selected a subnet for the client. This means that the client
+class specified within a host reservation cannot be used to influence
+subnet assignment for this client, unless the subnet belongs to a
+shared network. If the subnet belongs to a shared network, the server may
+dynamically change the subnet assignment while trying to allocate a lease.
+If the subnet does not belong to a shared network, the subnet
+is not changed once selected.
+
+If the subnet does not belong to a shared network, it is possible to
+use host reservation-based client classification to select an address pool
+within the subnet as follows:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "reserved_class"
+ },
+ {
+ "name": "unreserved_class",
+ "test": "not member('reserved_class')"
+ }
+ ],
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:fe",
+ "client-classes": [ "reserved_class" ]
+ }
+ ],
+ "pools": [
+ {
+ "pool": "192.0.2.10-192.0.2.20",
+ "client-class": "reserved_class"
+ },
+ {
+ "pool": "192.0.2.30-192.0.2.40",
+ "client-class": "unreserved_class"
+ }
+ ]
+ }
+ ]
+ }
+
+The ``reserved_class`` is declared without the ``test`` parameter because
+it may only be assigned to the client via the host reservation mechanism. The
+second class, ``unreserved_class``, is assigned to clients which do not
+belong to the ``reserved_class``. The first pool within the subnet is only
+used for clients having a reservation for the ``reserved_class``. The
+second pool is used for clients not having such a reservation. The
+configuration snippet includes one host reservation which causes the client
+with the MAC address aa:bb:cc:dd:ee:fe to be assigned to the
+``reserved_class``. Thus, this client will be given an IP address from the
+first address pool.
+
+.. _subnet-selection-with-class-reservations4:
+
+Subnet Selection with Client Class Reservations
+-----------------------------------------------
+
+There is one specific use case when subnet selection may be influenced by
+client classes specified within host reservations: when the
+client belongs to a shared network. In such a case it is possible to use
+classification to select a subnet within this shared network. Consider the
+following example:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "reserved_class"
+ },
+ {
+ "name": "unreserved_class",
+ "test": "not member('reserved_class')"
+ }
+ ],
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:fe",
+ "client-classes": [ "reserved_class" ]
+ }
+ ],
+ # It is replaced by the "reservations-global",
+ # "reservations-in-subnet", and "reservations-out-of-pool" parameters.
+ # Specify if the server should look up global reservations.
+ "reservations-global": true,
+ # Specify if the server should look up in-subnet reservations.
+ "reservations-in-subnet": false,
+ # Specify if the server can assume that all reserved addresses
+ # are out-of-pool. It can be ignored because "reservations-in-subnet"
+ # is false, but if specified, it is inherited by "shared-networks"
+ # and "subnet4" levels.
+ # "reservations-out-of-pool": false,
+ "shared-networks": [
+ {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.10-192.0.2.20",
+ "client-class": "reserved_class"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.3.0/24",
+ "pools": [
+ {
+ "pool": "192.0.3.10-192.0.3.20",
+ "client-class": "unreserved_class"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+This is similar to the example described in
+:ref:`pool-selection-with-class-reservations4`. This time, however, there
+are two subnets, each of which has a pool associated with a different
+class. The clients that do not have a reservation for the ``reserved_class``
+are assigned an address from the subnet 192.0.3.0/24. Clients with
+a reservation for the ``reserved_class`` are assigned an address from
+the subnet 192.0.2.0/24. The subnets must belong to the same shared network.
+In addition, the reservation for the client class must be specified at the
+global scope (global reservation) and ``reservations-global`` must be
+set to ``true``.
+
+In the example above, the ``client-class`` could also be specified at the
+subnet level rather than the pool level, and would yield the same effect.
+
+.. _multiple-reservations-same-ip4:
+
+Multiple Reservations for the Same IP
+-------------------------------------
+
+Host reservations were designed to preclude the creation of multiple
+reservations for the same IP address within a particular subnet, to avoid
+having two different clients compete for the same address.
+When using the default settings, the server returns a configuration error
+when it finds two or more reservations for the same IP address within
+a subnet in the Kea configuration file. :ischooklib:`libdhcp_host_cmds.so`
+returns an error in response to the :isccmd:`reservation-add` command
+when it detects that the reservation exists in the database for the IP
+address for which the new reservation is being added.
+
+In some deployments a single host can select one of several network
+interfaces to communicate with the DHCP server, and the server must assign
+the same IP address to the host regardless of the interface used. Since
+each interface is assigned a different MAC address, it implies that
+several host reservations must be created to associate all of the MAC
+addresses present on this host with IP addresses. Using different
+IP addresses for each interface is impractical and is considered a waste
+of the IPv4 address space, especially since the host typically uses only one
+interface for communication with the server, hence only one IP address
+is in use.
+
+This causes a need to create multiple host reservations for a single
+IP address within a subnet; this is supported since the Kea 1.9.1
+release as an optional mode of operation, enabled with the
+``ip-reservations-unique`` global parameter.
+
+The ``ip-reservations-unique`` is a boolean parameter that defaults to
+``true``, which forbids the specification of more than one reservation
+for the same IP address within a given subnet. Setting this parameter to
+``false`` allows such reservations to be created both in the Kea configuration
+file and in the host database backend, via :ischooklib:`libdhcp_host_cmds.so`.
+
+Setting ``ip-reservations-unique`` to ``false`` when using memfile, MySQL or PostgreSQL is supported.
+This setting is not supported when using Host Cache (see :ref:`hooks-host-cache`), and the RADIUS backend
+(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the
+same IP. If either of these hooks are loaded and ``ip-reservations-unique`` is set to ``false``, then a
+configuration error will be emitted and the server will fail to start.
+
+.. note::
+
+ When ``ip-reservations-unique`` is set to ``true`` (the default value),
+ the server ensures that IP reservations are unique for a subnet within
+ a single host backend and/or Kea configuration file. It does not
+ guarantee that the reservations are unique across multiple backends.
+ On server startup, only IP reservations defined in the Kea configuration
+ file are checked for uniqueness.
+
+The following is an example configuration with two reservations for
+the same IP address but different MAC addresses:
+
+::
+
+ "Dhcp4": {
+ "ip-reservations-unique": false,
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "reservations": [
+ {
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "ip-address": "192.0.2.11"
+ },
+ {
+ "hw-address": "2a:2b:2c:2d:2e:2f",
+ "ip-address": "192.0.2.11"
+ }
+ ]
+ }
+ ]
+ }
+
+It is possible to control the ``ip-reservations-unique`` parameter via the
+:ref:`dhcp4-cb`. If the new setting of this parameter conflicts with
+the currently used backends (i.e. backends do not support the new setting),
+the new setting is ignored and a warning log message is generated.
+The backends continue to use the default setting, expecting that
+IP reservations are unique within each subnet. To allow the
+creation of non-unique IP reservations, the administrator must remove
+the backends which lack support for them from the configuration file.
+
+Administrators must be careful when they have been using multiple
+reservations for the same IP address and later decide to return to
+the default mode in which this is no longer allowed. They
+must make sure that at most one reservation for a given IP address
+exists within a subnet, prior to switching back to the default mode.
+If such duplicates are left in the configuration file, the server
+reports a configuration error. Leaving such reservations in the host
+databases does not cause configuration errors but may lead to lease
+allocation errors during the server's operation, when it unexpectedly
+finds multiple reservations for the same IP address.
+
+.. note::
+
+ Currently the Kea server does not verify whether multiple reservations for
+ the same IP address exist in MySQL and/or PostgreSQL host databases when
+ ``ip-reservations-unique`` is updated from ``false`` to ``true``. This may
+ cause issues with lease allocations. The administrator must ensure that there
+ is at most one reservation for each IP address within each subnet, prior to
+ the configuration update.
+
+The ``reservations-lookup-first`` is a boolean parameter which controls whether
+host reservations lookup should be performed before lease lookup. This parameter
+has effect only when multi-threading is disabled. When multi-threading is
+enabled, host reservations lookup is always performed first to avoid lease-lookup
+resource locking. The ``reservations-lookup-first`` parameter defaults to ``false``
+when multi-threading is disabled.
+
+.. _host_reservations_as_basic_access_control4:
+
+Host Reservations as Basic Access Control
+-----------------------------------------
+
+Starting with Kea 2.3.5, it is possible to define a host reservation that
+contains just an identifier, without any address, options, or values. In some
+deployments this is useful, as the hosts that have a reservation belong to
+the KNOWN class while others do not. This can be used as a basic access control
+mechanism.
+
+The following example demonstrates this concept. It indicates a single IPv4 subnet
+and all clients will get an address from it. However, only known clients (those that
+have reservations) will get their default router configured. Empty reservations
+i.e. reservations that only have the identification criterion, can be
+specifically useful in this regard of making the clients known.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "KNOWN",
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.2.250"
+ }
+ ]
+ }
+ ],
+ "reservations": [
+ // Clients on this list will be added to the KNOWN class.
+ { "hw-address": "aa:bb:cc:dd:ee:fe" },
+ { "hw-address": "11:22:33:44:55:66" }
+ ],
+ "reservations-in-subnet": true,
+
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.1-192.0.2.200"
+ }
+ ]
+ }
+ ]
+ }
+
+This concept can be extended further. A good real-life scenario might be a
+situation where some customers of an ISP have not paid their bills. A new class can be
+defined to use an alternative default router that, instead of relaying traffic,
+redirects those customers to a captive portal urging them to bring their accounts up to date.
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ "name": "blocked",
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.2.251"
+ }
+ ]
+ }
+ ],
+ "reservations": [
+ // Clients on this list will be added to the KNOWN class. Some
+ // will also be added to the blocked class.
+ { "hw-address": "aa:bb:cc:dd:ee:fe",
+ "client-classes": [ "blocked" ] },
+ { "hw-address": "11:22:33:44:55:66" }
+ ],
+ "reservations-in-subnet": true,
+
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.1-192.0.2.200"
+ }
+ ],
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.2.250"
+ }
+ ]
+ }
+ ]
+ }
+
+.. _shared-network4:
+
+Shared Networks in DHCPv4
+=========================
+
+DHCP servers use subnet information in two ways. It is used to
+both determine the point of attachment, i.e. where the client is
+connected to the network, and to
+group information pertaining to a specific location in the network.
+Sometimes it is useful to have more than one
+logical IP subnet deployed on the same physical link.
+Understanding that two or more subnets are used on the same link requires
+additional logic in the DHCP server. This capability is called "shared
+networks" in Kea, and sometimes also
+"shared subnets"; in Microsoft's nomenclature it is called "multinet."
+
+There are many cases where the shared networks feature is useful; here we
+explain just a handful of the most common ones. The first and by far
+most common use case is an existing IPv4 network that has grown and is
+running out of available address space. Rather than migrating all
+devices to a new, larger subnet, it is easier to simply configure
+additional subnets on top of the existing one. Sometimes, due to address
+space fragmentation (e.g. only many disjointed /24s are available), this
+is the only choice. Also, configuring additional subnets has the
+advantage of not disrupting the operation of existing devices.
+
+Another very frequent use case comes from cable networks. There are two
+types of devices in cable networks: cable modems and the end-user
+devices behind them. It is a common practice to use different subnets
+for cable modems to prevent users from tinkering with them. In this
+case, the distinction is based on the type of device, rather than
+on address-space exhaustion.
+
+A client connected to a shared network may be assigned an address from
+any of the pools defined within the subnets belonging to the shared
+network. Internally, the server selects one of the subnets belonging to
+a shared network and tries to allocate an address from this subnet. If
+the server is unable to allocate an address from the selected subnet
+(e.g., due to address-pool exhaustion), it uses another subnet from
+the same shared network and tries to allocate an address from this subnet.
+The server typically allocates all
+addresses available in a given subnet before it starts allocating
+addresses from other subnets belonging to the same shared network.
+However, in certain situations the client can be allocated an address
+from another subnet before the address pools in the first subnet get
+exhausted; this sometimes occurs when the client provides a hint that belongs to another
+subnet, or the client has reservations in a subnet other than the
+default.
+
+.. note::
+
+ Deployments should not assume that Kea waits until it has allocated
+ all the addresses from the first subnet in a shared network before
+ allocating addresses from other subnets.
+
+To define a shared network, an additional configuration scope is
+introduced:
+
+::
+
+ {
+ "Dhcp4": {
+ "shared-networks": [
+ {
+ # Name of the shared network. It may be an arbitrary string
+ # and it must be unique among all shared networks.
+ "name": "my-secret-lair-level-1",
+
+ # The subnet selector can be specified at the shared-network level.
+ # Subnets from this shared network will be selected for directly
+ # connected clients sending requests to the server's "eth0" interface.
+ "interface": "eth0",
+
+ # This starts a list of subnets in this shared network.
+ # There are two subnets in this example.
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ]
+ }
+ ]
+ }
+ ],
+ # end of shared-networks
+
+ # It is likely that in the network there will be a mix of regular,
+ # "plain" subnets and shared networks. It is perfectly valid to mix
+ # them in the same configuration file.
+ #
+ # This is a regular subnet. It is not part of any shared network.
+ "subnet4": [
+ {
+ "id": 3,
+ "subnet": "192.0.3.0/24",
+ "pools": [ { "pool": "192.0.3.1 - 192.0.3.200" } ],
+ "interface": "eth1"
+ }
+ ]
+ }
+ }
+
+As demonstrated in the example, it is possible to mix shared and regular
+("plain") subnets. Each shared network must have a unique name. This is
+similar to the ID for subnets, but gives administrators more
+flexibility. It is used for logging, but also internally for identifying
+shared networks.
+
+In principle it makes sense to define only shared networks that consist
+of two or more subnets. However, for testing purposes, an empty subnet
+or a network with just a single subnet is allowed. This is not a
+recommended practice in production networks, as the shared network logic
+requires additional processing and thus lowers the server's performance.
+To avoid unnecessary performance degradation, shared subnets should
+only be defined when required by the deployment.
+
+Shared networks provide the ability to specify many parameters in the
+shared network scope that apply to all subnets within it. If
+necessary, it is possible to specify a parameter in the shared-network scope and
+then override its value in the subnet scope. For example:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "lab-network3",
+
+ "interface": "eth0",
+
+ # This applies to all subnets in this shared network, unless
+ # values are overridden on subnet scope.
+ "valid-lifetime": 600,
+
+ # This option is made available to all subnets in this shared
+ # network.
+ "option-data": [
+ {
+ "name": "log-servers",
+ "data": "1.2.3.4"
+ }
+ ],
+
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ],
+
+ # This particular subnet uses different values.
+ "valid-lifetime": 1200,
+ "option-data": [
+ {
+ "name": "log-servers",
+ "data": "10.0.0.254"
+ },
+ {
+ "name": "routers",
+ "data": "10.0.0.254"
+ } ]
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ],
+
+ # This subnet does not specify its own valid-lifetime value,
+ # so it is inherited from shared network scope.
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.2.1"
+ } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+In this example, there is a ``log-servers`` option defined that is available
+to clients in both subnets in this shared network. Also, the valid
+lifetime is set to 10 minutes (600s). However, the first subnet
+overrides some of the values (the valid lifetime is 20 minutes, there is a different IP
+address for ``log-servers``), but also adds its own option (the router address).
+Assuming a client asking for router and ``log-servers`` options is assigned
+a lease from this subnet, it will get a lease for 20 minutes and a
+``log-servers`` and routers value of 10.0.0.254. If the same client is
+assigned to the second subnet, it will get a 10-minute lease, a
+``log-servers`` value of 1.2.3.4, and routers set to 192.0.2.1.
+
+Local and Relayed Traffic in Shared Networks
+--------------------------------------------
+
+It is possible to specify an interface name at the shared-network level,
+to tell the server that this specific shared network is reachable
+directly (not via relays) using the local network interface. As all
+subnets in a shared network are expected to be used on the same physical
+link, it is a configuration error to attempt to define a shared network
+using subnets that are reachable over different interfaces. In other
+words, all subnets within the shared network must have the same value
+for the ``interface`` parameter. The following configuration is an
+example of what **NOT** to do:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "office-floor-2",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ],
+ "interface": "eth0"
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ],
+
+ # Specifying the different interface name is a configuration
+ # error. This value should rather be "eth0" or the interface
+ # name in the other subnet should be "eth1".
+ "interface": "eth1"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+To minimize the chance of configuration errors, it is often more convenient
+to simply specify the interface name once, at the shared-network level, as
+shown in the example below.
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "office-floor-2",
+
+ # This tells Kea that the whole shared network is reachable over a
+ # local interface. This applies to all subnets in this network.
+ "interface": "eth0",
+
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+
+With relayed traffic, subnets are typically selected using
+the relay agents' addresses. If the subnets are used independently (not
+grouped within a shared network), a different relay
+address can be specified for each of these subnets. When multiple subnets belong to a
+shared network they must be selected via the same relay address and,
+similarly to the case of the local traffic described above, it is a
+configuration error to specify different relay addresses for the respective
+subnets in the shared network. The following configuration is another example
+of what **NOT** to do:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "kakapo",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/26",
+ "relay": {
+ "ip-addresses": [ "192.1.1.1" ]
+ },
+ "pools": [ { "pool": "192.0.2.63 - 192.0.2.63" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "10.0.0.0/24",
+ "relay": {
+ # Specifying a different relay address for this
+ # subnet is a configuration error. In this case
+ # it should be 192.1.1.1 or the relay address
+ # in the previous subnet should be 192.2.2.2.
+ "ip-addresses": [ "192.2.2.2" ]
+ },
+ "pools": [ { "pool": "10.0.0.16 - 10.0.0.16" } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+Again, it is better to specify the relay address at the shared-network
+level; this value will be inherited by all subnets belonging to the
+shared network.
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "kakapo",
+ "relay": {
+ # This relay address is inherited by both subnets.
+ "ip-addresses": [ "192.1.1.1" ]
+ },
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/26",
+ "pools": [ { "pool": "192.0.2.63 - 192.0.2.63" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.16 - 10.0.0.16" } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+Even though it is technically possible to configure two (or more) subnets
+within the shared network to use different relay addresses, this will almost
+always lead to a different behavior than what the user expects. In this
+case, the Kea server will initially select one of the subnets by matching
+the relay address in the client's packet with the subnet's configuration.
+However, it MAY end up using the other subnet (even though it does not match
+the relay address) if the client already has a lease in this subnet or has a
+host reservation in this subnet, or simply if the initially selected subnet has no
+more addresses available. Therefore, it is strongly recommended to always
+specify subnet selectors (interface or relay address) at the shared-network
+level if the subnets belong to a shared network, as it is rarely useful to
+specify them at the subnet level and may lead to the configuration errors
+described above.
+
+Client Classification in Shared Networks
+----------------------------------------
+
+Sometimes it is desirable to segregate clients into specific subnets
+based on certain properties. This mechanism is called client
+classification and is described in :ref:`classify`. Client
+classification can be applied to subnets belonging to shared networks in
+the same way as it is used for subnets specified outside of shared
+networks. It is important to understand how the server selects subnets
+for clients when client classification is in use, to ensure that the
+appropriate subnet is selected for a given client type.
+
+If a subnet is associated with a class, only the clients belonging to
+this class can use this subnet. If there are no classes specified for a
+subnet, any client connected to a given shared network can use this
+subnet. A common mistake is to assume that a subnet that includes a client
+class is preferred over subnets without client classes. Consider the
+following example:
+
+::
+
+ {
+ "client-classes": [
+ {
+ "name": "b-devices",
+ "test": "option[93].hex == 0x0002"
+ }
+ ],
+ "shared-networks": [
+ {
+ "name": "galah",
+ "interface": "eth0",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/26",
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.2 - 10.0.0.250" } ],
+ "client-class": "b-devices"
+ }
+ ]
+ }
+ ]
+ }
+
+If the client belongs to the "b-devices" class (because it includes
+option 93 with a value of 0x0002), that does not guarantee that the
+subnet 10.0.0.0/24 will be used (or preferred) for this client. The
+server can use either of the two subnets, because the subnet 192.0.2.0/26
+is also allowed for this client. The client classification used in this
+case should be perceived as a way to restrict access to certain subnets,
+rather than as a way to express subnet preference. For example, if the
+client does not belong to the "b-devices" class, it may only use the
+subnet 192.0.2.0/26 and will never use the subnet 10.0.0.0/24.
+
+A typical use case for client classification is in a cable network,
+where cable modems should use one subnet and other devices should use
+another subnet within the same shared network. In this case it is
+necessary to apply classification on all subnets. The following example
+defines two classes of devices, and the subnet selection is made based
+on option 93 values.
+
+::
+
+ {
+ "client-classes": [
+ {
+
+ "name": "a-devices",
+ "test": "option[93].hex == 0x0001"
+ },
+ {
+ "name": "b-devices",
+ "test": "option[93].hex == 0x0002"
+ }
+ ],
+ "shared-networks": [
+ {
+ "name": "galah",
+ "interface": "eth0",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/26",
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ],
+ "client-class": "a-devices"
+ },
+ {
+ "id": 2,
+ "subnet": "10.0.0.0/24",
+ "pools": [ { "pool": "10.0.0.2 - 10.0.0.250" } ],
+ "client-class": "b-devices"
+ }
+ ]
+ }
+ ]
+ }
+
+In this example each class has its own restriction. Only clients that
+belong to class "a-devices" are able to use subnet 192.0.2.0/26 and
+only clients belonging to "b-devices" are able to use subnet
+10.0.0.0/24. Care should be taken not to define too-restrictive
+classification rules, as clients that are unable to use any subnets will
+be refused service. However, this may be a desired outcome if one wishes
+to provide service only to clients with known properties (e.g. only VoIP
+phones allowed on a given link).
+
+It is possible to achieve an effect similar to the one
+presented in this section without the use of shared networks. If the
+subnets are placed in the global subnets scope, rather than in the
+shared network, the server will still use classification rules to pick
+the right subnet for a given class of devices. The major benefit of
+placing subnets within the shared network is that common parameters for
+the logically grouped subnets can be specified once in the
+shared-network scope, e.g. the ``interface`` or ``relay`` parameter. All subnets
+belonging to this shared network will inherit those parameters.
+
+Host Reservations in Shared Networks
+------------------------------------
+
+Subnets that are part of a shared network allow host reservations,
+similar to regular subnets:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "frog",
+ "interface": "eth0",
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/26",
+ "id": 100,
+ "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ],
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "ip-address": "192.0.2.28"
+ }
+ ]
+ },
+ {
+ "subnet": "10.0.0.0/24",
+ "id": 101,
+ "pools": [ { "pool": "10.0.0.1 - 10.0.0.254" } ],
+ "reservations": [
+ {
+ "hw-address": "11:22:33:44:55:66",
+ "ip-address": "10.0.0.29"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+
+It is worth noting that Kea conducts additional checks when processing a
+packet if shared networks are defined. First, instead of simply checking
+whether there is a reservation for a given client in its initially
+selected subnet, Kea looks through all subnets in a shared network for a
+reservation. This is one of the reasons why defining a shared network
+may impact performance. If there is a reservation for a client in any
+subnet, that particular subnet is selected for the client. Although
+it is technically not an error, it is considered bad practice to define
+reservations for the same host in multiple subnets belonging to the same
+shared network.
+
+While not strictly mandatory, it is strongly recommended to use explicit
+"id" values for subnets if database storage will be used for host
+reservations. If an ID is not specified, the values for it are
+auto-generated, i.e. Kea assigns increasing integer values starting from
+1. Thus, the auto-generated IDs are not stable across configuration
+changes.
+
+.. _dhcp4-serverid:
+
+Server Identifier in DHCPv4
+===========================
+
+The DHCPv4 protocol uses a "server identifier" to allow clients to
+discriminate between several servers present on the same link; this
+value is an IPv4 address of the server. The server chooses the IPv4
+address of the interface on which the message from the client (or relay)
+has been received. A single server instance uses multiple server
+identifiers if it is receiving queries on multiple interfaces.
+
+It is possible to override the default server identifier values by specifying
+the ``dhcp-server-identifier`` option. This option configuration is only
+supported at the subnet, shared network, client class, and global levels. It
+must not be specified at the host-reservation level.
+When configuring the ``dhcp-server-identifier`` option at client-class level, the
+class must not set the ``only-if-required`` flag, because this class would not
+be evaluated before the server determines if the received DHCP message should
+be accepted for processing. Such classes are evaluated after subnet selection.
+See :ref:`dhcp4-required-class` for details.
+
+The following example demonstrates how to override the server identifier
+for a subnet:
+
+::
+
+ {
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "option-data": [
+ {
+ "name": "dhcp-server-identifier",
+ "data": "10.2.5.76"
+ }
+ ],
+ ...
+ }
+ ],
+ ...
+ }
+
+.. _dhcp4-subnet-selection:
+
+How the DHCPv4 Server Selects a Subnet for the Client
+=====================================================
+
+The DHCPv4 server differentiates among directly connected clients,
+clients trying to renew leases, and clients sending their messages
+through relays. For directly connected clients, the server checks
+the configuration for the interface on which the message has been
+received and, if the server configuration does not match any configured
+subnet, the message is discarded.
+
+An optional interface parameter is available within a subnet definition to
+designate that a given subnet is local, i.e. reachable directly over the
+specified interface. For example, a server that is intended to serve a local
+subnet over eth0 may be configured as follows:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.100 - 192.0.2.199"
+ }
+ ],
+ "interface": "eth0"
+ }
+ ],
+ ...
+ }
+
+Assuming that the server's interface is configured with the IPv4 address
+192.0.2.3, the server only processes messages received through this
+interface from a directly connected client if there is a subnet
+configured to which this IPv4 address belongs, such as 192.0.2.0/24. The
+server uses this subnet to assign an IPv4 address for the client.
+
+The rule above does not apply when the client unicasts its message, i.e.
+is trying to renew its lease; such a message is accepted through any
+interface. The renewing client sets ``ciaddr`` to the currently used IPv4
+address, and the server uses this address to select the subnet for the
+client (in particular, to extend the lease using this address).
+
+If the message is relayed it is accepted through any interface. The
+``giaddr`` set by the relay agent is used to select the subnet for the
+client.
+
+It is also possible to specify a relay IPv4 address for a given subnet.
+It can be used to match incoming packets into a subnet in uncommon
+configurations, e.g. shared networks. See :ref:`dhcp4-relay-override` for details.
+
+.. note::
+
+ The subnet selection mechanism described in this section is based on
+ the assumption that client classification is not used. The
+ classification mechanism alters the way in which a subnet is selected
+ for the client, depending on the classes to which the client belongs.
+
+.. note::
+
+ When the selected subnet is a member of a shared network, the
+ whole shared network is selected.
+
+.. _dhcp4-relay-override:
+
+Using a Specific Relay Agent for a Subnet
+-----------------------------------------
+
+A relay must have an interface connected to the link on which the
+clients are being configured. Typically the relay has an IPv4 address
+configured on that interface, which belongs to the subnet from which the
+server assigns addresses. Normally, the server is able to use the
+IPv4 address inserted by the relay (in the ``giaddr`` field of the DHCPv4
+packet) to select the appropriate subnet.
+
+However, that is not always the case. In certain uncommon — but valid —
+deployments, the relay address may not match the subnet. This usually
+means that there is more than one subnet allocated for a given link. The
+two most common examples of this are long-lasting network
+renumbering (where both old and new address spaces are still being used)
+and a cable network. In a cable network, both cable modems and the
+devices behind them are physically connected to the same link, yet they
+use distinct addressing. In such a case, the DHCPv4 server needs
+additional information (the IPv4 address of the relay) to properly
+select an appropriate subnet.
+
+The following example assumes that there is a subnet 192.0.2.0/24 that
+is accessible via a relay that uses 10.0.0.1 as its IPv4 address. The
+server is able to select this subnet for any incoming packets that come
+from a relay that has an address in the 192.0.2.0/24 subnet. It also
+selects that subnet for a relay with address 10.0.0.1.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "relay": {
+ "ip-addresses": [ "10.0.0.1" ]
+ }
+ }
+ ]
+ }
+ }
+
+If ``relay`` is specified, the ``ip-addresses`` parameter within it is
+mandatory. The ``ip-addresses`` parameter supports specifying a list of addresses.
+
+.. _dhcp4-srv-example-client-class-relay:
+
+Segregating IPv4 Clients in a Cable Network
+-------------------------------------------
+
+In certain cases, it is useful to mix relay address information
+(introduced in :ref:`dhcp4-relay-override`) with client classification (explained
+in :ref:`classify`). One specific example is in a cable network,
+where modems typically get addresses from a different subnet than all
+the devices connected behind them.
+
+Let us assume that there is one Cable Modem Termination System (CMTS)
+with one CM MAC (a physical link that modems are connected to). We want
+the modems to get addresses from the 10.1.1.0/24 subnet, while
+everything connected behind the modems should get addresses from the
+192.0.2.0/24 subnet. The CMTS that acts as a relay uses address
+10.1.1.1. The following configuration can serve that situation:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.1.1.0/24",
+ "pools": [ { "pool": "10.1.1.2 - 10.1.1.20" } ],
+ "client-class": "docsis3.0",
+ "relay": {
+ "ip-addresses": [ "10.1.1.1" ]
+ }
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24",
+ "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
+ "relay": {
+ "ip-addresses": [ "10.1.1.1" ]
+ }
+ }
+ ],
+ ...
+ }
+
+.. _dhcp4-decline:
+
+Duplicate Addresses (DHCPDECLINE Support)
+=========================================
+
+The DHCPv4 server is configured with a certain pool of addresses that it
+is expected to hand out to DHCPv4 clients. It is assumed that the server
+is authoritative and has complete jurisdiction over those addresses.
+However, for various reasons such as misconfiguration or a faulty
+client implementation that retains its address beyond the valid
+lifetime, there may be devices connected that use those addresses
+without the server's approval or knowledge.
+
+Such an unwelcome event can be detected by legitimate clients (using ARP
+or ICMP Echo Request mechanisms) and reported to the DHCPv4 server using
+a DHCPDECLINE message. The server does a sanity check (to see whether
+the client declining an address really was supposed to use it) and then
+conducts a clean-up operation. Any DNS entries related to that
+address are removed, the event is logged, and hooks are
+triggered. After that is complete, the address is marked as
+declined (which indicates that it is used by an unknown entity and thus
+not available for assignment) and a probation time is set on it.
+Unless otherwise configured, the probation period lasts 24 hours; after
+that time, the server will recover the lease (i.e. put it back into
+the available state) and the address will be available for assignment
+again. It should be noted that if the underlying issue of a
+misconfigured device is not resolved, the duplicate-address scenario
+will repeat. If reconfigured correctly, this mechanism provides an
+opportunity to recover from such an event automatically, without any
+system administrator intervention.
+
+To configure the decline probation period to a value other than the
+default, the following syntax can be used:
+
+::
+
+ "Dhcp4": {
+ "decline-probation-period": 3600,
+ "subnet4": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+The parameter is expressed in seconds, so the example above
+instructs the server to recycle declined leases after one hour.
+
+There are several statistics and hook points associated with the decline
+handling procedure. The ``lease4_decline`` hook point is triggered after the
+incoming DHCPDECLINE message has been sanitized and the server is about
+to decline the lease. The ``declined-addresses`` statistic is increased
+after the hook returns (both the global and subnet-specific variants). (See
+:ref:`dhcp4-stats` and :ref:`hooks-libraries`
+for more details on DHCPv4 statistics and Kea hook points.)
+
+Once the probation time elapses, the declined lease is recovered using
+the standard expired-lease reclamation procedure, with several
+additional steps. In particular, both ``declined-addresses`` statistics
+(global and subnet-specific) are decreased. At the same time,
+``reclaimed-declined-addresses`` statistics (again in two variants, global
+and subnet-specific) are increased.
+
+A note about statistics: The Kea server does not decrease the
+``assigned-addresses`` statistics when a DHCPDECLINE is received and
+processed successfully. While technically a declined address is no
+longer assigned, the primary usage of the ``assigned-addresses`` statistic
+is to monitor pool utilization. Most people would forget to include
+``declined-addresses`` in the calculation, and would simply use
+``assigned-addresses``/``total-addresses``. This would cause a bias towards
+under-representing pool utilization. As this has a potential to cause serious
+confusion, ISC decided not to decrease ``assigned-addresses`` immediately after
+receiving DHCPDECLINE, but to do it later when Kea recovers the address
+back to the available pool.
+
+.. _dhcp4-stats:
+
+Statistics in the DHCPv4 Server
+===============================
+
+The DHCPv4 server supports the following statistics:
+
+.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}|
+
+.. table:: DHCPv4 statistics
+ :class: longtable
+ :widths: 20 10 70
+
+
+ +----------------------------------------------------+----------------+------------------------------------+
+ | Statistic | Data Type | Description |
+ +====================================================+================+====================================+
+ | pkt4-received | integer | Number of DHCPv4 packets received. |
+ | | | This includes all packets: valid, |
+ | | | bogus, corrupted, rejected, etc. |
+ | | | This statistic is expected to grow |
+ | | | rapidly. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-discover-received | integer | Number of DHCPDISCOVER packets |
+ | | | received. This statistic is |
+ | | | expected to grow; its increase |
+ | | | means that clients that just |
+ | | | booted started their configuration |
+ | | | process and their initial packets |
+ | | | reached the Kea server. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-offer-received | integer | Number of DHCPOFFER packets |
+ | | | received. This statistic is |
+ | | | expected to remain zero at all |
+ | | | times, as DHCPOFFER 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 DHCPOFFER |
+ | | | messages towards the server, |
+ | | | rather than back to the clients. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-request-received | integer | Number of DHCPREQUEST packets |
+ | | | received. This statistic is |
+ | | | expected to grow. Its increase |
+ | | | means that clients that just |
+ | | | booted received the server's |
+ | | | response (DHCPOFFER) and accepted |
+ | | | it, and are now requesting an |
+ | | | address (DHCPREQUEST). |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-ack-received | integer | Number of DHCPACK packets |
+ | | | received. This statistic is |
+ | | | expected to remain zero at all |
+ | | | times, as DHCPACK 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 DHCPACK |
+ | | | messages towards the server, |
+ | | | rather than back to the clients. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-nak-received | integer | Number of DHCPNAK packets |
+ | | | received. This statistic is |
+ | | | expected to remain zero at all |
+ | | | times, as DHCPNAK 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 DHCPNAK |
+ | | | messages towards the server, |
+ | | | rather than back to the clients. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-release-received | integer | Number of DHCPRELEASE packets |
+ | | | received. This statistic is |
+ | | | expected to grow. Its increase |
+ | | | means that clients that had an |
+ | | | address are shutting down or |
+ | | | ceasing to use their addresses. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-decline-received | integer | Number of DHCPDECLINE packets |
+ | | | received. This statistic is |
+ | | | expected to remain close to zero. |
+ | | | Its increase means that a client |
+ | | | leased an address, but discovered |
+ | | | that the address is currently |
+ | | | used by an unknown device |
+ | | | elsewhere in the network. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-inform-received | integer | Number of DHCPINFORM packets |
+ | | | received. This statistic is |
+ | | | expected to grow. Its increase |
+ | | | means that there are clients |
+ | | | that either do not need an address |
+ | | | or already have an address and are |
+ | | | interested only in getting |
+ | | | additional configuration |
+ | | | parameters. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-unknown-received | integer | Number of packets received of an |
+ | | | unknown type. A non-zero value of |
+ | | | this statistic indicates that the |
+ | | | server received a packet that it |
+ | | | was not able to recognize, either |
+ | | | with an unsupported type or |
+ | | | possibly malformed (without a |
+ | | | message-type option). |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-sent | integer | Number of DHCPv4 packets sent. |
+ | | | This statistic is expected to grow |
+ | | | every time the server transmits a |
+ | | | packet. In general, it should |
+ | | | roughly match pkt4-received, as |
+ | | | most incoming packets cause the |
+ | | | server to respond. There are |
+ | | | exceptions (e.g. DHCPRELEASE), so |
+ | | | do not worry if it is less than |
+ | | | pkt4-received. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-offer-sent | integer | Number of DHCPOFFER packets sent. |
+ | | | This statistic is expected to grow |
+ | | | in most cases after a DHCPDISCOVER |
+ | | | is processed. There are certain |
+ | | | uncommon, but valid, cases where |
+ | | | incoming DHCPDISCOVER packets are |
+ | | | dropped, but in general this |
+ | | | statistic is expected to be close |
+ | | | to pkt4-discover-received. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-ack-sent | integer | Number of DHCPACK packets sent. |
+ | | | This statistic is expected to grow |
+ | | | in most cases after a DHCPREQUEST |
+ | | | is processed. There are certain |
+ | | | cases where DHCPNAK is sent |
+ | | | instead. In general, the sum of |
+ | | | pkt4-ack-sent and pkt4-nak-sent |
+ | | | should be close to |
+ | | | pkt4-request-received. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-nak-sent | integer | Number of DHCPNAK packets sent. |
+ | | | This statistic is expected to grow |
+ | | | when the server chooses not to |
+ | | | honor the address requested by a |
+ | | | client. In general, the sum of |
+ | | | pkt4-ack-sent and pkt4-nak-sent |
+ | | | should be close to |
+ | | | pkt4-request-received. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-parse-failed | integer | Number of incoming packets that |
+ | | | could not be parsed. A non-zero |
+ | | | value of this statistic indicates |
+ | | | that the server received a |
+ | | | malformed or truncated packet. |
+ | | | This may indicate problems in the |
+ | | | network, faulty clients, or a bug |
+ | | | in the server. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-receive-drop | integer | Number of incoming packets that |
+ | | | were dropped. The exact reason for |
+ | | | dropping packets is logged, but |
+ | | | the most common reasons may be: an |
+ | | | unacceptable packet type was |
+ | | | received, direct responses are |
+ | | | forbidden, or the server-id sent |
+ | | | by the client does not match the |
+ | | | server's server-id. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].total-addresses | integer | Total number of addresses |
+ | | | available for DHCPv4 management |
+ | | | for a given subnet; in other |
+ | | | words, this is the count of all |
+ | | | addresses in all configured pools. |
+ | | | This statistic changes only during |
+ | | | configuration updates. It does not |
+ | | | take into account any addresses |
+ | | | that may be reserved due to host |
+ | | | reservation. 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. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].total-addresses | integer | Total number of addresses |
+ | | | available for DHCPv4 management |
+ | | | for a given subnet pool; in other |
+ | | | words, this is the count of all |
+ | | | addresses in configured subnet |
+ | | | pool. This statistic changes only |
+ | | | during configuration updates. It |
+ | | | does not take into account any |
+ | | | addresses that may be reserved due |
+ | | | to host reservation. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of a |
+ | | | given pool. This statistic is |
+ | | | exposed for each subnet pool |
+ | | | separately, and is reset during a |
+ | | | reconfiguration event. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | cumulative-assigned-addresses | integer | Cumulative number of addresses |
+ | | | that have been assigned since |
+ | | | server startup. It is incremented |
+ | | | each time an address is assigned |
+ | | | and is not reset when the server |
+ | | | is reconfigured. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].cumulative-assigned-addresses | integer | Cumulative number of assigned |
+ | | | addresses in a given subnet. It |
+ | | | increases every time a new lease |
+ | | | is allocated (as a result of |
+ | | | receiving a DHCPREQUEST message) |
+ | | | and never decreases. The *id* is |
+ | | | the subnet-id of the subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately, and is reset |
+ | | | during a reconfiguration event. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].cumulative-assigned-addresses | integer | Cumulative number of assigned |
+ | | | addresses in a given subnet pool. |
+ | | | It increases every time a new |
+ | | | lease is allocated (as a result of |
+ | | | receiving a DHCPREQUEST message) |
+ | | | and never decreases. The *id* is |
+ | | | the subnet-id of the subnet. The |
+ | | | *pid* is the pool-id of the pool. |
+ | | | This statistic is exposed for each |
+ | | | subnet pool separately, and is |
+ | | | reset during a reconfiguration |
+ | | | event. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].assigned-addresses | integer | Number of assigned addresses in a |
+ | | | given subnet. It increases every |
+ | | | time a new lease is allocated (as |
+ | | | a result of receiving a |
+ | | | DHCPREQUEST message) and decreases |
+ | | | every time a lease is released (a |
+ | | | DHCPRELEASE message is received) |
+ | | | or expires. The *id* is the |
+ | | | subnet-id of the subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately, and is reset |
+ | | | during a reconfiguration event. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].assigned-addresses | integer | Number of assigned addresses in a |
+ | | | given subnet pool. It increases |
+ | | | every time a new lease is |
+ | | | allocated (as a result of |
+ | | | receiving a DHCPREQUEST message) |
+ | | | and decreases every time a lease |
+ | | | is released (a DHCPRELEASE message |
+ | | | is received) or expires. The *id* |
+ | | | is the subnet-id of the subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately, |
+ | | | and is reset during a |
+ | | | reconfiguration event. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | reclaimed-leases | integer | Number of expired leases that have |
+ | | | been reclaimed since server |
+ | | | startup. It is incremented each |
+ | | | time an expired lease is reclaimed |
+ | | | and never decreases. It can be |
+ | | | used as a long-term indicator of |
+ | | | how many actual leases have been |
+ | | | reclaimed. This is a global |
+ | | | statistic that covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].reclaimed-leases | integer | Number of expired leases |
+ | | | associated with a given subnet |
+ | | | that have been reclaimed since |
+ | | | server startup. It is incremented |
+ | | | each time an expired lease is |
+ | | | reclaimed. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].reclaimed-leases | integer | Number of expired leases |
+ | | | associated with a given subnet |
+ | | | pool that have been reclaimed |
+ | | | since server startup. It is |
+ | | | incremented each time an expired |
+ | | | lease is reclaimed. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | declined-addresses | integer | Number of IPv4 addresses that are |
+ | | | currently declined; a count of the |
+ | | | number of leases currently |
+ | | | unavailable. Once a lease is |
+ | | | recovered, this statistic is |
+ | | | decreased; ideally, this statistic |
+ | | | should be zero. If this statistic |
+ | | | is non-zero or increasing, a |
+ | | | network administrator should |
+ | | | investigate whether there is a |
+ | | | misbehaving device in the network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].declined-addresses | integer | Number of IPv4 addresses that are |
+ | | | currently declined in a given |
+ | | | subnet; a count of the number of |
+ | | | leases currently unavailable. Once |
+ | | | a lease is recovered, this |
+ | | | statistic is decreased; ideally, |
+ | | | this statistic should be zero. If |
+ | | | this statistic is non-zero or |
+ | | | increasing, a network |
+ | | | administrator should investigate |
+ | | | whether there is a misbehaving |
+ | | | device in the network. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | This statistic is exposed for each |
+ | | | subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].declined-addresses | integer | Number of IPv4 addresses that are |
+ | | | currently declined in a given |
+ | | | subnet pool; a count of the number |
+ | | | of leases currently unavailable. |
+ | | | Once a lease is recovered, this |
+ | | | statistic is decreased; ideally, |
+ | | | this statistic should be zero. If |
+ | | | this statistic is non-zero or |
+ | | | increasing, a network |
+ | | | administrator should investigate |
+ | | | whether there is a misbehaving |
+ | | | device in the network. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | reclaimed-declined-addresses | integer | Number of IPv4 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. This |
+ | | | is a global statistic that covers |
+ | | | all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].reclaimed-declined-addresses | integer | Number of IPv4 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. The |
+ | | | *id* is the subnet-id of a given |
+ | | | subnet. This statistic is exposed |
+ | | | for each subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].reclaimed-declined-addresses | integer | Number of IPv4 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. The |
+ | | | *id* is the subnet-id of a given |
+ | | | subnet. The *pid* is the pool-id |
+ | | | of the pool. This statistic is |
+ | | | exposed for each subnet pool |
+ | | | separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-lease-query-received | integer | Number of IPv4 DHCPLEASEQUERY |
+ | | | packets received. (Only exists if |
+ | | | Leasequery hook library is |
+ | | | loaded.) |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-lease-query-response-unknown-sent | integer | Number of IPv4 DHCPLEASEUNKNOWN |
+ | | | responses sent. (Only exists if |
+ | | | Leasequery hook library is |
+ | | | loaded.) |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-lease-query-response-unassigned-sent | integer | Number of IPv4 DHCPLEASEUNASSIGNED |
+ | | | responses sent. (Only exists if |
+ | | | Leasequery hook library is |
+ | | | loaded.) |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | pkt4-lease-query-response-active-sent | integer | Number of IPv4 DHCPLEASEACTIVE |
+ | | | responses sent. (Only exists if |
+ | | | Leasequery hook library is |
+ | | | loaded.) |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-allocation-fail | integer | Number of total address allocation |
+ | | | failures for a particular client. |
+ | | | This consists in the number of |
+ | | | lease allocation attempts that the |
+ | | | server made before giving up and |
+ | | | was unable to use any of the |
+ | | | address pools. This is a global |
+ | | | statistic that covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-allocation-fail | integer | Number of total address allocation |
+ | | | failures for a particular client. |
+ | | | This consists in the number of |
+ | | | lease allocation attempts that the |
+ | | | server made before giving up and |
+ | | | was unable to use any of the |
+ | | | address pools. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-allocation-fail-shared-network | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a shared network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-allocation-fail-shared-network | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a shared network. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. This statistic is |
+ | | | exposed for each subnet |
+ | | | separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-allocation-fail-subnet | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a subnet that does |
+ | | | not belong to a shared network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-allocation-fail-subnet | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a subnet that does |
+ | | | not belong to a shared network. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. This statistic is |
+ | | | exposed for each subnet |
+ | | | separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-allocation-fail-no-pools | integer | Number of address allocation |
+ | | | failures because the server could |
+ | | | not use any configured pools for |
+ | | | a particular client. It is also |
+ | | | possible that all of the subnets |
+ | | | from which the server attempted to |
+ | | | assign an address lack address |
+ | | | pools. In this case, it should be |
+ | | | considered misconfiguration if an |
+ | | | operator expects that some clients |
+ | | | should be assigned dynamic |
+ | | | addresses. This is a global |
+ | | | statistic that covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-allocation-fail-no-pools | integer | Number of address allocation |
+ | | | failures because the server could |
+ | | | not use any configured pools for |
+ | | | a particular client. It is also |
+ | | | possible that all of the subnets |
+ | | | from which the server attempted to |
+ | | | assign an address lack address |
+ | | | pools. In this case, it should be |
+ | | | considered misconfiguration if an |
+ | | | operator expects that some clients |
+ | | | should be assigned dynamic |
+ | | | addresses. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-allocation-fail-classes | integer | Number of address allocation |
+ | | | failures when the client's packet |
+ | | | belongs to one or more classes. |
+ | | | There may be several reasons why a |
+ | | | lease was not assigned. One of |
+ | | | them may be a case when all pools |
+ | | | require packet to belong to |
+ | | | certain classes and the incoming |
+ | | | packet didn't belong to any of |
+ | | | them. Another case where this |
+ | | | information may be useful is to |
+ | | | point out that the pool reserved |
+ | | | to a given class has ran out of |
+ | | | addresses. This is a global |
+ | | | statistic that covers all subnets. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-allocation-fail-classes | integer | Number of address allocation |
+ | | | failures when the client's packet |
+ | | | belongs to one or more classes. |
+ | | | There may be several reasons why a |
+ | | | lease was not assigned. One of |
+ | | | them may be a case when all pools |
+ | | | require packet to belong to |
+ | | | certain classes and the incoming |
+ | | | packet didn't belong to any of |
+ | | | them. Another case where this |
+ | | | information may be useful is to |
+ | | | point out that the pool reserved |
+ | | | to a given class has ran out of |
+ | | | addresses. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-lease-reuses | integer | Number of times an IPv4 lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is global. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-lease-reuses | integer | Number of times an IPv4 lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is on a per-subnet |
+ | | | basis. The *id* is the subnet-id |
+ | | | of a given subnet. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | v4-reservation-conflicts | integer | Number of host reservation |
+ | | | allocation conflicts which have |
+ | | | occurred across every subnet. When |
+ | | | a client sends a DHCP Discover and |
+ | | | is matched to a host reservation |
+ | | | which is already leased to another |
+ | | | client, this counter is increased |
+ | | | by 1. |
+ +----------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v4-reservation-conflicts | integer | Number of host reservation |
+ | | | allocation conflicts which have |
+ | | | occurred in a specific subnet. |
+ | | | When a client sends a DHCP |
+ | | | Discover and is matched to a host |
+ | | | reservation which is already |
+ | | | leased to another client, this |
+ | | | counter is increased by 1. |
+ +----------------------------------------------------+----------------+------------------------------------+
+
+.. note::
+
+ The pool ID can be configured on each pool by explicitly setting the ``pool-id``
+ parameter in the pool parameter map. If not configured, ``pool-id`` defaults to 0.
+ The statistics related to pool ID 0 refer to all the statistics of all the pools
+ that have unconfigured ``pool-id``.
+ The pool ID does not need to be unique within the subnet or across subnets.
+ The statistics regarding a specific pool ID within a subnet will be combined with the
+ other statistics of all other pools with the same pool ID in the respective subnet.
+
+.. note::
+
+ This section describes DHCPv4-specific statistics. For a general
+ overview and usage of statistics, see :ref:`stats`.
+
+The DHCPv4 server provides two global parameters to control the default sample
+limits of statistics:
+
+- ``statistic-default-sample-count`` - determines the default maximum
+ number of samples which are kept. The special value of 0
+ indicates that a default maximum age should be used.
+
+- ``statistic-default-sample-age`` - determines the default maximum
+ age in seconds of samples which are kept.
+
+For instance, to reduce the statistic-keeping overhead, set
+the default maximum sample count to 1 so only one sample is kept:
+
+::
+
+ "Dhcp4": {
+ "statistic-default-sample-count": 1,
+ "subnet4": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Statistics can be retrieved periodically to gain more insight into Kea operations. One tool that
+leverages that capability is ISC Stork. See :ref:`stork` for details.
+
+
+.. _dhcp4-ctrl-channel:
+
+Management API for the DHCPv4 Server
+====================================
+
+The management API allows the issuing of specific management commands,
+such as statistics retrieval, reconfiguration, or shutdown. For more
+details, see :ref:`ctrl-channel`. Currently, the only supported
+communication channel type is the UNIX stream socket. By default there are
+no sockets open; to instruct Kea to open a socket, the following entry
+in the configuration file can be used:
+
+::
+
+ "Dhcp4": {
+ "control-socket": {
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket"
+ },
+
+ "subnet4": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+The length of the path specified by the ``socket-name`` parameter is
+restricted by the maximum length for the UNIX socket name on the administrator's
+operating system, i.e. the size of the ``sun_path`` field in the
+``sockaddr_un`` structure, decreased by 1. This value varies on
+different operating systems, between 91 and 107 characters. Typical
+values are 107 on Linux and 103 on FreeBSD.
+
+Communication over the control channel is conducted using JSON
+structures. See the
+`Control Channel section in the Kea Developer's Guide
+<https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__
+for more details.
+
+The DHCPv4 server supports the following operational commands:
+
+- :isccmd:`build-report`
+- :isccmd:`config-get`
+- :isccmd:`config-hash-get`
+- :isccmd:`config-reload`
+- :isccmd:`config-set`
+- :isccmd:`config-test`
+- :isccmd:`config-write`
+- :isccmd:`dhcp-disable`
+- :isccmd:`dhcp-enable`
+- :isccmd:`leases-reclaim`
+- :isccmd:`list-commands`
+- :isccmd:`shutdown`
+- :isccmd:`status-get`
+- :isccmd:`version-get`
+
+as described in :ref:`commands-common`. In addition, it supports the
+following statistics-related commands:
+
+- :isccmd:`statistic-get`
+- :isccmd:`statistic-reset`
+- :isccmd:`statistic-remove`
+- :isccmd:`statistic-get`-all
+- :isccmd:`statistic-reset`-all
+- :isccmd:`statistic-remove`-all
+- :isccmd:`statistic-sample-age-set`
+- :isccmd:`statistic-sample-age-set`-all
+- :isccmd:`statistic-sample-count-set`
+- :isccmd:`statistic-sample-count-set`-all
+
+as described in :ref:`command-stats`.
+
+.. _dhcp4-user-contexts:
+
+User Contexts in IPv4
+=====================
+
+Kea allows the loading of hook libraries that can sometimes benefit from
+additional parameters. If such a parameter is specific to the whole
+library, it is typically defined as a parameter for the hook library.
+However, sometimes there is a need to specify parameters that are
+different for each pool.
+
+See :ref:`user-context` for additional background regarding the
+user-context idea. See :ref:`user-context-hooks` for a discussion from the
+hooks perspective.
+
+User contexts can be specified at global scope; at the shared-network, subnet,
+pool, client-class, option-data, or definition level; and via host
+reservation. One other useful feature is the ability to store comments or
+descriptions.
+
+Let's consider an imaginary case of devices that have colored LED lights.
+Depending on their location, they should glow red, blue, or green. It
+would be easy to write a hook library that would send specific values,
+maybe as a vendor option. However, the server has to have some way to
+specify that value for each pool. This need is addressed by user
+contexts. In essence, any user data can be specified in the user context
+as long as it is a valid JSON map. For example, the aforementioned case
+of LED devices could be configured in the following way:
+
+::
+
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.10 - 192.0.2.20",
+ # This is pool specific user context
+ "user-context": { "color": "red" }
+ }
+ ],
+
+ # This is a subnet-specific user context. Any type
+ # of information can be entered here as long as it is valid JSON.
+ "user-context": {
+ "comment": "network on the second floor",
+ "last-modified": "2017-09-04 13:32",
+ "description": "you can put anything you like here",
+ "phones": [ "x1234", "x2345" ],
+ "devices-registered": 42,
+ "billing": false
+ }
+ }
+ ]
+ }
+
+Kea does not interpret or use the user-context information; it simply
+stores it and makes it available to the hook libraries. It is up to each
+hook library to extract that information and use it. The parser
+translates a ``comment`` entry into a user context with the entry, which
+allows a comment to be attached inside the configuration itself.
+
+
+.. _dhcp4-std:
+
+Supported DHCP Standards
+========================
+
+The following standards are currently supported in Kea:
+
+- *BOOTP Vendor Information Extensions*, `RFC 1497
+ <https://tools.ietf.org/html/rfc1497>`__: This requires the open source
+ BOOTP hook to be loaded. See :ref:`hooks-bootp` for details.
+
+- *Dynamic Host Configuration Protocol*, `RFC 2131
+ <https://tools.ietf.org/html/rfc2131>`__: Supported messages are
+ DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPRELEASE (7),
+ DHCPINFORM (8), DHCPACK (5), and DHCPNAK(6).
+
+- *DHCP Options and BOOTP Vendor Extensions*, `RFC 2132
+ <https://tools.ietf.org/html/rfc2132>`__: Supported options are PAD (0),
+ END(255), Message Type(53), DHCP Server Identifier (54), Domain Name (15),
+ DNS Servers (6), IP Address Lease Time (51), Subnet Mask (1), and Routers (3).
+
+- *The IPv4 Subnet Selection Option for DHCP*, `RFC 3011
+ <https://tools.ietf.org/html/rfc3011>`__: The subnet-selection option is
+ supported; if received in a packet, it is used in the subnet-selection
+ process.
+
+- *DHCP Relay Agent Information Option*, `RFC 3046
+ <https://tools.ietf.org/html/rfc3046>`__: Relay Agent Information,
+ Circuit ID, and Remote ID options are supported.
+
+- *Link Selection sub-option for the Relay Agent Option*, `RFC 3527
+ <https://tools.ietf.org/html/rfc3527>`__: The link selection sub-option
+ is supported.
+
+- *Vendor-Identifying Vendor Options for Dynamic Host Configuration
+ Protocol version 4*, `RFC 3925
+ <https://tools.ietf.org/html/rfc3925>`__: The Vendor-Identifying Vendor Class
+ and Vendor-Identifying Vendor-Specific Information options are supported.
+
+- *Subscriber-ID Suboption for the DHCP Relay Agent Option*, `RFC 3993
+ <https://tools.ietf.org/html/rfc3993>`__: The Subscriber-ID option is
+ supported.
+
+- *The Dynamic Host Configuration Protocol (DHCP) Client Fully
+ Qualified Domain Name (FQDN) Option*, `RFC 4702
+ <https://tools.ietf.org/html/rfc4702>`__: The Kea server is able to handle
+ the Client FQDN option. Also, it is able to use the :iscman:`kea-dhcp-ddns`
+ component to initiate appropriate DNS Update operations.
+
+- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic
+ Host Configuration Protocol (DHCP) Clients*, `RFC 4703
+ <https://tools.ietf.org/html/rfc4703>`__: The DHCPv6 server uses a DHCP-DDNS
+ server to resolve conflicts.
+
+- *Server Identifier Override sub-option for the Relay Agent Option*, `RFC 5107
+ <https://tools.ietf.org/html/rfc5107>`__: The server identifier override
+ sub-option is supported. The implementation is not complete according to the
+ RFC, because the server does not store the RAI, but the functionality handles
+ expected use cases.
+
+- *Client Identifier Option in DHCP Server Replies*, `RFC 6842
+ <https://tools.ietf.org/html/rfc6842>`__: The server by default sends back
+ the ``client-id`` option. That capability can be disabled. See
+ :ref:`dhcp4-echo-client-id` for details.
+
+- *Generalized UDP Source Port for the DHCP Relay Agent Option*, `RFC 8357
+ <https://tools.ietf.org/html/rfc8357>`__: The Kea server handles the Relay
+ Agent Information Source Port sub-option in a received message, remembers the
+ UDP port, and sends back a reply to the same relay agent using this UDP port.
+
+- *Captive-Portal Identification in DHCP and Router Advertisements (RAs)*, `RFC
+ 8910 <https://tools.ietf.org/html/rfc8910>`__: The Kea server can configure
+ both v4 and v6 versions of the captive portal options.
+
+- *IPv6-Only Preferred Option for DHCPv4*, `RFC 8925
+ <https://tools.ietf.org/html/rfc8925>`__: The Kea server is able to designate
+ its pools and subnets as IPv6-Only Preferred and send back the
+ ``v6-only-preferred`` option to clients that requested it.
+
+- *DHCP and Router Advertisement Options for the Discovery of Network-designated
+ Resolvers (DNR)*, `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The Kea server
+ supports the DNR option. Part of its value (SvcParams) must be configured in
+ hex.
+
+Known RFC Violations
+--------------------
+
+In principle, Kea aspires to be a reference implementation and aims to implement 100% of the RFC standards.
+However, in some cases there are practical aspects that prevent Kea from completely adhering to the text of the RFC documents.
+
+- `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__, page 30, says that if the incoming DHCPREQUEST packet has no
+ "requested IP address" option and ``ciaddr`` is not set, the server is supposed to respond with NAK. However,
+ broken clients exist that will always send a DHCPREQUEST without those options indicated. In that event, Kea accepts the DHCPREQUEST,
+ assigns an address, and responds with an ACK.
+
+- `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__, table 5, says that messages
+ of type DHCPDECLINE or DHCPRELEASE must have the server identifier set and
+ should be dropped if that option is missing. However, ISC DHCP does not enforce this, presumably as a compatibility
+ effort for broken clients, and the Kea team decided to follow suit.
+
+.. _dhcp4-limit:
+
+DHCPv4 Server Limitations
+=========================
+
+These are the current known limitations of the Kea DHCPv4 server software. Most of
+them are reflections of the current stage of development and should be
+treated as “not implemented yet”, rather than as actual limitations.
+However, some of them are implications of the design choices made. Those
+are clearly marked as such.
+
+- On the Linux and BSD system families, DHCP messages are sent and
+ received over raw sockets (using LPF and BPF) and all packet
+ headers (including data link layer, IP, and UDP headers) are created
+ and parsed by Kea, rather than by the system kernel. Currently, Kea
+ can only parse the data-link layer headers with a format adhering to
+ the IEEE 802.3 standard, and assumes this data-link-layer header
+ format for all interfaces. Thus, Kea does not work on interfaces
+ which use different data-link-layer header formats (e.g. Infiniband).
+
+.. _dhcp4-srv-examples:
+
+Kea DHCPv4 Server Examples
+==========================
+
+A collection of simple-to-use examples for the DHCPv4 component of Kea
+is available with the source files, located in the ``doc/examples/kea4``
+directory.
+
+.. _dhcp4-cb:
+
+Configuration Backend in DHCPv4
+===============================
+
+In the :ref:`config-backend` section we have described the Configuration
+Backend (CB) feature, its applicability, and its limitations. This section focuses
+on the usage of the CB with the Kea DHCPv4 server. It lists the supported
+parameters, describes limitations, and gives examples of DHCPv4
+server configurations to take advantage of the CB. Please also refer to
+the corresponding section :ref:`dhcp6-cb` for DHCPv6-specific usage of
+the CB.
+
+.. _dhcp4-cb-parameters:
+
+Supported Parameters
+--------------------
+
+The ultimate goal for the CB is to serve as a central configuration
+repository for one or multiple Kea servers connected to a database.
+In currently supported Kea versions, only a subset of
+the DHCPv4 server parameters can be configured in the database. All other
+parameters must be specified in the JSON configuration file, if
+required.
+
+All supported parameters can be configured via :ischooklib:`libdhcp_cb_cmds.so`.
+The general rule is that
+scalar global parameters are set using
+:isccmd:`remote-global-parameter4-set`; shared-network-specific parameters
+are set using :isccmd:`remote-network4-set`; and subnet-level and pool-level
+parameters are set using :isccmd:`remote-subnet4-set`. Whenever
+there is an exception to this general rule, it is highlighted in the
+table. Non-scalar global parameters have dedicated commands; for example,
+the global DHCPv4 options (``option-data``) are modified using
+:isccmd:`remote-option4-global-set`. Client classes, together with class-specific
+option definitions and DHCPv4 options, are configured using the
+:isccmd:`remote-class4-set` command.
+
+The :ref:`cb-sharing` section explains the concept of shareable
+and non-shareable configuration elements and the limitations for
+sharing them between multiple servers. In the DHCP configuration (both DHCPv4
+and DHCPv6), the shareable configuration elements are subnets and shared
+networks. Thus, they can be explicitly associated with multiple server tags.
+The global parameters, option definitions, and global options are non-shareable
+and can be associated with only one server tag. This rule does not apply
+to the configuration elements associated with ``all`` servers. Any configuration
+element associated with ``all`` servers (using the ``all`` keyword as a server tag) is
+used by all servers connecting to the configuration database.
+
+The following table lists DHCPv4-specific parameters supported by the
+Configuration Backend, with an indication of the level of the hierarchy
+at which it is currently supported.
+
+.. table:: List of DHCPv4 parameters supported by the Configuration Backend
+
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | Parameter | Global | Client | Shared | Subnet | Pool |
+ | | | Class | Network | | |
+ +=============================+============================+==============+=============+=============+=============+
+ | 4o6-interface | n/a | n/a | n/a | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | 4o6-interface-id | n/a | n/a | n/a | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | 4o6-subnet | n/a | n/a | n/a | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | allocator | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | boot-file-name | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | cache-max-age | yes | n/a | no | no | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | cache-threshold | yes | n/a | no | no | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | calculate-tee-times | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | client-class | n/a | n/a | yes | yes | yes |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-send-update | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-override-no-update | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-override-client-update | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-replace-client-name | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-generated-prefix | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | ddns-qualifying-suffix | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | decline-probation-period | yes | n/a | n/a | n/a | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | dhcp4o6-port | yes | n/a | n/a | n/a | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | echo-client-id | yes | n/a | n/a | n/a | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | hostname-char-set | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | hostname-char-replacement | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | interface | n/a | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | match-client-id | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | min-valid-lifetime | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | max-valid-lifetime | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | next-server | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | option-data | yes (via | yes | yes | yes | yes |
+ | | remote-option4-global-set) | | | | |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | option-def | yes (via | yes | n/a | n/a | n/a |
+ | | remote-option-def4-set) | | | | |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | rebind-timer | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | renew-timer | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | server-hostname | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | valid-lifetime | yes | yes | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | relay | n/a | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | require-client-classes | no | n/a | yes | yes | yes |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | reservation-mode | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | reservations-global | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | reservations-in-subnet | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | reservations-out-of-pool | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | t1-percent | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+ | t2-percent | yes | n/a | yes | yes | n/a |
+ +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+
+
+- ``yes`` - indicates that the parameter is supported at the given
+ level of the hierarchy and can be configured via the Configuration Backend.
+
+- ``no`` - indicates that a parameter is supported at the given level
+ of the hierarchy but cannot be configured via the Configuration Backend.
+
+- ``n/a`` - indicates that a given parameter is not applicable
+ at the particular level of the hierarchy or that the
+ server does not support the parameter at that level.
+
+Some scalar parameters contained by top level global maps are supported by the Configuration Backend.
+
+.. table:: List of DHCPv4 map parameters supported by the Configuration Backend
+
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | Parameter name (flat naming format) | Global map | Parameter name |
+ +==================================================================+==============================+==================================+
+ | compatibility.ignore-dhcp-server-identifier | compatibility | ignore-dhcp-server-identifier |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | compatibility.ignore-rai-link-selection | compatibility | ignore-rai-link-selection |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | compatibility.lenient-option-parsing | compatibility | lenient-option-parsing |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | compatibility.exclude-first-last-24 | compatibility | exclude-first-last-24 |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | control-socket.socket-name | control-socket | socket-name |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | control-socket.socket-type | control-socket | socket-type |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.enable-updates | dhcp-ddns | enable-updates |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.max-queue-size | dhcp-ddns | max-queue-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.ncr-format | dhcp-ddns | ncr-format |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.ncr-protocol | dhcp-ddns | ncr-protocol |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.sender-ip | dhcp-ddns | sender-ip |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.sender-port | dhcp-ddns | sender-port |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.server-ip | dhcp-ddns | server-ip |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.server-port | dhcp-ddns | server-port |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.generated-prefix | dhcp-ddns | generated-prefix |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.hostname-char-replacement | dhcp-ddns | hostname-char-replacement |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.hostname-char-set | dhcp-ddns | hostname-char-set |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.override-client-update | dhcp-ddns | override-client-update |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.override-no-update | dhcp-ddns | override-no-update |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.qualifying-suffix | dhcp-ddns | qualifying-suffix |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.replace-client-name | dhcp-ddns | replace-client-name |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.flush-reclaimed-timer-wait-time | expired-leases-processing | flush-reclaimed-timer-wait-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.hold-reclaimed-time | expired-leases-processing | hold-reclaimed-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.max-reclaim-leases | expired-leases-processing | max-reclaim-leases |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.max-reclaim-time | expired-leases-processing | max-reclaim-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.reclaim-timer-wait-time | expired-leases-processing | reclaim-timer-wait-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.unwarned-reclaim-cycles | expired-leases-processing | unwarned-reclaim-cycles |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.enable-multi-threading | multi-threading | enable-multi-threading |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.thread-pool-size | multi-threading | thread-pool-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.packet-queue-size | multi-threading | packet-queue-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | sanity-checks.lease-checks | sanity-checks | lease-checks |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | sanity-checks.extended-info-checks | sanity-checks | extended-info-checks |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.enable-queue | dhcp-queue-control | enable-queue |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.queue-type | dhcp-queue-control | queue-type |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.capacity | dhcp-queue-control | capacity |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+
+.. _dhcp4-cb-json:
+
+Enabling the Configuration Backend
+----------------------------------
+
+Consider the following configuration snippet, which uses a MySQL configuration
+database:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "server-tag": "my DHCPv4 server",
+ "config-control": {
+ "config-databases": [
+ {
+ "type": "mysql",
+ "name": "kea",
+ "user": "kea",
+ "password": "kea",
+ "host": "192.0.2.1",
+ "port": 3302
+ }
+ ],
+ "config-fetch-wait-time": 20
+ },
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_mysql_cb.so"
+ }, {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so"
+ }
+ ]
+ }
+ }
+
+The ``config-control`` map contains two parameters. ``config-databases``
+is a list that contains one element, which includes the database type, its location,
+and the credentials to be used to connect to this database. (Note that
+the parameters specified here correspond to the database specification
+for the lease database backend and hosts database backend.) Currently
+only one database connection can be specified on the
+``config-databases`` list. The server connects to this database
+during startup or reconfiguration, and fetches the configuration
+available for this server from the database. This configuration is
+merged into the configuration read from the configuration file.
+
+The following snippet illustrates the use of a PostgreSQL database:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "server-tag": "my DHCPv4 server",
+ "config-control": {
+ "config-databases": [
+ {
+ "type": "postgresql",
+ "name": "kea",
+ "user": "kea",
+ "password": "kea",
+ "host": "192.0.2.1",
+ "port": 5432
+ }
+ ],
+ "config-fetch-wait-time": 20
+ },
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_pgsql_cb.so"
+ }, {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so"
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ Whenever there is a conflict between the parameters specified in the
+ configuration file and the database, the parameters from the database
+ take precedence. We strongly recommend avoiding the duplication of
+ parameters in the file and the database, but this recommendation is
+ not enforced by the Kea servers. In particular, if the subnets'
+ configuration is sourced from the database, we recommend that all
+ subnets be specified in the database and that no subnets be specified in
+ the configuration file. It is possible to specify the subnets in both
+ places, but the subnets in the
+ configuration file with overlapping IDs and/or prefixes with the
+ subnets from the database will be superseded by those from the
+ database.
+
+Once the Kea server is configured, it starts periodically polling
+the database for configuration changes. The polling frequency is
+controlled by the ``config-fetch-wait-time`` parameter, expressed
+in seconds; it is the period between the time when the server
+completed its last poll (and possibly the local configuration update) and
+the time when it will begin polling again. In the example above, this period
+is set to 20 seconds. This means that after adding a new configuration
+into the database (e.g. adding a new subnet), it will take up to 20 seconds
+(plus the time needed to fetch and apply the new configuration) before
+the server starts using this subnet. The lower the
+``config-fetch-wait-time`` value, the shorter the time for the server to
+react to incremental configuration updates in the database. On the
+other hand, polling the database too frequently may impact the DHCP
+server's performance, because the server needs to make at least one query
+to the database to discover any pending configuration updates. The
+default value of ``config-fetch-wait-time`` is 30 seconds.
+
+The :isccmd:`config-backend-pull` command can be used to force the server to
+immediately poll any configuration changes from the database and avoid
+waiting for the next fetch cycle.
+
+In the configuration examples above, two hook libraries are loaded. The first
+is a library which implements the Configuration Backend for a specific database
+type: :ischooklib:`libdhcp_mysql_cb.so` provides support for MySQL and :ischooklib:`libdhcp_pgsql_cb.so`
+provides support for PostgreSQL. The library loaded must match the database
+``type`` specified within the ``config-control`` parameter or an will error be
+logged when the server attempts to load its configuration and the load will
+fail.
+
+The second hook library, :ischooklib:`libdhcp_cb_cmds.so`, is optional. It should
+be loaded when the Kea server instance is to be used to manage the
+configuration in the database. See the :ref:`hooks-cb-cmds` section for
+details. This hook library is only available to ISC
+customers with a paid support contract.
+
+.. _dhcp4-compatibility:
+
+Kea DHCPv4 Compatibility Configuration Parameters
+=================================================
+
+ISC's intention is for Kea to follow the RFC documents to promote better standards
+compliance. However, many buggy DHCP implementations already exist that cannot be
+easily fixed or upgraded. Therefore, Kea provides an easy-to-use compatibility
+mode for broken or non-compliant clients. For that purpose, the compatibility option must be
+enabled to permit uncommon practices:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "compatibility": {
+ }
+ }
+ }
+
+
+Lenient Option Parsing
+----------------------
+
+By default, tuple fields defined in custom options are parsed as a set of
+length-value pairs.
+
+With ``"lenient-option-parsing": true``, if a length ever exceeds the rest of
+the option's buffer, previous versions of Kea returned a log message ``unable to
+parse the opaque data tuple, the buffer length is x, but the tuple length is y``
+with ``x < y``; this no longer occurs. Instead, the value is considered to be the rest of the buffer,
+or in terms of the log message above, the tuple length ``y`` becomes ``x``.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "compatibility": {
+ "lenient-option-parsing": true
+ }
+ }
+ }
+
+Ignore DHCP Server Identifier
+-----------------------------
+
+With ``"ignore-dhcp-server-identifier": true``, the server does not check the
+address in the DHCP Server Identifier option, i.e. whether a query is sent
+to this server or another one (and in the second case dropping the query).
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "compatibility": {
+ "ignore-dhcp-server-identifier": true
+ }
+ }
+ }
+
+
+Ignore RAI Link Selection
+-------------------------
+
+With ``"ignore-rai-link-selection": true``, Relay Agent Information Link
+Selection sub-option data is not used for subnet selection. In this case,
+normal logic drives the subnet selection, instead of attempting to use the subnet specified
+by the sub-option. This option is not RFC-compliant and is set to ``false`` by
+default. Setting this option to ``true`` can help with subnet selection in
+certain scenarios; for example, when DHCP relays do not allow the administrator to
+specify which sub-options are included in the Relay Agent Information option,
+and include incorrect Link Selection information.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "compatibility": {
+ "ignore-rai-link-selection": true
+ }
+ }
+ }
+
+Exclude First Last Addresses in /24 Subnets or Larger
+-----------------------------------------------------
+
+The ``exclude-first-last-24`` compatibility flag is described in
+:ref:`dhcp4-address-config` (when true .0 and .255 addresses are excluded
+from subnets with prefix length less than or equal to 24).
+
+.. _dhcp4_allocation_strategies:
+
+Address Allocation Strategies in DHCPv4
+=======================================
+
+A DHCP server follows a complicated algorithm to select an IPv4 address for a client.
+It prefers assigning specific addresses requested by the client and the addresses for
+which the client has reservations.
+
+If the client requests no particular address and
+has no reservations, or other clients are already using any requested addresses, the server must
+find another available address within the configured pools. A server function called
+an "allocator" is responsible in Kea for finding an available address in such a case.
+
+The Kea DHCPv4 server provides configuration parameters to select different allocators
+at the global, shared-network, and subnet levels.
+Consider the following example:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "allocator": "random",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "allocator": "iterative"
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.2.0/24"
+ }
+ ]
+ }
+ }
+
+This allocator overrides the default iterative allocation strategy at the global level and
+selects the random allocation instead. The random allocation will be used
+for the subnet with ID 2, while the iterative allocation will be used for the subnet
+with ID 1.
+
+The following sections describe the supported allocators and their
+recommended uses.
+
+Allocators Comparison
+---------------------
+
+In the table below, we briefly compare the supported allocators. The
+detailed allocators' descriptions are in later sections.
+
+.. table:: Comparison of the lease allocators supported by Kea DHCPv4
+
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Allocator | Low Utilization Performance | High Utilization Performance | Lease Randomization | Startup/Configuration | Memory Usage |
+ +==================+=============================+==============================+=======================+==============================+================+
+ | Iterative | very high | low | no | very fast | low |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Random | high | low | yes | very fast | high (varying) |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Free Lease Queue | high | high | yes | slow (depends on pool sizes) | high (varying) |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+
+
+Iterative Allocator
+-------------------
+This is the default allocator used by the Kea DHCPv4 server. It remembers the
+last offered address and offers this address, increased by one, to the next client.
+For example, it may offer addresses in this order: ``192.0.2.10``, ``192.0.2.11``,
+``192.0.2.12``, and so on. The time to find and offer the next address is very
+short; thus, this is the most performant allocator when pool utilization
+is low and there is a high probability that the next address is available.
+
+The iterative allocation underperforms when multiple DHCP servers share a lease
+database or are connected to a cluster. The servers tend to offer and allocate
+the same blocks of addresses to different clients independently, which causes many
+allocation conflicts between the servers and retransmissions by clients. A random
+allocation addresses this issue by dispersing the allocation order.
+
+Random Allocator
+----------------
+
+The random allocator uses a uniform randomization function to select offered
+addresses from subnet pools. It is suitable in deployments where multiple servers
+are connected to a shared
+database or a database cluster. By dispersing the offered addresses, the servers
+minimize the risk of allocating the same address to two different clients at
+the same or nearly the same time. In addition, it improves the server's resilience against
+attacks based on allocation predictability.
+
+The random allocator is, however, slightly slower than the iterative allocator.
+Moreover, it increases the server's memory consumption because it must remember
+randomized addresses to avoid offering them repeatedly. Memory consumption grows
+with the number of offered addresses; in other words, larger pools and more
+clients increase memory consumption by random allocation.
+
+The following configuration snippet shows how to select the random allocator
+for a subnet:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "allocator": "random",
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "10.0.0.0/8",
+ "allocator": "random"
+ }
+ ]
+ }
+ }
+
+Free Lease Queue Allocator
+--------------------------
+
+This is a sophisticated allocator whose use should be considered in subnets
+with highly utilized address pools. In such cases, it can take a considerable
+amount of time for the iterative or random allocator to find an available
+address, because they must repeatedly check whether there is a valid lease for
+an address they will offer. The number of checks can be as high as the number
+of addresses in the subnet when the subnet pools are exhausted, which can have a
+direct negative impact on the DHCP response time for each request.
+
+The Free Lease Queue (FLQ) allocator tracks lease allocations and de-allocations
+and maintains a running list of available addresses for each address pool.
+It allows an available lease to be selected within a constant time, regardless of
+the subnet pools' utilization. The allocator continuously updates the list of
+free leases by removing any allocated leases and adding released or
+reclaimed ones.
+
+The following configuration snippet shows how to select the FLQ allocator
+for a subnet:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "allocator": "flq"
+ }
+ ]
+ }
+ }
+
+
+There are several considerations that the administrator should take into account
+before using this allocator. The FLQ allocator can heavily impact the server's
+startup and reconfiguration time, because the allocator has to populate the
+list of free leases for each subnet where it is used. These delays can be
+observed both during the configuration reload and when the subnets are
+created using :ischooklib:`libdhcp_subnet_cmds.so`. The allocator increases the
+memory consumption to hold the list of free leases, proportional
+to the total size of the address pools for which this allocator is used.
+Finally, lease reclamation must be enabled with a low value of the
+``reclaim-timer-wait-time`` parameter, to ensure that the server frequently
+collects expired leases and makes them available for allocation via the
+free lease queue. Expired leases are not considered free by
+the allocator until they are reclaimed by the server. See
+:ref:`lease-reclamation` for more details about the lease reclamation process.
+
+We recommend that the FLQ allocator be selected
+only after careful consideration. For example, using it for a subnet with a
+``/8`` pool may delay the server's startup by 15 seconds or more. On the
+other hand, the startup delay and the memory consumption increase should
+be acceptable for subnets with a ``/16`` pool or smaller. We also recommend
+specifying another allocator type in the global configuration settings
+and overriding this selection at the subnet or shared-network level, to use
+the FLQ allocator only for selected subnets. That way, when a new subnet is
+added without an allocator specification, the global setting is used, thus
+avoiding unnecessary impact on the server's startup time.
+
+Like the random allocator, the FLQ allocator offers leases in
+random order, which makes it suitable for use with a shared lease database.
diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst
new file mode 100644
index 0000000..f2f64de
--- /dev/null
+++ b/doc/sphinx/arm/dhcp6-srv.rst
@@ -0,0 +1,8184 @@
+.. _dhcp6:
+
+*****************
+The DHCPv6 Server
+*****************
+
+.. _dhcp6-start-stop:
+
+Starting and Stopping the DHCPv6 Server
+=======================================
+
+It is recommended that the Kea DHCPv6 server be started and stopped
+using :iscman:`keactrl` (described in :ref:`keactrl`); however, it is also
+possible to run the server directly via the :iscman:`kea-dhcp6` command, which accepts
+the following command-line switches:
+
+- ``-c file`` - specifies the configuration file. This is the only
+ mandatory switch.
+
+- ``-d`` - specifies whether the server logging should be switched to
+ debug/verbose mode. In verbose mode, the logging severity and debuglevel
+ specified in the configuration file are ignored; "debug" severity
+ and the maximum debuglevel (99) are assumed. The flag is convenient
+ for temporarily switching the server into maximum verbosity, e.g.
+ when debugging.
+
+- ``-p server-port`` - specifies the local UDP port on which the server
+ listens. This is only useful during testing, as a DHCPv6 server
+ listening on ports other than the standard ones is not able to
+ handle regular DHCPv6 queries.
+
+- ``-P client-port`` - specifies the remote UDP port to which the
+ server sends all responses. This is only useful during testing,
+ as a DHCPv6 server sending responses to ports other than the standard
+ ones is not able to handle regular DHCPv6 queries.
+
+- ``-t file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp6`
+ loads it, checks it, and exits. During the test, log messages are
+ printed to standard output and error messages to standard error. The
+ result of the test is reported through the exit code (0 =
+ configuration looks OK, 1 = error encountered). The check is not
+ comprehensive; certain checks are possible only when running the
+ server.
+
+- ``-T file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp6`
+ loads it, checks it, and exits. It performs extra checks beyond what ``-t``
+ offers, such as establishing database connections (for the lease backend,
+ host reservations backend, configuration backend, and forensic logging
+ backend), loading hook libraries, parsing hook-library configurations, etc.
+ It does not open UNIX or TCP/UDP sockets, nor does it open or rotate
+ files, as any of these actions could interfere with a running process on the
+ same machine.
+
+- ``-v`` - displays the Kea version and exits.
+
+- ``-V`` - displays the Kea extended version with additional parameters
+ and exits. The listing includes the versions of the libraries
+ dynamically linked to Kea.
+
+- ``-W`` - displays the Kea configuration report and exits. The report
+ is a copy of the ``config.report`` file produced by ``./configure``;
+ it is embedded in the executable binary.
+
+ The contents of the ``config.report`` file may also be accessed by examining
+ certain libraries in the installation tree or in the source tree.
+
+ .. code-block:: shell
+
+ # from installation using libkea-process.so
+ $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.so
+ $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.a
+ $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
+
+ # from sources using libcfgrpt.a
+ $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
+
+On startup, the server detects available network interfaces and
+attempts to open UDP sockets on all interfaces listed in the
+configuration file. Since the DHCPv6 server opens privileged ports, it
+requires root access; this daemon must be run as root.
+
+During startup, the server attempts to create a PID file of the
+form: ``[runstatedir]/kea/[conf name].kea-dhcp6.pid``, where:
+
+- ``runstatedir``: The value as passed into the build configure
+ script; it defaults to ``/usr/local/var/run``. Note that this value may be
+ overridden at runtime by setting the environment variable
+ ``KEA_PIDFILE_DIR``, although this is intended primarily for testing
+ purposes.
+
+- ``conf name``: The configuration file name used to start the server,
+ minus all preceding paths and the file extension. For example, given
+ a pathname of ``/usr/local/etc/kea/myconf.txt``, the portion used would
+ be ``myconf``.
+
+If the file already exists and contains the PID of a live process, the
+server issues a ``DHCP6_ALREADY_RUNNING`` log message and exits. It is
+possible, though unlikely, that the file is a remnant of a system crash
+and the process to which the PID belongs is unrelated to Kea. In such a
+case, it would be necessary to manually delete the PID file.
+
+The server can be stopped using the ``kill`` command. When running in a
+console, the server can also be shut down by pressing Ctrl-c. Kea detects
+the key combination and shuts down gracefully.
+
+The reconfiguration of each Kea server is triggered by the SIGHUP signal.
+When a server receives the SIGHUP signal it rereads its configuration file and,
+if the new configuration is valid, uses the new configuration.
+If the new configuration proves to be invalid, the server retains its
+current configuration; however, in some cases a fatal error message is logged
+indicating that the server is no longer providing any service: a working
+configuration must be loaded as soon as possible.
+
+.. _dhcp6-configuration:
+
+DHCPv6 Server Configuration
+===========================
+
+Introduction
+------------
+
+This section explains how to configure the Kea DHCPv6 server using a
+configuration file.
+
+Before DHCPv6 is started, its configuration file must
+be created. The basic configuration is as follows:
+
+::
+
+ {
+ # DHCPv6 configuration starts on the next line
+ "Dhcp6": {
+
+ # First we set up global values
+ "valid-lifetime": 4000,
+ "renew-timer": 1000,
+ "rebind-timer": 2000,
+ "preferred-lifetime": 3000,
+
+ # Next we set up the interfaces to be used by the server.
+ "interfaces-config": {
+ "interfaces": [ "eth0" ]
+ },
+
+ # And we specify the type of lease database
+ "lease-database": {
+ "type": "memfile",
+ "persist": true,
+ "name": "/var/lib/kea/dhcp6.leases"
+ },
+
+ # Finally, we list the subnets from which we will be leasing addresses.
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::ffff"
+ }
+ ]
+ }
+ ]
+ # DHCPv6 configuration ends with the next line
+ }
+
+ }
+
+The following paragraphs provide a brief overview of the parameters in
+the above example, along with their format. Subsequent sections of this
+chapter go into much greater detail for these and other parameters.
+
+The lines starting with a hash (#) are comments and are ignored by the
+server; they do not impact its operation in any way.
+
+The configuration starts in the first line with the initial opening
+curly bracket (or brace). Each configuration must contain an object
+specifying the configuration of the Kea module using it. In the example
+above, this object is called ``Dhcp6``.
+
+The ``Dhcp6`` configuration starts with the ``"Dhcp6": {`` line and ends
+with the corresponding closing brace (in the above example, the brace
+after the last comment). Everything defined between those lines is
+considered to be the ``Dhcp6`` configuration.
+
+In general, the order in which those parameters appear does not
+matter, but there are two caveats. The first one is that the
+configuration file must be well-formed JSON, meaning that the
+parameters for any given scope must be separated by a comma, and there
+must not be a comma after the last parameter. When reordering a
+configuration file, moving a parameter to or from the
+last position in a given scope may also require moving the comma. The
+second caveat is that it is uncommon — although legal JSON — to repeat
+the same parameter multiple times. If that happens, the last occurrence
+of a given parameter in a given scope is used, while all previous
+instances are ignored. This is unlikely to cause any confusion as there
+are no real-life reasons to keep multiple copies of the same parameter
+in the configuration file.
+
+The first few DHCPv6 configuration elements
+define some global parameters. ``valid-lifetime`` defines how long the
+addresses (leases) given out by the server are valid; the default
+is for a client to be allowed to use a given address for 4000
+seconds. (Note that integer numbers are specified as is, without any
+quotes around them.) The address will become deprecated in 3000 seconds,
+i.e. clients are allowed to keep old connections, but cannot use this
+address to create new connections. ``renew-timer`` and
+``rebind-timer`` are values (also in seconds) that define T1 and T2 timers, which govern
+when the client begins the renewal and rebind procedures.
+
+The ``interfaces-config`` map specifies the network interfaces on which the
+server should listen to DHCP messages. The ``interfaces`` parameter specifies
+a list of network interfaces on which the server should listen. Lists are
+opened and closed with square brackets, with elements separated by commas. To
+listen on two interfaces, the ``interfaces-config`` element should look like
+this:
+
+::
+
+ {
+ "interfaces-config": {
+ "interfaces": [ "eth0", "eth1" ]
+ },
+ ...
+ }
+
+The next lines define the lease database, the place where the
+server stores its lease information. This particular example tells the
+server to use memfile, which is the simplest and fastest database
+backend. It uses an in-memory database and stores leases on disk in a
+CSV (comma-separated values) file. This is a very simple configuration example;
+usually the lease database configuration is more extensive and contains
+additional parameters. Note that ``lease-database`` is an object and opens up a
+new scope, using an opening brace. Its parameters (just one in this example:
+``type``) follow. If there were more than one, they would be separated
+by commas. This scope is closed with a closing brace. As more parameters
+for the ``Dhcp6`` definition follow, a trailing comma is present.
+
+Finally, we need to define a list of IPv6 subnets. This is the most
+important DHCPv6 configuration structure, as the server uses that
+information to process clients' requests. It defines all subnets from
+which the server is expected to receive DHCP requests. The subnets are
+specified with the ``subnet6`` parameter. It is a list, so it starts and
+ends with square brackets. Each subnet definition in the list has
+several attributes associated with it, so it is a structure and is
+opened and closed with braces. At a minimum, a subnet definition must
+have at least two parameters: ``subnet``, which defines the whole
+subnet; and ``pools``, which is a list of dynamically allocated pools
+that are governed by the DHCP server.
+
+The example contains a single subnet. If more than one were defined,
+additional elements in the ``subnet6`` parameter would be specified and
+separated by commas. For example, to define two subnets, the following
+syntax would be used:
+
+::
+
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [ { "pool": "2001:db8:1::/112" } ],
+ "subnet": "2001:db8:1::/64"
+ },
+ {
+ "id": 2,
+ "pools": [ { "pool": "2001:db8:2::1-2001:db8:2::ffff" } ],
+ "subnet": "2001:db8:2::/64"
+ }
+ ],
+ ...
+ }
+
+Note that indentation is optional and is used for aesthetic purposes
+only. In some cases it may be preferable to use more compact notation.
+
+After all the parameters have been specified, there are two contexts open:
+``global`` and ``Dhcp6``; thus, two closing curly brackets must be used to close
+them.
+
+Lease Storage
+-------------
+
+All leases issued by the server are stored in the lease database.
+There are three database backends available: memfile
+(the default), MySQL, PostgreSQL.
+
+Memfile - Basic Storage for Leases
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server is able to store lease data in different repositories. Larger
+deployments may elect to store leases in a database;
+:ref:`database-configuration6` describes this option. In
+typical smaller deployments, though, the server stores lease
+information in a CSV file rather than a database. As well as requiring
+less administration, an advantage of using a file for storage is that it
+eliminates a dependency on third-party database software.
+
+The configuration of the memfile backend is controlled through
+the ``Dhcp6``/``lease-database`` parameters. The ``type`` parameter is mandatory
+and specifies which storage for leases the server should use, through
+the ``"memfile"`` value. The following list gives additional optional parameters
+that can be used to configure the memfile backend.
+
+- ``persist``: controls whether the new leases and updates to existing
+ leases are written to the file. It is strongly recommended that the
+ value of this parameter be set to ``true`` at all times during the
+ server's normal operation. Not writing leases to disk means that if a
+ server is restarted (e.g. after a power failure), it will not know
+ which addresses have been assigned. As a result, it may assign new clients
+ addresses that are already in use. The value of
+ ``false`` is mostly useful for performance-testing purposes. The
+ default value of the ``persist`` parameter is ``true``, which enables
+ writing lease updates to the lease file.
+
+- ``name``: specifies an absolute location of the lease file in which
+ new leases and lease updates are recorded. The default value for
+ this parameter is ``"[kea-install-dir]/var/lib/kea/kea-leases6.csv"``.
+
+- ``lfc-interval``: specifies the interval, in seconds, at which the
+ server will perform a lease file cleanup (LFC). This removes
+ redundant (historical) information from the lease file and
+ effectively reduces the lease file size. The cleanup process is
+ described in more detail later in this section. The default
+ value of the ``lfc-interval`` is ``3600``. A value of ``0`` disables the LFC.
+
+- ``max-row-errors``: specifies the number of row errors before the server
+ stops attempting to load a lease file. When the server loads a lease file, it is processed
+ row by row, each row containing a single lease. If a row is flawed and
+ cannot be processed correctly the server logs it, discards the row,
+ and goes on to the next row. This parameter can be used to set a limit on
+ the number of such discards that can occur, after which the server
+ abandons the effort and exits. The default value of ``0`` disables the limit
+ and allows the server to process the entire file, regardless of how many
+ rows are discarded.
+
+An example configuration of the memfile backend is presented below:
+
+::
+
+ "Dhcp6": {
+ "lease-database": {
+ "type": "memfile",
+ "persist": true,
+ "name": "/tmp/kea-leases6.csv",
+ "lfc-interval": 1800,
+ "max-row-errors": 100
+ }
+ }
+
+This configuration selects ``/tmp/kea-leases6.csv`` as the storage file
+for lease information and enables persistence (writing lease updates to
+this file). It also configures the backend to perform a periodic cleanup
+of the lease file every 1800 seconds (30 minutes) and sets the maximum number of
+row errors to 100.
+
+Why Is Lease File Cleanup Necessary?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to know how the lease file contents are organized to
+understand why the periodic lease file cleanup is needed. Every time the
+server updates a lease or creates a new lease for a client, the new
+lease information must be recorded in the lease file. For performance
+reasons, the server does not update the existing client's lease in the
+file, as this would potentially require rewriting the entire file.
+Instead, it simply appends the new lease information to the end of the
+file; the previous lease entries for the client are not removed. When
+the server loads leases from the lease file, e.g. at server startup,
+it assumes that the latest lease entry for the client is the valid one.
+Previous entries are discarded, meaning that the server can
+reconstruct accurate information about the leases even though there
+may be many lease entries for each client. However, storing many entries
+for each client results in a bloated lease file and impairs the
+performance of the server's startup and reconfiguration, as it needs to
+process a larger number of lease entries.
+
+Lease file cleanup (LFC) removes all previous entries for each client
+and leaves only the latest ones. The interval at which the cleanup is
+performed is configurable, and it should be selected according to the
+frequency of lease renewals initiated by the clients. The more frequent
+the renewals, the smaller the value of ``lfc-interval`` should be. Note,
+however, that the LFC takes time and thus it is possible (although
+unlikely) that, if the ``lfc-interval`` is too short, a new cleanup may
+be started while the previous one is still running. The server would
+recover from this by skipping the new cleanup when it detected that the
+previous cleanup was still in progress, but it implies that the actual
+cleanups will be triggered more rarely than the configured interval. Moreover,
+triggering a new cleanup adds overhead to the server, which is not
+able to respond to new requests for a short period of time when the new
+cleanup process is spawned. Therefore, it is recommended that the
+``lfc-interval`` value be selected in a way that allows the LFC
+to complete the cleanup before a new cleanup is triggered.
+
+Lease file cleanup is performed by a separate process (in the
+background) to avoid a performance impact on the server process. To
+avoid conflicts between two processes using the same lease
+files, the LFC process starts with Kea opening a new lease file; the
+actual LFC process operates on the lease file that is no longer used by
+the server. There are also other files created as a side effect of the
+lease file cleanup. The detailed description of the LFC process is located later
+in this Kea Administrator's Reference Manual: :ref:`kea-lfc`.
+
+.. _database-configuration6:
+
+Lease Database Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ Lease database access information must be configured for the DHCPv6
+ server, even if it has already been configured for the DHCPv4 server.
+ The servers store their information independently, so each server can
+ use a separate database or both servers can use the same database.
+
+.. note::
+
+ Kea requires the database timezone to match the system timezone.
+ For more details, see :ref:`mysql-database-create` and
+ :ref:`pgsql-database-create`.
+
+Lease database configuration is controlled through the
+``Dhcp6``/``lease-database`` parameters. The database type must be set to
+``memfile``, ``mysql`` or ``postgresql``, e.g.:
+
+::
+
+ "Dhcp6": { "lease-database": { "type": "mysql", ... }, ... }
+
+Next, the name of the database to hold the leases must be set; this is
+the name used when the database was created (see
+:ref:`mysql-database-create` or :ref:`pgsql-database-create`).
+
+For MySQL or PostgreSQL:
+
+::
+
+ "Dhcp6": { "lease-database": { "name": "database-name" , ... }, ... }
+
+If the database is located on a different system from the DHCPv6 server,
+the database host name must also be specified:
+
+::
+
+ "Dhcp6": { "lease-database": { "host": "remote-host-name", ... }, ... }
+
+Normally, the database is on the same machine as the DHCPv6 server.
+In this case, set the value to the empty string:
+
+::
+
+ "Dhcp6": { "lease-database": { "host" : "", ... }, ... }
+
+Should the database use a port other than the default, it may be
+specified as well:
+
+::
+
+ "Dhcp6": { "lease-database": { "port" : 12345, ... }, ... }
+
+Should the database be located on a different system, the administrator may need to
+specify a longer interval for the connection timeout:
+
+::
+
+ "Dhcp6": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... }
+
+The default value of five seconds should be more than adequate for local
+connections. If a timeout is given, though, it should be an integer
+greater than zero.
+
+The maximum number of times the server automatically attempts to
+reconnect to the lease database after connectivity has been lost may be
+specified:
+
+::
+
+ "Dhcp6": { "lease-database": { "max-reconnect-tries" : number-of-tries, ... }, ... }
+
+If the server is unable to reconnect to the database after making the
+maximum number of attempts, the server will exit. A value of 0 (the
+default) disables automatic recovery and the server will exit
+immediately upon detecting a loss of connectivity (MySQL and PostgreSQL
+only).
+
+The number of milliseconds the server waits between attempts to
+reconnect to the lease database after connectivity has been lost may
+also be specified:
+
+::
+
+ "Dhcp6": { "lease-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... }
+
+The default value for MySQL and PostgreSQL is 0, which disables automatic
+recovery and causes the server to exit immediately upon detecting the
+loss of connectivity.
+
+::
+
+ "Dhcp6": { "lease-database": { "on-fail" : "stop-retry-exit", ... }, ... }
+
+The possible values are:
+
+- ``stop-retry-exit`` - disables the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``. This is the default value for the lease backend,
+ the host backend, and the configuration backend.
+
+- ``serve-retry-exit`` - continues the DHCP service while trying to
+ automatically recover lost connections. Shuts down the server on failure
+ after exhausting ``max-reconnect-tries``.
+
+- ``serve-retry-continue`` - continues the DHCP service and does not shut down
+ the server even if the recovery fails. This is the default value for forensic
+ logging.
+
+.. note::
+
+ Automatic reconnection to database backends is configured individually per
+ backend; this allows users to tailor the recovery parameters to each backend
+ they use. We suggest that users enable it either for all backends or none,
+ so behavior is consistent.
+
+ Losing connectivity to a backend for which reconnection is disabled results
+ (if configured) in the server shutting itself down. This includes cases when
+ the lease database backend and the hosts database backend are connected to
+ the same database instance.
+
+ It is highly recommended not to change the ``stop-retry-exit`` default
+ setting for the lease manager, as it is critical for the connection to be
+ active while processing DHCP traffic. Change this only if the server is used
+ exclusively as a configuration tool.
+
+::
+
+ "Dhcp6": { "lease-database": { "retry-on-startup" : true, ... }, ... }
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
+
+The host parameter is used by the MySQL and PostgreSQL backends.
+
+Finally, the credentials of the account under which the server will
+access the database should be set:
+
+::
+
+ "Dhcp6": {
+ "lease-database": {
+ "user": "user-name",
+ "password": "password",
+ ...
+ },
+ ...
+ }
+
+If there is no password to the account, set the password to the empty
+string ``""``. (This is the default.)
+
+.. _tuning-database-timeouts6:
+
+Tuning Database Timeouts
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+In rare cases, reading or writing to the database may hang. This can be
+caused by a temporary network issue, or by misconfiguration of the proxy
+server switching the connection between different database instances.
+These situations are rare, but users have reported
+that Kea sometimes hangs while performing database IO operations.
+Setting appropriate timeout values can mitigate such issues.
+
+MySQL exposes two distinct connection options to configure the read and
+write timeouts. Kea's corresponding ``read-timeout`` and ``write-timeout``
+configuration parameters specify the timeouts in seconds. For example:
+
+::
+
+ "Dhcp6": { "lease-database": { "read-timeout" : 10, "write-timeout": 20, ... }, ... }
+
+
+Setting these parameters to 0 is equivalent to not specifying them, and
+causes the Kea server to establish a connection to the database with the
+MySQL defaults. In this case, Kea waits indefinitely for the completion of
+the read and write operations.
+
+MySQL versions earlier than 5.6 do not support setting timeouts for
+read and write operations. Moreover, the ``read-timeout`` and ``write-timeout``
+parameters can only be specified for the MySQL backend; setting them for
+any other backend database type causes a configuration error.
+
+To set a timeout in seconds for PostgreSQL, use the ``tcp-user-timeout``
+parameter. For example:
+
+::
+
+ "Dhcp6": { "lease-database": { "tcp-user-timeout" : 10, ... }, ... }
+
+
+Specifying this parameter for other backend types causes a configuration
+error.
+
+.. note::
+
+ The timeouts described here are only effective for TCP connections.
+ Please note that the MySQL client library used by the Kea servers
+ typically connects to the database via a UNIX domain socket when the
+ ``host`` parameter is ``localhost``, but establishes a TCP connection
+ for ``127.0.0.1``.
+
+
+.. _hosts6-storage:
+
+Hosts Storage
+-------------
+
+Kea is also able to store information about host reservations in the
+database. The hosts database configuration uses the same syntax as the
+lease database. In fact, the Kea server opens independent connections for
+each purpose, be it lease or hosts information, which gives
+the most flexibility. Kea can keep leases and host reservations
+separately, but can also point to the same database. Currently the
+supported hosts database types are MySQL and PostgreSQL.
+
+The following configuration can be used to configure a
+connection to MySQL:
+
+::
+
+ "Dhcp6": {
+ "hosts-database": {
+ "type": "mysql",
+ "name": "kea",
+ "user": "kea",
+ "password": "secret123",
+ "host": "localhost",
+ "port": 3306
+ }
+ }
+
+Depending on the database configuration, many of the
+parameters may be optional.
+
+Please note that usage of hosts storage is optional. A user can define
+all host reservations in the configuration file, and that is the
+recommended way if the number of reservations is small. However, when
+the number of reservations grows, it is more convenient to use host
+storage. Please note that both storage methods (the configuration file and
+one of the supported databases) can be used together. If hosts are
+defined in both places, the definitions from the configuration file are
+checked first and external storage is checked later, if necessary.
+
+Host information can be placed in multiple stores. Operations
+are performed on the stores in the order they are defined in the
+configuration file, although this leads to a restriction in ordering
+in the case of a host reservation addition; read-only stores must be
+configured after a (required) read-write store, or the addition will
+fail.
+
+.. note::
+
+ Kea requires the database timezone to match the system timezone.
+ For more details, see :ref:`mysql-database-create` and
+ :ref:`pgsql-database-create`.
+
+.. _hosts-databases-configuration6:
+
+DHCPv6 Hosts Database Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hosts database configuration is controlled through the
+``Dhcp6``/``hosts-database`` parameters. If enabled, the type of database must
+be set to ``mysql`` or ``postgresql``.
+
+::
+
+ "Dhcp6": { "hosts-database": { "type": "mysql", ... }, ... }
+
+Next, the name of the database to hold the reservations must be set;
+this is the name used when the lease database was created (see
+:ref:`supported-databases` for instructions on how to set up the
+desired database type):
+
+::
+
+ "Dhcp6": { "hosts-database": { "name": "database-name" , ... }, ... }
+
+If the database is located on a different system than the DHCPv6 server,
+the database host name must also be specified:
+
+::
+
+ "Dhcp6": { "hosts-database": { "host": remote-host-name, ... }, ... }
+
+Normally, the database is on the same machine as the DHCPv6 server.
+In this case, set the value to the empty string:
+
+::
+
+ "Dhcp6": { "hosts-database": { "host" : "", ... }, ... }
+
+Should the database use a port different than the default, it may be
+specified as well:
+
+::
+
+ "Dhcp6": { "hosts-database": { "port" : 12345, ... }, ... }
+
+The maximum number of times the server automatically attempts to
+reconnect to the host database after connectivity has been lost may be
+specified:
+
+::
+
+ "Dhcp6": { "hosts-database": { "max-reconnect-tries" : number-of-tries, ... }, ... }
+
+If the server is unable to reconnect to the database after making the
+maximum number of attempts, the server will exit. A value of 0 (the
+default) disables automatic recovery and the server will exit
+immediately upon detecting a loss of connectivity (MySQL and PostgreSQL
+only).
+
+The number of milliseconds the server waits between attempts to
+reconnect to the host database after connectivity has been lost may also
+be specified:
+
+::
+
+ "Dhcp6": { "hosts-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... }
+
+The default value for MySQL and PostgreSQL is 0, which disables automatic
+recovery and causes the server to exit immediately upon detecting the
+loss of connectivity.
+
+::
+
+ "Dhcp6": { "hosts-database": { "on-fail" : "stop-retry-exit", ... }, ... }
+
+The possible values are:
+
+- ``stop-retry-exit`` - disables the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``. This is the default value for MySQL and PostgreSQL.
+
+- ``serve-retry-exit`` - continues the DHCP service while trying to automatically
+ recover lost connections. Shuts down the server on failure after exhausting
+ ``max-reconnect-tries``.
+
+- ``serve-retry-continue`` - continues the DHCP service and does not shut down the
+ server even if the recovery fails.
+
+.. note::
+
+ Automatic reconnection to database backends is configured individually per
+ backend. This allows users to tailor the recovery parameters to each backend
+ they use. We suggest that users enable it either for all backends or none,
+ so behavior is consistent.
+
+ Losing connectivity to a backend for which reconnection is disabled results
+ (if configured) in the server shutting itself down. This includes cases when
+ the lease database backend and the hosts database backend are connected to
+ the same database instance.
+
+::
+
+ "Dhcp6": { "hosts-database": { "retry-on-startup" : true, ... }, ... }
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
+Database connection retries are not attempted on startup if the
+:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a
+valid connection to the database to check if JSON format is supported and to
+recount class limits.
+
+Finally, the credentials of the account under which the server will
+access the database should be set:
+
+::
+
+ "Dhcp6": {
+ "hosts-database": {
+ "user": "user-name",
+ "password": "password",
+ ...
+ },
+ ...
+ }
+
+If there is no password to the account, set the password to the empty
+string ``""``. (This is the default.)
+
+The multiple-storage extension uses a similar syntax; a configuration is
+placed into a ``hosts-databases`` list instead of into a ``hosts-database``
+entry, as in:
+
+::
+
+ "Dhcp6": { "hosts-databases": [ { "type": "mysql", ... }, ... ], ... }
+
+If the same host is configured both in-file and in-database, Kea does not issue a warning,
+as it would if both were specified in the same data source.
+Instead, the host configured in-file has priority over the one configured
+in-database.
+
+.. _read-only-database-configuration6:
+
+Using Read-Only Databases for Host Reservations with DHCPv6
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some deployments, the user whose name is specified in the
+database backend configuration may not have write privileges to the
+database. This is often required by the policy within a given network to
+secure the data from being unintentionally modified. In many cases
+administrators have deployed inventory databases, which contain
+substantially more information about the hosts than just the static
+reservations assigned to them. The inventory database can be used to
+create a view of a Kea hosts database and such a view is often
+read-only.
+
+Kea host-database backends operate with an implicit configuration to
+both read from and write to the database. If the user does not
+have write access to the host database, the backend will fail to start
+and the server will refuse to start (or reconfigure). However, if access
+to a read-only host database is required for retrieving reservations
+for clients and/or assigning specific addresses and options, it is
+possible to explicitly configure Kea to start in "read-only" mode. This
+is controlled by the ``readonly`` boolean parameter as follows:
+
+::
+
+ "Dhcp6": { "hosts-database": { "readonly": true, ... }, ... }
+
+Setting this parameter to ``false`` configures the database backend to
+operate in "read-write" mode, which is also the default configuration if
+the parameter is not specified.
+
+.. note::
+
+ The ``readonly`` parameter is only supported for MySQL and
+ PostgreSQL databases.
+
+
+Tuning Database Timeouts for Hosts Storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+See :ref:`tuning-database-timeouts6`.
+
+.. _dhcp6-interface-configuration:
+
+Interface Configuration
+-----------------------
+
+The DHCPv6 server must be configured to listen on specific network
+interfaces. The simplest network interface configuration tells the
+server to listen on all available interfaces:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "*" ]
+ },
+ ...
+ }
+
+The asterisk plays the role of a wildcard and means "listen on all
+interfaces." However, it is usually a good idea to explicitly specify
+interface names:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ]
+ },
+ ...
+ }
+
+
+It is possible to use an interface wildcard (*) concurrently
+with explicit interface names:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3", "*" ]
+ },
+ ...
+ }
+
+This format should only be used when it is
+desired to temporarily override a list of interface names and listen on
+all interfaces.
+
+As with the DHCPv4 server, binding to specific addresses and disabling
+re-detection of interfaces are supported. But ``dhcp-socket-type`` is
+not supported, because DHCPv6 uses only UDP/IPv6 sockets. The following example
+shows how to disable interface detection:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "re-detect": false
+ },
+ ...
+ }
+
+
+The loopback interfaces (i.e. the ``lo`` or ``lo0`` interface) are not
+configured by default, unless explicitly mentioned in the
+configuration. Note that Kea requires a link-local address (which does
+not exist on all systems) or a specified unicast address, as in:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "enp0s2/2001:db8::1234:abcd" ]
+ },
+ ...
+ }
+
+Kea binds the service sockets for each interface on startup. If another
+process is already using a port, then Kea logs the message and suppresses an
+error. DHCP service runs, but it is unavailable on some interfaces.
+
+The "service-sockets-require-all" option makes Kea require all sockets to
+be successfully bound. If any opening fails, Kea interrupts the
+initialization and exits with a non-zero status. (Default is false).
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "service-sockets-require-all": true
+ },
+ ...
+ }
+
+Sometimes, immediate interruption isn't a good choice. The port can be
+unavailable only temporary. In this case, retrying the opening may resolve
+the problem. Kea provides two options to specify the retrying:
+``service-sockets-max-retries`` and ``service-sockets-retry-wait-time``.
+
+The first defines a maximal number of retries that Kea makes to open a socket.
+The zero value (default) means that the Kea doesn't retry the process.
+
+The second defines a wait time (in milliseconds) between attempts. The default
+value is 5000 (5 seconds).
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1", "eth3" ],
+ "service-sockets-max-retries": 5,
+ "service-sockets-retry-wait-time": 5000
+ },
+ ...
+ }
+
+If "service-sockets-max-retries" is non-zero and "service-sockets-require-all"
+is false, then Kea retries the opening (if needed) but does not fail if any
+socket is still not opened.
+
+.. _ipv6-subnet-id:
+
+IPv6 Subnet Identifier
+----------------------
+
+The subnet identifier (subnet ID) is a unique number associated with a particular
+subnet. In principle, it is used to associate clients' leases with their
+respective subnets. The server configuration should contain unique and stable
+identifiers for all subnets. When a subnet identifier is not specified for a
+subnet, it is automatically assigned by the configuration mechanism. The identifiers
+are assigned starting at 1 and are monotonically increased for each subsequent
+subnet: 1, 2, 3, ....
+
+If there are multiple subnets configured with auto-generated identifiers
+and one of them is removed, the subnet identifiers may be renumbered.
+For example: if there are four subnets and the third is removed, the
+last subnet will be assigned the identifier that the third subnet had
+before removal. As a result, the leases stored in the lease database for
+subnet 3 are now associated with subnet 4, something that may have
+unexpected consequences. It is one of the reasons why auto-generated subnet
+identifiers are deprecated starting from Kea version 2.4.0.
+
+.. note::
+
+ The auto-generation of the subnet identifiers will be removed in a future
+ release. Starting from Kea 2.4.0, a subnet without an ``id`` entry
+ or with the zero value raises a warning at the configuration time.
+
+.. note::
+
+ Subnet IDs must be greater than zero and less than 4294967295.
+
+The following configuration assigns the specified subnet identifier
+to a newly configured subnet:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "id": 1024,
+ ...
+ }
+ ]
+ }
+
+This identifier will not change for this subnet unless the ``id``
+parameter is removed or set to 0. The value of 0 forces auto-generation
+of the subnet identifier.
+
+.. _ipv6-subnet-prefix:
+
+IPv6 Subnet Prefix
+------------------
+
+The subnet prefix is the second way to identify a subnet. Kea can
+accept non-canonical subnet addresses; for instance,
+this configuration is accepted:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::1/64",
+ ...
+ }
+ ]
+ }
+
+This works even if there is another subnet with the "2001:db8:1::/64" prefix;
+only the textual form of subnets are compared to avoid duplicates.
+
+.. note::
+
+ Abuse of this feature can lead to incorrect subnet selection
+ (see :ref:`dhcp6-config-subnets`).
+
+.. _dhcp6-unicast:
+
+Unicast Traffic Support
+-----------------------
+
+When the DHCPv6 server starts, by default it listens to the DHCP traffic
+sent to multicast address ff02::1:2 on each interface that it is
+configured to listen on (see :ref:`dhcp6-interface-configuration`). In some cases it is
+useful to configure a server to handle incoming traffic sent to global
+unicast addresses as well; the most common reason for this is to have
+relays send their traffic to the server directly. To configure the
+server to listen on a specific unicast address, add a slash (/) after the interface name,
+followed by the global unicast
+address on which the server should listen. The server will listen to this
+address in addition to normal link-local binding and listening on the
+ff02::1:2 address. The sample configuration below shows how to listen on
+2001:db8::1 (a global address) configured on the ``eth1`` interface.
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "eth1/2001:db8::1" ]
+ },
+ "option-data": [
+ {
+ "name": "unicast",
+ "data": "2001:db8::1"
+ } ],
+ ...
+ }
+
+
+This configuration will cause the server to listen on ``eth1`` on the
+link-local address, the multicast group (ff02::1:2), and 2001:db8::1.
+
+Usually, unicast support is associated with a server unicast option which
+allows clients to send unicast messages to the server. The example above
+includes a server unicast option specification which causes the
+client to send messages to the specified unicast address.
+
+It is possible to mix interface names, wildcards, and interface
+names/addresses in the list of interfaces. It is not possible, however,
+to specify more than one unicast address on a given interface.
+
+Care should be taken to specify proper unicast addresses, as the server
+will attempt to bind to the addresses specified without any additional
+checks. This approach was selected intentionally, to allow the software to
+communicate over uncommon addresses if so desired.
+
+.. _dhcp6-address-config:
+
+Configuration of IPv6 Address Pools
+-----------------------------------
+
+The main role of a DHCPv6 server is address assignment. For this, the
+server must be configured with at least one subnet and one pool of
+dynamic addresses to be managed. For example, assume that the server is
+connected to a network segment that uses the 2001:db8:1::/64 prefix. The
+administrator of that network decides that addresses from the range
+2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the DHCPv6
+server. Such a configuration can be achieved in the following way:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::ffff"
+ }
+ ],
+ ...
+ }
+ ]
+ }
+
+Note that ``subnet`` is defined as a simple string, but the ``pools``
+parameter is actually a list of pools; for this reason, the pool
+definition is enclosed in square brackets, even though only one range of
+addresses is specified.
+
+Each ``pool`` is a structure that contains the parameters that describe
+a single pool. Currently there is only one parameter, ``pool``, which
+gives the range of addresses in the pool.
+
+It is possible to define more than one pool in a subnet; continuing the
+previous example, further assume that 2001:db8:1:0:5::/80 should also be
+managed by the server. It could be written as 2001:db8:1:0:5:: to
+2001:db8:1::5:ffff:ffff:ffff, but typing so many ``f`` characters is cumbersome.
+The pool can be expressed more simply as 2001:db8:1:0:5::/80. Both formats are
+supported by ``Dhcp6`` and they can be mixed in the pool list. For example,
+the following pools could be defined:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ { "pool": "2001:db8:1::1-2001:db8:1::ffff" },
+ { "pool": "2001:db8:1:05::/80" }
+ ],
+ ...
+ }
+ ]
+ }
+
+White space in pool definitions is ignored, so spaces before and after
+the hyphen are optional. They can be used to improve readability.
+
+The number of pools is not limited, but for performance reasons it is
+recommended to use as few as possible.
+
+The server may be configured to serve more than one subnet. To add a
+second subnet, use a command similar to the following:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ { "pool": "2001:db8:1::1-2001:db8:1::ffff" }
+ ]
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/64",
+ "pools": [
+ { "pool": "2001:db8:2::/64" }
+ ]
+ },
+ ...
+ ]
+ }
+
+In this example, we allow the server to dynamically assign all addresses
+available in the whole subnet. Although rather wasteful, it is certainly
+a valid configuration to dedicate the whole /64 subnet for that purpose.
+Note that the Kea server does not preallocate the leases, so there is no
+danger in using gigantic address pools.
+
+When configuring a DHCPv6 server using prefix/length notation, please
+pay attention to the boundary values. When specifying that the server
+can use a given pool, it is also able to allocate the first
+(typically a network address) address from that pool. For example, for
+pool 2001:db8:2::/64, the 2001:db8:2:: address may be assigned as well.
+To avoid this, use the ``min-max`` notation.
+
+.. _dhcp6-prefix-config:
+
+Subnet and Prefix Delegation Pools
+----------------------------------
+
+Subnets may also be configured to delegate prefixes, as defined in `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__, section 6.3. A subnet may
+have one or more prefix delegation pools. Each pool has a prefixed
+address, which is specified as a prefix (``prefix``) and a prefix length
+(``prefix-len``), as well as a delegated prefix length
+(``delegated-len``). The delegated length must not be shorter than
+(i.e. it must be numerically greater than or equal to) the prefix length.
+If both the delegated and prefix lengths are equal, the server will be
+able to delegate only one prefix. The delegated prefix does not have to
+match the subnet prefix.
+
+Below is a sample subnet configuration which enables prefix delegation
+for the subnet:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:d8b:1::/64",
+ "pd-pools": [
+ {
+ "prefix": "3000:1::",
+ "prefix-len": 64,
+ "delegated-len": 96
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+.. _pd-exclude-option:
+
+Prefix Exclude Option
+---------------------
+
+For each delegated prefix, the delegating router may choose to exclude a
+single prefix out of the delegated prefix as specified in `RFC
+6603 <https://tools.ietf.org/html/rfc6603>`__. The requesting router must
+not assign the excluded prefix to any of its downstream interfaces.
+The excluded prefix is intended to be used on a link through which the delegating router
+exchanges DHCPv6 messages with the requesting router. The configuration
+example below demonstrates how to specify an excluded prefix within a
+prefix pool definition. The excluded prefix
+``2001:db8:1:8000:cafe:80::/72`` will be sent to a requesting router which
+includes the Prefix Exclude option in the Option Request option (ORO),
+and which is delegated a prefix from this pool.
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pd-pools": [
+ {
+ "prefix": "2001:db8:1:8000::",
+ "prefix-len": 56,
+ "delegated-len": 64,
+ "excluded-prefix": "2001:db8:1:8000:cafe:80::",
+ "excluded-prefix-len": 72
+ }
+ ]
+ }
+ ]
+ }
+
+.. note::
+
+ Here are some liberties and limits to the values that subnets and pools can
+ take in Kea configurations that are out of the ordinary:
+
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Kea configuration case | Allowed | Comment |
+ +===============================================================================+=========+====================================================================================+
+ | Overlapping subnets | Yes | Administrator consideration needs to be given to how clients are matched to |
+ | | | these subnets. |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Overlapping address pools in one subnet | No | Startup error: DHCP6_PARSER_FAIL |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Overlapping address pools in different subnets | Yes | Specifying the same address pool in different subnets can be used as an equivalent |
+ | | | of the global address pool. In that case, the server can assign addresses from the |
+ | | | same range regardless of the client's subnet. If an address from such a pool is |
+ | | | assigned to a client in one subnet, the same address will be renewed for this |
+ | | | client if it moves to another subnet. Another client in a different subnet will |
+ | | | not be assigned an address already assigned to the client in any of the subnets. |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Address pools that are outside the subnet they are configured under | No | Startup error: DHCP6_PARSER_FAIL |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Overlapping prefix delegation pools in one subnet | No | Startup error: DHCP6_PARSER_FAIL |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Overlapping prefix delegation pools in different subnets | Yes | Specifying the same prefix delegation pool in different subnets can be used as an |
+ | | | equivalent of the global pool. In that case, the server can delegate the same |
+ | | | prefixes regardless of the client's subnet. If a prefix from such a pool is |
+ | | | delegated to a client in one subnet, the same prefix will be renewed for this |
+ | | | client if it moves to another subnet. Another client in a different subnet will |
+ | | | not be delegated a prefix already delegated to the client in any of the subnets. |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+ | Prefix delegation pools not matching the subnet prefix | Yes | It is common in many deployments to configure the prefix delegation pools not |
+ | | | matching the subnet prefix, e.g. a prefix pool of 3000::/96 within the |
+ | | | 2001:db8:1::/64 subnet. Such use cases are supported by the Kea DHCPv6 server. |
+ +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+
+
+.. _dhcp6-std-options:
+
+Standard DHCPv6 Options
+-----------------------
+
+One of the major features of the DHCPv6 server is the ability to provide
+configuration options to clients. Although there are several options
+that require special behavior, most options are sent by the server only
+if the client explicitly requests them. The following example shows how
+to configure the addresses of DNS servers, one of the most frequently used options.
+Options specified in this way are considered global and apply to all configured subnets.
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8::cafe, 2001:db8::babe"
+ },
+ ...
+ ]
+ }
+
+The ``option-data`` line creates a new entry in the option-data table.
+This table contains information on all global options that the server is
+supposed to configure in all subnets. The ``name`` line specifies the
+option name. (For a complete list of currently supported names, see
+:ref:`dhcp6-std-options-list`.) The next line specifies the
+option code, which must match one of the values from that list. The line
+beginning with ``space`` specifies the option space, which must always
+be set to ``dhcp6`` as these are standard DHCPv6 options. For other name
+spaces, including custom option spaces, see :ref:`dhcp6-option-spaces`. The following line
+specifies the format in which the data will be entered; use of CSV
+(comma-separated values) is recommended. Finally, the ``data`` line
+gives the actual value to be sent to clients. The data parameter is specified as
+normal text, with values separated by commas if more than one value is
+allowed.
+
+Options can also be configured as hexadecimal values. If ``csv-format`` is
+set to ``false``, the option data must be specified as a hexadecimal string.
+The following commands configure the ``dns-servers`` option for all subnets
+with the addresses 2001:db8:1::cafe and 2001:db8:1::babe.
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": false,
+ "data": "20 01 0D B8 00 01 00 00 00 00 00 00 00 00 CA FE \
+ 20 01 0D B8 00 01 00 00 00 00 00 00 00 00 BA BE"
+ },
+ ...
+ ]
+ }
+
+.. note::
+
+ The value for the setting of the ``data`` element is split across two
+ lines in this example for clarity; when entering the command, the
+ whole string should be entered on the same line.
+
+Kea supports the following formats when specifying hexadecimal data:
+
+- ``Delimited octets`` - one or more octets separated by either colons or
+ spaces (":" or " "). While each octet may contain one or two digits,
+ we strongly recommend always using two digits. Valid examples are
+ "ab:cd:ef" and "ab cd ef".
+
+- ``String of digits`` - a continuous string of hexadecimal digits with
+ or without a "0x" prefix. Valid examples are "0xabcdef" and "abcdef".
+
+Care should be taken to use proper encoding when using hexadecimal
+format; Kea's ability to validate data correctness in hexadecimal is
+limited.
+
+It is also possible to specify data for binary options as
+a single-quoted text string within double quotes, as shown (note that
+``csv-format`` must be set to ``false``):
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "subscriber-id",
+ "code": 38,
+ "space": "dhcp6",
+ "csv-format": false,
+ "data": "'convert this text to binary'"
+ },
+ ...
+ ],
+ ...
+ }
+
+Most of the parameters in the ``option-data`` structure are optional and
+can be omitted in some circumstances, as discussed in :ref:`dhcp6-option-data-defaults`.
+Only one of ``name`` or ``code``
+is required; it is not necessary to specify both. Space has a default value
+of ``dhcp6``, so this can be skipped as well if a regular (not
+encapsulated) DHCPv6 option is defined. Finally, ``csv-format`` defaults to ``true``, so it
+too can be skipped, unless the option value is specified as
+hexstring. Therefore, the above example can be simplified to:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::cafe, 2001:db8::babe"
+ },
+ ...
+ ]
+ }
+
+
+Defined options are added to the response when the client requests them,
+as well as any options required by a protocol. An administrator can also
+specify that an option is always sent, even if a client did not
+specifically request it. To enforce the addition of a particular option,
+set the ``always-send`` flag to ``true``, as in:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::cafe, 2001:db8::babe",
+ "always-send": true
+ },
+ ...
+ ]
+ }
+
+
+The effect is the same as if the client added the option code in the
+Option Request Option (or its equivalent for vendor options), as in:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::cafe, 2001:db8::babe",
+ "always-send": true
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::cafe, 2001:db8:1::babe"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+
+In the example above, the ``dns-servers`` option respects the global
+``always-send`` flag and is always added to responses, but for subnet
+``2001:db8:1::/64``, the value is taken from the subnet-level option data
+specification.
+
+Contrary to ``always-send``, if the ``never-send`` flag is set to
+``true`` for a particular option, the server does not add it to the response.
+The effect is the same as if the client removed the option code in the
+Option Request Option (or its equivalent for vendor options):
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::cafe, 2001:db8::babe"
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "never-send": true
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+In the example above, the ``dns-server`` option is never added to responses
+on subnet ``2001:db8:1::/64``. ``never-send`` has precedence over
+``always-send``, so if both are ``true`` the option is not added.
+
+.. note::
+
+ The ``always-send`` and ``never-send`` flags are sticky, meaning
+ they do not follow the usual configuration inheritance rules.
+ Instead, if they are enabled at least once along the configuration
+ inheritance chain, they are applied - even if they are
+ disabled in other places which would normally receive a higher priority.
+ For instance, if one of the flags is enabled in the global scope,
+ but disabled at the subnet level, it is enabled,
+ disregarding the subnet-level setting.
+
+.. note::
+
+ The ``never-send`` flag is less powerful than :ischooklib:`libdhcp_flex_option.so`;
+ for instance, it has no effect on options managed by the server itself.
+ Both ``always-send`` and ``never-send`` have no effect on options
+ which cannot be requested, for instance from a custom space.
+
+It is possible to override options on a per-subnet basis. If clients
+connected to most subnets are expected to get the same values of
+a given option, administrators should use global options; it is possible to override
+specific values for a small number of subnets. On the other hand, if
+different values are used in each subnet, it does not make sense to specify
+global option values; rather, only subnet-specific ones should be set.
+
+The following commands override the global ``dns-servers`` option for a
+particular subnet, setting a single DNS server with address
+2001:db8:1::3.
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:1::3"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+In some cases it is useful to associate some options with an address or
+prefix pool from which a client is assigned a lease. Pool-specific
+option values override subnet-specific and global option values. If the
+client is assigned multiple leases from different pools, the server
+assigns options from all pools from which the leases have been obtained.
+However, if the particular option is specified in multiple pools from
+which the client obtains the leases, only one instance of this option
+is handed out to the client. The server's administrator must not
+try to prioritize assignment of pool-specific options by trying to order
+pool declarations in the server configuration.
+
+The following configuration snippet demonstrates how to specify the
+``dns-servers`` option, which will be assigned to a client only if the client
+obtains an address from the given pool:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "pools": [
+ {
+ "pool": "2001:db8:1::100-2001:db8:1::300",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::10"
+ }
+ ]
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ }
+
+Options can also be specified in class or host-reservation scope. The
+current Kea options precedence order is (from most important to least): host
+reservation, pool, subnet, shared network, class, global.
+
+When a data field is a string and that string contains the comma (``,``;
+U+002C) character, the comma must be escaped with two backslashes (``\\,``;
+U+005C). This double escape is required because both the routine
+splitting of CSV data into fields and JSON use the same escape character; a
+single escape (``\,``) would make the JSON invalid. For example, the string
+"EST5EDT4,M3.2.0/02:00,M11.1.0/02:00" must be represented as:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "pools": [
+ {
+ "option-data": [
+ {
+ "name": "new-posix-timezone",
+ "data": "EST5EDT4\\,M3.2.0/02:00\\,M11.1.0/02:00"
+ }
+ ]
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Some options are designated as arrays, which means that more than one
+value is allowed. For example, the option ``dns-servers``
+allows the specification of more than one IPv6 address, enabling clients
+to obtain the addresses of multiple DNS servers.
+
+:ref:`dhcp6-custom-options` describes the
+configuration syntax to create custom option definitions (formats).
+Creation of custom definitions for standard options is generally not
+permitted, even if the definition being created matches the actual
+option format defined in the RFCs. However, there is an exception to this rule
+for standard options for which Kea currently does not provide a
+definition. To use such options, a server administrator must
+create a definition as described in :ref:`dhcp6-custom-options` in the ``dhcp6`` option space. This
+definition should match the option format described in the relevant RFC,
+but the configuration mechanism allows any option format as there is
+currently no way to validate it.
+
+The currently supported standard DHCPv6 options are listed in
+the table below. "Name" and "Code" are the
+values that should be used as a name/code in the option-data structures.
+"Type" designates the format of the data; the meanings of the various
+types are given in :ref:`dhcp-types`.
+
+.. _dhcp6-std-options-list:
+
+.. table:: List of standard DHCPv6 options configurable by an administrator
+
+ +--------------------------+-----------------+-----------------+-----------------+
+ | Name | Code | Type | Array? |
+ +==========================+=================+=================+=================+
+ | preference | 7 | uint8 | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | unicast | 12 | ipv6-address | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | sip-server-dns | 21 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | sip-server-addr | 22 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | dns-servers | 23 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | domain-search | 24 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | nis-servers | 27 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | nisp-servers | 28 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | nis-domain-name | 29 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | nisp-domain-name | 30 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | sntp-servers | 31 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | information-refresh-time | 32 | uint32 | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | bcmcs-server-dns | 33 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | bcmcs-server-addr | 34 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | geoconf-civic | 36 | record (uint8, | false |
+ | | | uint16, binary) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | remote-id | 37 | record (uint32, | false |
+ | | | binary) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | subscriber-id | 38 | binary | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | client-fqdn | 39 | record (uint8, | false |
+ | | | fqdn) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | pana-agent | 40 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | new-posix-timezone | 41 | string | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | new-tzdb-timezone | 42 | string | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | ero | 43 | uint16 | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | lq-query (1) | 44 | record (uint8, | false |
+ | | | ipv6-address) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | client-data (1) | 45 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | clt-time (1) | 46 | uint32 | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | lq-relay-data (1) | 47 | record | false |
+ | | | (ipv6-address, | |
+ | | | binary) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | lq-client-link (1) | 48 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | v6-lost | 51 | fqdn | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | capwap-ac-v6 | 52 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | relay-id | 53 | binary | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | v6-access-domain | 57 | fqdn | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | sip-ua-cs-list | 58 | fqdn | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | bootfile-url | 59 | string | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | bootfile-param | 60 | tuple | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | client-arch-type | 61 | uint16 | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | nii | 62 | record (uint8, | false |
+ | | | uint8, uint8) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | aftr-name | 64 | fqdn | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | erp-local-domain-name | 65 | fqdn | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | rsoo | 66 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | pd-exclude | 67 | binary | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | rdnss-selection | 74 | record | true |
+ | | | (ipv6-address, | |
+ | | | uint8, fqdn) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | client-linklayer-addr | 79 | binary | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | link-address | 80 | ipv6-address | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | solmax-rt | 82 | uint32 | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | inf-max-rt | 83 | uint32 | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | dhcp4o6-server-addr | 88 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-rule | 89 | record (uint8, | false |
+ | | | uint8, uint8, | |
+ | | | ipv4-address, | |
+ | | | ipv6-prefix) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-br | 90 | ipv6-address | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-dmr | 91 | ipv6-prefix | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-v4v6bind | 92 | record | false |
+ | | | (ipv4-address, | |
+ | | | ipv6-prefix) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-portparams | 93 | record(uint8, | false |
+ | | | psid) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-cont-mape | 94 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-cont-mapt | 95 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | s46-cont-lw | 96 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | v6-captive-portal | 103 | string | false |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | v6-sztp-redirect | 136 | tuple | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | ipv6-address-andsf | 143 | ipv6-address | true |
+ +--------------------------+-----------------+-----------------+-----------------+
+ | v6-dnr | 144 | record (uint16, | false |
+ | | | uint16, fqdn, | |
+ | | | binary) | |
+ +--------------------------+-----------------+-----------------+-----------------+
+
+Options marked with (1) have option definitions, but the logic behind
+them is not implemented. That means that, technically, Kea knows how to
+parse them in incoming messages or how to send them if configured to do
+so, but not what to do with them. Since the related RFCs require certain
+processing, the support for those options is non-functional. However, it
+may be useful in some limited lab testing; hence the definition formats
+are listed here.
+
+Some options are more complex to configure than others. In particular, the Softwire46 family of options
+and DNR are discussed in separate sections below.
+
+Kea supports more options than those listed above. The following list is mostly useful for readers who
+want to understand whether Kea is able to support certain options. The following options are
+returned by the Kea engine itself and in general should not be configured manually.
+
+.. table:: List of standard DHCPv6 options managed by Kea on its own and not directly configurable by an administrator
+
+ +--------------+------+------------------------------------------------------------------------+
+ | Name | Code | Description |
+ +==============+======+========================================================================+
+ | client-id | 1 | Sent by the client; Kea uses it to distinguish between clients. |
+ +--------------+------+------------------------------------------------------------------------+
+ | server-id | 2 | Sent by clients to request action from a specific server and by the |
+ | | | server to identify itself. See :ref:`dhcp6-serverid` for details. |
+ +--------------+------+------------------------------------------------------------------------+
+ | ia-na | 3 | A container option that conveys IPv6 addresses (``iaddr`` options). Kea|
+ | | | receives and sends those options using its allocation engine. |
+ +--------------+------+------------------------------------------------------------------------+
+ | ia-ta | 4 | Conveys temporary addresses. Deprecated feature, not supported. |
+ +--------------+------+------------------------------------------------------------------------+
+ | iaaddr | 5 | Conveys addresses with lifetimes in ``ia-na`` and ``ia-ta`` options. |
+ +--------------+------+------------------------------------------------------------------------+
+ | oro | 6 | ORO (or Option Request Option) is used by clients to request a list |
+ | | | of options they are interested in. Kea supports it and sends the |
+ | | | requested options back if configured with required options. |
+ +--------------+------+------------------------------------------------------------------------+
+ | elapsed-time | 8 | Sent by clients to identify how long they have been trying to obtain a |
+ | | | configuration. Kea uses high values sent by clients as an indicator |
+ | | | that something is wrong; this is one of the aspects used in HA to |
+ | | | determine if the partner is healthy or not. |
+ +--------------+------+------------------------------------------------------------------------+
+ | relay-msg | 9 | Used by relays to encapsulate the original client message. Kea uses it |
+ | | | when sending back relayed responses to the relay agent. |
+ +--------------+------+------------------------------------------------------------------------+
+ | auth | 11 | Used to pass authentication information between clients and server. The|
+ | | | support for this option is very limited. |
+ +--------------+------+------------------------------------------------------------------------+
+ | status-code | 13 | An option that the server can attach in case of various failures, such |
+ | | | as running out of addresses or not being configured to assign prefixes.|
+ +--------------+------+------------------------------------------------------------------------+
+ | rapid-commit | 14 | Used to signal the client's willingness to support ``rapid-commit`` and|
+ | | | the server's acceptance for this configuration. See |
+ | | | :ref:`dhcp6-rapid-commit` for details. |
+ +--------------+------+------------------------------------------------------------------------+
+ | user-class | 15 | Sent by the client to self-identify the device type. Kea |
+ | | | can use this for client classification. |
+ +--------------+------+------------------------------------------------------------------------+
+ | vendor-class | 16 | Similar to ``user-class``, but vendor-specific. |
+ +--------------+------+------------------------------------------------------------------------+
+ | vendor-opts | 17 | A vendor-specific container that is used by both the client and the |
+ | | | server to exchange vendor-specific options. The logic behind those |
+ | | | options varies between vendors. Vendor options are explained in |
+ | | | :ref:`dhcp6-vendor-opts`. |
+ +--------------+------+------------------------------------------------------------------------+
+ | interface-id | 18 | May be inserted by the relay agent to identify the interface that the |
+ | | | original client message was received on. Kea may be told to use this |
+ | | | information to select specific subnets. Also, if specified, Kea |
+ | | | echoes this option back, so the relay will know which interface to use |
+ | | | to reach the client. |
+ +--------------+------+------------------------------------------------------------------------+
+ | ia-pd | 25 | A container for conveying Prefix Delegations (PDs)) that are being |
+ | | | delegated to clients. See :ref:`dhcp6-prefix-config` for details. |
+ +--------------+------+------------------------------------------------------------------------+
+ | iaprefix | 26 | Conveys the IPv6 prefix in the ``ia-pd`` option. See |
+ | | | :ref:`dhcp6-prefix-config` for details. |
+ +--------------+------+------------------------------------------------------------------------+
+
+.. _s46-options:
+
+Common Softwire46 Options
+-------------------------
+
+Softwire46 options are involved in IPv4-over-IPv6 provisioning by means
+of tunneling or translation, as specified in `RFC
+7598 <https://tools.ietf.org/html/rfc7598>`__. The following sections
+provide configuration examples of these options.
+
+.. _s46-containers:
+
+Softwire46 Container Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Softwire46 (S46) container options group rules and optional port parameters for a
+specified domain. There are three container options specified in the
+"dhcp6" (top-level) option space: the MAP-E Container option, the MAP-T
+Container option, and the S46 Lightweight 4over6 Container option. These
+options only contain the encapsulated options specified below; they do not
+include any data fields.
+
+To configure the server to send a specific container option along with
+all encapsulated options, the container option must be included in the
+server configuration as shown below:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "s46-cont-mape"
+ } ],
+ ...
+ }
+
+This configuration will cause the server to include the MAP-E Container
+option to the client. Use ``s46-cont-mapt`` or ``s46-cont-lw`` for the MAP-T
+Container and S46 Lightweight 4over6 Container options, respectively.
+
+All remaining Softwire46 options described below are included in one of
+the container options. Thus, they must be included in appropriate
+option spaces by selecting a ``space`` name, which specifies the
+option where they are supposed to be included.
+
+S46 Rule Option
+~~~~~~~~~~~~~~~
+
+The S46 Rule option is used to convey the Basic Mapping Rule (BMR)
+and Forwarding Mapping Rule (FMR).
+
+::
+
+ {
+ "space": "s46-cont-mape-options",
+ "name": "s46-rule",
+ "data": "128, 0, 24, 192.0.2.0, 2001:db8:1::/64"
+ }
+
+Another possible ``space`` value is ``s46-cont-mapt-options``.
+
+The S46 Rule option conveys a number of parameters:
+
+- ``flags`` - an unsigned 8-bit integer, with currently only the
+ most-significant bit specified. It denotes whether the rule can be
+ used for forwarding (128) or not (0).
+
+- ``ea-len`` - an 8-bit-long Embedded Address length. Allowed values
+ range from 0 to 48.
+
+- ``IPv4 prefix length`` - an 8-bit-long expression of the prefix length of
+ the Rule IPv4 prefix specified in the ``ipv4-prefix`` field. Allowed
+ values range from 0 to 32.
+
+- ``IPv4 prefix`` - a fixed-length 32-bit field that specifies the IPv4
+ prefix for the S46 rule. The bits in the prefix after
+ a specific number of bits (defined in ``prefix4-len``) are reserved, and MUST
+ be initialized to zero by the sender and ignored by the receiver.
+
+- ``IPv6 prefix`` - a field in prefix/length notation that specifies the IPv6
+ domain prefix for the S46 rule. The field is padded on the right with
+ zero bits up to the nearest octet boundary, when ``prefix6-len`` is not
+ evenly divisible by 8.
+
+S46 BR Option
+~~~~~~~~~~~~~
+
+The S46 BR option is used to convey the IPv6 address of the Border
+Relay. This option is mandatory in the MAP-E Container option and is not
+permitted in the MAP-T and S46 Lightweight 4over6 Container options.
+
+.. code-block:: json
+
+ {
+ "space": "s46-cont-mape-options",
+ "name": "s46-br",
+ "data": "2001:db8:cafe::1"
+ }
+
+Another possible ``space`` value is ``s46-cont-lw-options``.
+
+S46 DMR Option
+~~~~~~~~~~~~~~
+
+The S46 DMR option is used to convey values for the Default Mapping Rule
+(DMR). This option is mandatory in the MAP-T container option and is not
+permitted in the MAP-E and S46 Lightweight 4over6 Container options.
+
+.. code-block:: json
+
+ {
+ "space": "s46-cont-mapt-options",
+ "name": "s46-dmr",
+ "data": "2001:db8:cafe::/64"
+ }
+
+This option must not be included in other containers.
+
+S46 IPv4/IPv6 Address Binding Option
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The S46 IPv4/IPv6 Address Binding option may be used to specify the full
+or shared IPv4 address of the Customer Edge (CE). The IPv6 prefix field
+is used by the CE to identify the correct prefix to use for the tunnel
+source.
+
+::
+
+ {
+ "space": "s46-cont-lw",
+ "name": "s46-v4v6bind",
+ "data": "192.0.2.3, 2001:db8:1:cafe::/64"
+ }
+
+This option must not be included in other containers.
+
+S46 Port Parameters
+~~~~~~~~~~~~~~~~~~~
+
+The S46 Port Parameters option specifies optional port-set information
+that may be provided to CEs.
+
+.. code-block:: json
+
+ {
+ "space": "s46-rule-options",
+ "name": "s46-portparams",
+ "data": "2, 3/4"
+ }
+
+Another possible ``space`` value is ``s46-v4v6bind``, to include this option
+in the S46 IPv4/IPv6 Address Binding option.
+
+Note that the second value in the example above specifies the PSID and
+PSID-length fields in the format of PSID/PSID length. This is equivalent
+to the values of ``PSID-len=4`` and ``PSID=12288`` conveyed in the S46 Port
+Parameters option.
+
+.. _dnr6-options:
+
+DNR (Discovery of Network-designated Resolvers) Options for DHCPv6
+------------------------------------------------------------------
+
+One of the more recently added options is the Discovery of
+Network-designated Resolvers or DNR option,
+introduced in `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463>`__. The goal of that RFC is
+to provide a way to communicate location of DNS resolvers available over means other than
+the classic DNS over UDP port 53. At the time of this writing, the supported technologies
+are DoT (DNS-over-TLS), DoH (DNS-over-HTTPS), and DoQ (DNS-over-QUIC), but the option was
+designed to be extensible to accommodate other protocols in the future.
+
+DNR option may be configured using convenient notation. Comma delimited fields must be provided in the following order:
+
+- Service Priority (mandatory),
+- ADN FQDN (mandatory),
+- IP address(es) (optional - if more than one - they must be space-separated)
+- SvcParams as a set of key=value pairs (optional - if more than one - they must be space-separated;
+ to provide more than one alpn-id separate them with double backslash escaped comma like in the
+ example below).
+
+Let's imagine an example that we want to convey a DoT server operating at ``dot1.example.org``
+(which resolves to two IPv6 addresses: ``2001:db8::1`` and ``2001:db8::2``) on a non-standard port 8530.
+An example option that would convey this information looks as follows:
+
+::
+
+ {
+ "name": "v6-dnr", // name of the option
+
+ // The following fields should be specified:
+ // - service priority (unsigned 16 bit integer)
+ // - authentication-domain-name (fqdn of the encrypted resolver)
+ // - a list of one or more IPv6 addresses
+ // - list of parameters in key=value format, space separated; any comma
+ // characters in this field must be escaped with double backslash
+ "data": "100, dot1.example.org., 2001:db8::1 2001:db8::2, alpn=dot port=8530"
+ }
+
+The above option will be encoded on-wire as follows:
+
+::
+
+ 00 64 - service priority (100 in hex as unsigned 16 bit integer)
+ 00 12 - length of the Authentication Domain Name (name of the resolver) FQDN (18 in hex as unsigned 16 bit integer)
+ 04 64 6f 74 31 07 65 78 61 6d 70 6c 65 03 6f 72 67 00 - 18 octets of the ADN FQDN
+ 00 20 - 32 octets is the length of the following two IPv6 addresses
+ 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01 - 2001:db8::1
+ 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 02 - 2001:db8::2
+ 00 01 - SvsParams begin - this is alpn SvcParamKey
+ 00 04 - length of the alpn SvcParamValue field (4 octets)
+ 03 - length of the following alpn-id coded on one octet
+ 64 6f 74 - "dot" - value of the alpn
+ 00 03 - this is port SvcParamKey
+ 00 02 - length of the SvcParamValue field is 2 octets
+ 21 52 - the actual value is 0x2152 or 8530 in decimal
+
+The following example shows how to configure more than one ``ALPN`` protocol in Service Parameters.
+The example specifies a resolver known as ``resolver.example`` that supports:
+
+- DoT on default port 853
+- DoQ on default port 853
+- DoH at ``https://resolver.example/q{?dns}``
+
+::
+
+ {
+ "name": "v6-dnr", // name of the option
+
+ // Note the double backslash escaped commas in alpn-id list.
+ "data": "150, resolver.example., 2001:db8::1 2001:db8::2, alpn=dot\\,doq\\,h2\\,h3 dohpath=/q{?dns}"
+ }
+
+The above option will be encoded on-wire as follows:
+
+::
+
+ 00 96 - service priority (150 in hex as unsigned 16 bit integer)
+ 00 12 - length of the Authentication Domain Name (name of the resolver) FQDN (18 in hex as unsigned 16 bit integer)
+ 08 72 65 73 6f 6c 76 65 72 07 65 78 61 6d 70 6c 65 00 - 18 octets of the ADN FQDN
+ 00 20 - 32 octets is the length of the following two IPv6 addresses
+ 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01 - 2001:db8::1
+ 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 02 - 2001:db8::2
+ 00 01 - SvsParams begin - this is alpn SvcParamKey
+ 00 0e - length of the alpn SvcParamValue field (14 octets)
+ 03 - length of the following alpn-id coded on one octet
+ 64 6f 74 - "dot" - value of the alpn
+ 03 - length of the following alpn-id coded on one octet
+ 64 6f 71 - "doq" - value of the alpn
+ 02 - length of the following alpn-id coded on one octet
+ 68 32 - "h2" - value of the alpn "HTTP/2 over TLS"
+ 02 - length of the following alpn-id coded on one octet
+ 68 33 - "h3" - value of the alpn "HTTP/3"
+ 00 07 - this is dohpath SvcParamKey
+ 00 08 - length of the SvcParamValue field is 8 octets
+ 2f 71 7b 3f 64 6e 73 7d - "/q{?dns}" dohpath
+
+
+.. note::
+
+ Note that whenever "comma" characters need to be used not as the delimiters, they must be escaped with
+ double backslash (``\\,``). E.g. one must use escaped commas when configuring more than one ``ALPN``
+ protocol to separate them.
+
+The `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463#name-option-format>`__ Section 4.1 is encouraging to include
+at least the ``ALPN`` (Application-Layer Protocol Negotiation) SvcParam, as it will be required in most cases.
+It defines the protocol how the encrypted resolver could be reached. The most common values are
+``dot``, ``doq``, ``h2`` (meaning HTTP/2.0 over TLS, used in DoH).
+
+As per `RFC 9461 <https://www.rfc-editor.org/rfc/rfc9461.html#name-new-svcparamkey-dohpath>`__ Section 5:
+
+If the ``alpn`` SvcParam indicates support for HTTP, ``dohpath`` MUST be present. The URI Template MUST contain
+a "dns" variable. For example, when advertising DoH resolver available at
+``https://doh1.example.org/query{?dns}``, the ``dohpath`` should be set to relative URI ``/query{?dns}``.
+
+A reader interested in configuring this option is encouraged to read the following materials:
+
+- A very nice set of examples is available in Section 7 of `RFC 9461
+ <https://www.rfc-editor.org/rfc/rfc9461#name-examples>`__.
+- List of all currently defined service parameters is maintained on `IANA registry
+ <https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml>`__. This specifies records that can be
+ stored in the svcParams field of the DNR option.
+- List of currently allowed protocols in the ALPN parameter is maintained on `another IANA registry
+ <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>`__.
+
+- `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463>`__ which provides option definitions. In terms of SvcParams, it states
+ that at `alpn` and `port` must be supported, and `dohpath` (used for DoH) is recommended to be supported.
+- Section 2.2 of `RFC 9460 <https://www.rfc-editor.org/rfc/rfc9460>`__, which defines the on-wire format for SvcParams.
+- Sections 7.1, 7.2 of `RFC 9460 <https://www.rfc-editor.org/rfc/rfc9460>`__, which defines the on-wire format for alpn and port.
+- Section 5 of `RFC 9461 <https://www.rfc-editor.org/rfc/rfc9461#name-new-svcparamkey-dohpath>`__, which defines
+ on-wire format for `dohpath`.
+
+Kea currently supports the following service parameters:
+
+ +-----------------+------+------------------------------------------------------------------------+
+ | Name | Code | Description |
+ +=================+======+========================================================================+
+ | alpn | 1 | Specifies comma separated protocol types (DoT, DoH, etc.) |
+ +-----------------+------+------------------------------------------------------------------------+
+ | port | 3 | Unsigned 16 bit integer. Indicated non-standard TCP or UDP port. |
+ +-----------------+------+------------------------------------------------------------------------+
+ | dohpath | 7 | Mandatory for DoH. Contains URL path for the DoT resolver. |
+ +-----------------+------+------------------------------------------------------------------------+
+
+Other currently defined service parameters: mandatory (0), no-default-alpn (2), ipv4hint (4), ech (5),
+ipv6hint (6), and ohttp (8) are not usable in the DNR option.
+
+Further examples are provided in Kea sources in ``all-options.json`` file
+in the ``doc/examples/kea6`` directory. The DHCPv4 option is almost equivalent, and is described
+in :ref:`dnr4-options`.
+
+
+.. _dhcp6-custom-options:
+
+Custom DHCPv6 Options
+---------------------
+
+Kea supports custom (non-standard) DHCPv6 options.
+Let's say that we want to define a new DHCPv6 option called ``foo``, which
+will have code 100 and will convey a single, unsigned, 32-bit
+integer value. Such an option can be defined by putting the following entry
+in the configuration file:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "foo",
+ "code": 100,
+ "type": "uint32",
+ "array": false,
+ "record-types": "",
+ "space": "dhcp6",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The ``false`` value of the ``array`` parameter determines that the option
+does NOT comprise an array of ``uint32`` values but is, instead, a single
+value. Two other parameters have been left blank: ``record-types`` and
+``encapsulate``. The former specifies the comma-separated list of option
+data fields, if the option comprises a record of data fields. The
+``record-types`` value should be non-empty if ``type`` is set to
+``record``; otherwise it must be left blank. The latter parameter
+specifies the name of the option space being encapsulated by the
+particular option. If the particular option does not encapsulate any
+option space, the parameter should be left blank. Note that the ``option-def``
+configuration statement only defines the format of an option and does
+not set its value(s).
+
+The ``name``, ``code``, and ``type`` parameters are required; all others
+are optional. The ``array`` parameter default value is ``false``. The
+``record-types`` and ``encapsulate`` parameters default values are blank
+(``""``). The default ``space`` is ``dhcp6``.
+
+Once the new option format is defined, its value is set in the same way
+as for a standard option. For example, the following commands set a
+global value that applies to all subnets.
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "foo",
+ "code": 100,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "12345"
+ },
+ ...
+ ],
+ ...
+ }
+
+New options can take more complex forms than the simple use of primitives
+(uint8, string, ipv6-address, etc.); it is possible to define an option
+comprising a number of existing primitives.
+
+For example, say we want to define a new option that will consist of
+an IPv6 address, followed by an unsigned 16-bit integer, followed by a
+boolean value, followed by a text string. Such an option could be
+defined in the following way:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "bar",
+ "code": 101,
+ "space": "dhcp6",
+ "type": "record",
+ "array": false,
+ "record-types": "ipv6-address, uint16, boolean, string",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The ``type`` parameter is set to ``"record"`` to indicate that the option
+contains multiple values of different types. These types are given as a
+comma-separated list in the ``record-types`` field and should be ones
+from those listed in :ref:`dhcp-types`.
+
+The values of the options are set in an ``option-data`` statement as
+follows:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "bar",
+ "space": "dhcp6",
+ "code": 101,
+ "csv-format": true,
+ "data": "2001:db8:1::10, 123, false, Hello World"
+ }
+ ],
+ ...
+ }
+
+The ``csv-format`` parameter is set to ``true`` to indicate that the ``data``
+field comprises a comma-separated list of values. The values in ``data`` must
+correspond to the types set in the ``record-types`` field of the option
+definition.
+
+When ``array`` is set to ``true`` and ``type`` is set to ``"record"``, the
+last field is an array, i.e. it can contain more than one value, as in:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "bar",
+ "code": 101,
+ "space": "dhcp6",
+ "type": "record",
+ "array": true,
+ "record-types": "ipv6-address, uint16",
+ "encapsulate": ""
+ },
+ ...
+ ],
+ ...
+ }
+
+The new option content is one IPv6 address followed by one or more 16-bit
+unsigned integers.
+
+.. note::
+
+ In general, boolean values are specified as ``true`` or ``false``,
+ without quotes. Some specific boolean parameters may also accept
+ ``"true"``, ``"false"``, ``0``, ``1``, ``"0"``, and ``"1"``.
+
+.. _dhcp6-vendor-opts:
+
+DHCPv6 Vendor-Specific Options
+------------------------------
+
+Vendor options in DHCPv6 are carried in the Vendor-Specific
+Information option (code 17). The idea behind option 17
+is that each vendor has its own unique set of options with their own custom
+formats. The vendor is identified by a 32-bit unsigned integer called
+``enterprise-number`` or ``vendor-id``.
+
+The standard spaces defined in Kea and their options are:
+
+- ``vendor-2495``: Internet Systems Consortium, Inc. for 4o6 options:
+
++-------------+--------------------+------------------------------------------------------------------------+
+| option code | option name | option description |
++=============+====================+========================================================================+
+| 60000 | 4o6-interface | the name of the 4o6 server's client-facing interface |
++-------------+--------------------+------------------------------------------------------------------------+
+| 60001 | 4o6-source-address | the address that the 4o6 server uses to send packets to the client |
++-------------+--------------------+------------------------------------------------------------------------+
+| 60002 | 4o6-source-port | the port that the 4o6 server opens to send packets to the client |
++-------------+--------------------+------------------------------------------------------------------------+
+
+- ``vendor-4491``: Cable Television Laboratories, Inc. for DOCSIS3 options:
+
++-------------+--------------------+------------------------------------------------------------------------+
+| option code | option name | option description |
++=============+====================+========================================================================+
+| 1 | oro | ORO (or Option Request Option) is used by clients to request a list of |
+| | | options they are interested in. |
++-------------+--------------------+------------------------------------------------------------------------+
+| 2 | tftp-servers | a list of IPv4 addresses of TFTP servers to be used by the cable modem |
++-------------+--------------------+------------------------------------------------------------------------+
+
+The following examples show how to
+define an option ``"foo"`` with code 1 that consists of an IPv6 address,
+an unsigned 16-bit integer, and a string. The ``"foo"`` option is
+conveyed in a Vendor-Specific Information option, which comprises a
+single uint32 value that is set to ``12345``. The sub-option ``"foo"``
+follows the data field holding this value.
+
+The first step is to define the format of the option:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "foo",
+ "code": 1,
+ "space": "vendor-12345",
+ "type": "record",
+ "array": false,
+ "record-types": "ipv6-address, uint16, string",
+ "encapsulate": ""
+ }
+ ],
+ ...
+ }
+
+Note that the option space is set to ``"vendor-12345"``.
+Once the option format is defined, the next step is to define actual values
+for that option:
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "foo",
+ "space": "vendor-12345",
+ "data": "2001:db8:1::10, 123, Hello World"
+ },
+ ...
+ ],
+ ...
+ }
+
+We should also define a value (``"enterprise-number"``) for the
+Vendor-Specific Information option, to convey the option ``foo``.
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "vendor-opts",
+ "data": "12345"
+ },
+ ...
+ ],
+ ...
+ }
+
+Alternatively, the option can be specified using its code.
+
+::
+
+ "Dhcp6": {
+ "option-data": [
+ {
+ "code": 17,
+ "data": "12345"
+ },
+ ...
+ ],
+ ...
+ }
+
+A common configuration is to set the ``always-send`` flag to ``true``, so the
+vendor option is sent even when the client did not specify it in the query.
+
+This is also how :iscman:`kea-dhcp6` can be configured to send multiple vendor options
+from different vendors, along with each of their specific enterprise number.
+If these options need to be sent by the server regardless of whether the client
+specified any enterprise number, ``"always-send": true`` must be configured
+for the suboptions that will be included in the Vendor-Specific Information option (code 17).
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "option-data": [
+ {
+ "always-send": true,
+ "data": "tagged",
+ "name": "tag",
+ "space": "vendor-2234"
+ },
+ {
+ "always-send": true,
+ "data": "https://example.com:1234/path",
+ "name": "url",
+ "space": "vendor-3561"
+ }
+ ],
+ "option-def": [
+ {
+ "code": 22,
+ "name": "tag",
+ "space": "vendor-2234",
+ "type": "string"
+ },
+ {
+ "code": 11,
+ "name": "url",
+ "space": "vendor-3561",
+ "type": "string"
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ The :iscman:`kea-dhcp6` server is able to recognize multiple Vendor Class
+ options (code 16) with different enterprise numbers in the client requests
+ and to send multiple Vendor-Specific Information options (code 17) in the
+ responses, one for each vendor.
+
+.. _dhcp6-option-spaces:
+
+Nested DHCPv6 Options (Custom Option Spaces)
+--------------------------------------------
+
+It is sometimes useful to define a completely new option space, such as
+when a user creates a new option to convey sub-options that
+use a separate numbering scheme, such as sub-options with codes 1
+and 2. Those option codes conflict with standard DHCPv6 options, so a
+separate option space must be defined.
+
+Note that the creation of a new option space is not required when
+defining sub-options for a standard option, because one is created by
+default if the standard option is meant to convey any sub-options (see
+:ref:`dhcp6-vendor-opts`).
+
+If we want a DHCPv6 option called ``container`` with code 102,
+that conveys two sub-options with codes 1 and 2, we first need to
+define the new sub-options:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "subopt1",
+ "code": 1,
+ "space": "isc",
+ "type": "ipv6-address",
+ "record-types": "",
+ "array": false,
+ "encapsulate": ""
+ },
+ {
+ "name": "subopt2",
+ "code": 2,
+ "space": "isc",
+ "type": "string",
+ "record-types": "",
+ "array": false,
+ "encapsulate": ""
+ }
+ ],
+ ...
+ }
+
+Note that we have defined the options to belong to a new option space
+(in this case, ``"isc"``).
+
+The next step is to define a regular DHCPv6 option with the desired code
+and specify that it should include options from the new option space:
+
+::
+
+ "Dhcp6": {
+ "option-def": [
+ {
+ "name": "container",
+ "code": 102,
+ "space": "dhcp6",
+ "type": "empty",
+ "array": false,
+ "record-types": "",
+ "encapsulate": "isc"
+ },
+ ...
+ ],
+ ...
+ }
+
+The name of the option space in which the sub-options are defined is set
+in the ``encapsulate`` field. The ``type`` field is set to ``"empty"``, to
+indicate that this option does not carry any data other than
+sub-options.
+
+Finally, we can set values for the new options:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "option-data": [
+ {
+ "name": "subopt1",
+ "code": 1,
+ "space": "isc",
+ "data": "2001:db8::abcd"
+ },
+ {
+ "name": "subopt2",
+ "code": 2,
+ "space": "isc",
+ "data": "Hello world"
+ },
+ {
+ "name": "container",
+ "code": 102,
+ "space": "dhcp6"
+ }
+ ]
+ }
+ }
+
+It is possible to create an option which carries some data in
+addition to the sub-options defined in the encapsulated option space.
+For example, if the ``container`` option from the previous example were
+required to carry a uint16 value as well as the sub-options, the
+``type`` value would have to be set to ``"uint16"`` in the option
+definition. (Such an option would then have the following data
+structure: DHCP header, uint16 value, sub-options.) The value specified
+with the ``data`` parameter — which should be a valid integer enclosed
+in quotes, e.g. ``"123"`` — would then be assigned to the ``uint16`` field in
+the ``container`` option.
+
+.. _dhcp6-option-data-defaults:
+
+Unspecified Parameters for DHCPv6 Option Configuration
+------------------------------------------------------
+
+In many cases it is not required to specify all parameters for an option
+configuration, and the default values can be used. However, it is
+important to understand the implications of not specifying some of them,
+as it may result in configuration errors. The list below explains the
+behavior of the server when a particular parameter is not explicitly
+specified:
+
+- ``name`` - the server requires either an option name or an option code to
+ identify an option. If this parameter is unspecified, the option code
+ must be specified.
+
+- ``code`` - the server requires either an option name or an option code to
+ identify an option; this parameter may be left unspecified if the
+ ``name`` parameter is specified. However, this also requires that the
+ particular option have a definition (either as a standard option or
+ an administrator-created definition for the option using an
+ ``option-def`` structure), as the option definition associates an
+ option with a particular name. It is possible to configure an option
+ for which there is no definition (unspecified option format).
+ Configuration of such options requires the use of the option code.
+
+- ``space`` - if the option space is unspecified it defaults to
+ ``dhcp6``, which is an option space holding standard DHCPv6 options.
+
+- ``data`` - if the option data is unspecified it defaults to an empty
+ value. The empty value is mostly used for the options which have no
+ payload (boolean options), but it is legal to specify empty values
+ for some options which carry variable-length data and for which the
+ specification allows a length of 0. For such options, the data
+ parameter may be omitted in the configuration.
+
+- ``csv-format`` - if this value is not specified, the server
+ assumes that the option data is specified as a list of comma-separated
+ values to be assigned to individual fields of the DHCP option.
+
+.. _dhcp6-t1-t2-times:
+
+Controlling the Values Sent for T1 and T2 Times
+-----------------------------------------------
+
+According to RFC 8415, section 21.4, the recommended T1 and T2 values
+are 50% and 80% of the preferred
+lease time, respectively. Kea can be configured to send values that are
+specified explicitly or that are calculated as percentages of the
+preferred lease time. The server's behavior is determined by a combination
+of configuration parameters, of which T1 and T2 are only two.
+
+The lease's preferred and valid lifetimes are expressed as triplets with
+minimum, default, and maximum values using configuration entries:
+
+- ``min-preferred-lifetime`` - specifies the minimum preferred lifetime (optional).
+
+- ``preferred-lifetime`` - specifies the default preferred lifetime.
+
+- ``max-preferred-lifetime`` - specifies the maximum preferred lifetime (optional).
+
+- ``min-valid-lifetime`` - specifies the minimum valid lifetime (optional).
+
+- ``valid-lifetime`` - specifies the default valid lifetime.
+
+- ``max-valid-lifetime`` - specifies the maximum valid lifetime (optional).
+
+Since Kea 1.9.11, these values may be specified within client classes.
+
+When the client does not specify lifetimes, the default is used.
+A specified lifetime - using the IAADDR or IAPREFIX sub-option with
+non-zero values - uses these values when they are between the configured
+minimum and maximum bounds. Values outside the bounds are rounded up or down as
+needed.
+
+.. note::
+
+ As of Kea 2.3.8, if the preferred-lifetime has not been explicitly specified
+ or the specified value is larger than the value of valid-lifetime, the server
+ will use the value given by 0.625 * valid-lifetime.
+
+To send specific fixed values, use the following two parameters:
+
+- ``renew-timer`` - specifies the value of T1 in seconds.
+
+- ``rebind-timer`` - specifies the value of T2 in seconds.
+
+Any value greater than or equal to zero may be specified for T2.
+T1, if specified, must be less than T2. This flexibility allows
+a use case where administrators want to suppress client renewals and
+rebinds by deferring them beyond the lifespan of the lease. This should
+cause the lease to expire, rather than get renewed by clients. If T1 is
+specified as larger than T2, T1 is silently set to zero in the outbound IA.
+
+In the great majority of cases, the values should follow this rule: T1 < T2 <
+preferred lifetime < valid lifetime. Alternatively, both T1 and T2
+values can be configured to 0, which is a signal to DHCPv6 clients that
+they may renew at their own discretion. However, there are known broken
+client implementations in use that will start renewing immediately.
+Administrators who plan to use T1=T2=0 values should test first and make sure
+their clients behave rationally.
+
+In some rare cases there may be a need to disable a client's ability to
+renew addresses. This is undesired from a protocol perspective and should
+be avoided if possible. However, if necessary, administrators can
+configure the T1 and T2 values to be equal or greater to the valid
+lifetime. Be advised that this will cause clients to occasionally
+lose their addresses, which is generally perceived as poor service.
+However, there may be some rare business cases when this is desired
+(e.g. when it is desirable to intentionally break long-lasting connections).
+
+Calculation of the values is controlled by the following three parameters:
+
+- ``calculate-tee-times`` - when ``true``, T1 and T2 are calculated as
+ percentages of the valid lease time. It defaults to ``true``.
+
+- ``t1-percent`` - the percentage of the valid lease time to use for
+ T1. It is expressed as a real number between 0.0 and 1.0 and must be
+ less than ``t2-percent``. The default value is 0.5, per RFC 8415.
+
+- ``t2-percent`` - the percentage of the valid lease time to use for
+ T2. It is expressed as a real number between 0.0 and 1.0 and must be
+ greater than ``t1-percent``. The default value is 0.8 per RFC 8415.
+
+.. note::
+
+ If both explicit values are specified and
+ ``calculate-tee-times`` is ``true``, the server will use the explicit values.
+ Administrators with a setup where some subnets or shared-networks
+ use explicit values and some use calculated values must
+ not define the explicit values at any level higher than where they
+ will be used. Inheriting them from too high a scope, such as
+ global, will cause them to have values at every level underneath
+ (both shared-networks and subnets), effectively disabling calculated
+ values.
+
+.. _dhcp6-config-subnets:
+
+IPv6 Subnet Selection
+---------------------
+
+The DHCPv6 server may receive requests from local (connected to the same
+subnet as the server) and remote (connected via relays) clients. As the
+server may have many subnet configurations defined, it must select an
+appropriate subnet for a given request.
+
+In IPv4, the server can determine which of the configured subnets are
+local, as there is a reasonable expectation that the server will have a
+(global) IPv4 address configured on the interface. That assumption is not
+true in IPv6; the DHCPv6 server must be able to operate while only using
+link-local addresses. Therefore, an optional ``interface`` parameter is
+available within a subnet definition to designate that a given subnet is
+local, i.e. reachable directly over the specified interface. For
+example, a server that is intended to serve a local subnet over eth0
+may be configured as follows:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:beef::/48",
+ "pools": [
+ {
+ "pool": "2001:db8:beef::/48"
+ }
+ ],
+ "interface": "eth0"
+ }
+ ],
+ ...
+ }
+
+.. _dhcp6-rapid-commit:
+
+Rapid Commit
+------------
+
+The Rapid Commit option, described in `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__, is supported by the Kea
+DHCPv6 server. However, support is disabled by default. It can be
+enabled on a per-subnet basis using the ``rapid-commit`` parameter as
+shown below:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:beef::/48",
+ "rapid-commit": true,
+ "pools": [
+ {
+ "pool": "2001:db8:beef::1-2001:db8:beef::10"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+This setting only affects the subnet for which ``rapid-commit`` is
+set to ``true``. For clients connected to other subnets, the server
+ignores the Rapid Commit option sent by the client and follows the
+4-way exchange procedure, i.e. responds with an Advertise for a Solicit
+containing a Rapid Commit option.
+
+.. _dhcp6-relays:
+
+DHCPv6 Relays
+-------------
+
+A DHCPv6 server with multiple subnets defined must select the
+appropriate subnet when it receives a request from a client. For clients
+connected via relays, two mechanisms are used:
+
+The first uses the ``linkaddr`` field in the ``RELAY_FORW`` message. The name of
+this field is somewhat misleading in that it does not contain a
+link-layer address; instead, it holds an address (typically a global
+address) that is used to identify a link. The DHCPv6 server checks to
+see whether the address belongs to a defined subnet and, if it does,
+that subnet is selected for the client's request.
+
+The second mechanism is based on ``interface-id`` options. While forwarding
+a client's message, relays may insert an ``interface-id`` option into the
+message that identifies the interface on the relay that received the
+message. (Some relays allow configuration of that parameter, but it is
+sometimes hard-coded and may range from the very simple [e.g. "vlan100"]
+to the very cryptic; one example seen on real hardware was
+"ISAM144|299|ipv6|nt:vp:1:110".) The server can use this information to
+select the appropriate subnet. The information is also returned to the
+relay, which then knows the interface to use to transmit the response to
+the client. For this to work successfully, the relay interface IDs must
+be unique within the network and the server configuration must match
+those values.
+
+When configuring the DHCPv6 server, two
+similarly named parameters can be configured for a subnet:
+
+- ``interface`` - defines which local network interface can be used to
+ access a given subnet.
+
+- ``interface-id`` - specifies the content of the ``interface-id`` option
+ used by relays to identify the interface on the relay to which the
+ response packet is sent.
+
+The two are mutually exclusive; a subnet cannot be reachable both
+locally (direct traffic) and via relays (remote traffic). Specifying
+both is a configuration error and the DHCPv6 server will refuse such a
+configuration.
+
+The following example configuration shows how to specify an ``interface-id``
+with a value of "vlan123":
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:beef::/48",
+ "pools": [
+ {
+ "pool": "2001:db8:beef::/48"
+ }
+ ],
+ "interface-id": "vlan123"
+ }
+ ],
+ ...
+ }
+
+.. _dhcp6-rsoo:
+
+Relay-Supplied Options
+----------------------
+
+`RFC 6422 <https://tools.ietf.org/html/rfc6422>`__ defines a mechanism
+called Relay-Supplied DHCP Options. In certain cases relay agents are
+the only entities that may have specific information, and they can
+insert options when relaying messages from the client to the server. The
+server then does certain checks and copies those options to the
+response sent to the client.
+
+There are certain conditions that must be met for the option to be
+included. First, the server must not provide the option itself; in other
+words, if both relay and server provide an option, the server always
+takes precedence. Second, the option must be RSOO-enabled. (RSOO is the
+"Relay Supplied Options option.") IANA maintains a list of RSOO-enabled
+options
+`here <https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied>`__.
+However, there may be cases when system administrators want to echo
+other options. Kea can be instructed to treat other options as
+RSOO-enabled; for example, to mark options 110, 120, and 130 as
+RSOO-enabled, the following syntax should be used:
+
+::
+
+ "Dhcp6": {
+ "relay-supplied-options": [ "110", "120", "130" ],
+ ...
+ }
+
+At this time, only option 65 is RSOO-enabled by IANA. This option
+will always be treated as RSOO-enabled, so there is no need to explicitly mark
+it. When enabling standard options, it is also possible to use their
+names rather than their option code, e.g. use ``dns-servers`` instead of
+``23``. See ref:`dhcp6-std-options-list` for the names. In
+certain cases this may also work for custom options, but due to the
+nature of the parser code this may be unreliable and should be avoided.
+
+.. _dhcp6-client-classifier:
+
+Client Classification in DHCPv6
+-------------------------------
+
+The DHCPv6 server includes support for client classification. For a
+deeper discussion of the classification process, see :ref:`classify`.
+
+In certain cases it is useful to configure the server to differentiate
+between DHCP client types and treat them accordingly. Client
+classification can be used to modify the behavior of almost any part of
+DHCP message processing. Kea currently offers
+three mechanisms that take advantage of client classification in DHCPv6:
+subnet selection, address pool selection, and DHCP options assignment.
+
+Kea can be instructed to limit access to given subnets based on class
+information. This is particularly useful for cases where two types of
+devices share the same link and are expected to be served from two
+different subnets. The primary use case for such a scenario is cable
+networks, where there are two classes of devices: the cable modem
+itself, which should be handed a lease from subnet A; and all other
+devices behind the modem, which should get leases from subnet B. That
+segregation is essential to prevent overly curious end-users from playing
+with their cable modems. For details on how to set up class restrictions
+on subnets, see :ref:`classification-subnets`.
+
+When subnets belong to a shared network, the classification applies to
+subnet selection but not to pools; that is, a pool in a subnet limited to a
+particular class can still be used by clients which do not belong to the
+class, if the pool they are expected to use is exhausted. The limit
+on access based on class information is also available at the
+address/prefix pool level within a subnet: see :ref:`classification-pools`.
+This is useful when segregating clients belonging to the same
+subnet into different address ranges.
+
+In a similar way, a pool can be constrained to serve only known clients,
+i.e. clients which have a reservation, using the built-in ``KNOWN`` or
+``UNKNOWN`` classes. Addresses can be assigned to registered clients
+without giving a different address per reservation: for instance, when
+there are not enough available addresses. The determination whether
+there is a reservation for a given client is made after a subnet is
+selected, so it is not possible to use ``KNOWN``/``UNKNOWN`` classes to select a
+shared network or a subnet.
+
+The process of classification is conducted in five steps. The first step
+is to assess an incoming packet and assign it to zero or more classes.
+The second step is to choose a subnet, possibly based on the class
+information. When the incoming packet is in the special class ``DROP``,
+it is dropped and a debug message logged.
+The next step is to evaluate class expressions depending on the built-in
+``KNOWN``/``UNKNOWN`` classes after host reservation lookup, using them for
+pool/pd-pool selection and assigning classes from host reservations. The
+list of required classes is then built and each class of the list has
+its expression evaluated; when it returns ``true``, the packet is added as
+a member of the class. The last step is to assign options, again possibly
+based on the class information. More complete and detailed information
+is available in :ref:`classify`.
+
+There are two main methods of classification. The first is automatic and
+relies on examining the values in the vendor class options or the
+existence of a host reservation. Information from these options is
+extracted, and a class name is constructed from it and added to the
+class list for the packet. The second method specifies an expression that is
+evaluated for each packet. If the result is ``true``, the packet is a
+member of the class.
+
+.. note::
+
+ The new ``early-global-reservations-lookup`` global parameter flag
+ enables a lookup for global reservations before the subnet selection
+ phase. This lookup is similar to the general lookup described above
+ with two differences:
+
+ - the lookup is limited to global host reservations
+
+ - the ``UNKNOWN`` class is never set
+
+.. note::
+
+ Care should be taken with client classification, as it is easy for
+ clients that do not meet class criteria to be denied all service.
+
+Defining and Using Custom Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following example shows how to configure a class using an expression
+and a subnet using that class. This configuration defines the class
+named ``Client_enterprise``. It is comprised of all clients whose client
+identifiers start with the given hex string (which would indicate a DUID
+based on an enterprise id of 0xAABBCCDD). Members of this class will be given an address
+from 2001:db8:1::0 to 2001:db8:1::FFFF and the addresses of their DNS
+servers set to 2001:db8:0::1 and 2001:db8:2::1.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client_enterprise",
+ "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "code": 23,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:0::1, 2001:db8:2::1"
+ }
+ ]
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ],
+ "client-class": "Client_enterprise"
+ }
+ ],
+ ...
+ }
+
+This example shows a configuration using an automatically generated
+``VENDOR_CLASS_`` class. The administrator of the network has decided that
+addresses in the range 2001:db8:1::1 to 2001:db8:1::ffff are to be
+managed by the DHCPv6 server and that only clients belonging to the
+eRouter1.0 client class are allowed to use that pool.
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::ffff"
+ }
+ ],
+ "client-class": "VENDOR_CLASS_eRouter1.0"
+ }
+ ],
+ ...
+ }
+
+.. _dhcp6-required-class:
+
+Required Classification
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases it is useful to limit the scope of a class to a
+shared network, subnet, or pool. There are two parameters which are used
+to limit the scope of the class by instructing the server to evaluate test
+expressions when required.
+
+The first one is the per-class ``only-if-required`` flag, which is ``false``
+by default. When it is set to ``true``, the test expression of the class
+is not evaluated at the reception of the incoming packet but later, and
+only if the class evaluation is required.
+
+The second is ``require-client-classes``, which takes a list of class
+names and is valid in shared-network, subnet, and pool scope. Classes in
+these lists are marked as required and evaluated after selection of this
+specific shared network/subnet/pool and before output-option processing.
+
+In this example, a class is assigned to the incoming packet when the
+specified subnet is used:
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "Client_foo",
+ "test": "member('ALL')",
+ "only-if-required": true
+ },
+ ...
+ ],
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::ffff"
+ }
+ ],
+ "require-client-classes": [ "Client_foo" ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Required evaluation can be used to express complex dependencies like
+subnet membership. It can also be used to reverse the
+precedence; if ``option-data`` is set in a subnet, it takes precedence
+over ``option-data`` in a class. If ``option-data`` is moved to a
+required class and required in the subnet, a class evaluated earlier
+may take precedence.
+
+Required evaluation is also available at shared-network and pool/pd-pool
+levels. The order in which required classes are considered is:
+shared-network, subnet, and (pd-)pool, i.e. in the reverse order from the
+way in which ``option-data`` is processed.
+
+.. _dhcp6-ddns-config:
+
+DDNS for DHCPv6
+---------------
+
+As mentioned earlier, :iscman:`kea-dhcp6` can be configured to generate requests
+to the DHCP-DDNS server, :iscman:`kea-dhcp-ddns`, (referred to herein as "D2") to
+update DNS entries. These requests are known as NameChangeRequests or
+NCRs. Each NCR contains the following information:
+
+1. Whether it is a request to add (update) or remove DNS entries.
+
+2. Whether the change requests forward DNS updates (AAAA records), reverse
+ DNS updates (PTR records), or both.
+
+3. The Fully Qualified Domain Name (FQDN), lease address, and DHCID
+ (information identifying the client associated with the FQDN).
+
+DDNS-related parameters are split into two groups:
+
+1. Connectivity Parameters
+
+ These are parameters which specify where and how :iscman:`kea-dhcp6` connects to
+ and communicates with D2. These parameters can only be specified
+ within the top-level ``dhcp-ddns`` section in the :iscman:`kea-dhcp6`
+ configuration. The connectivity parameters are listed below:
+
+ - ``enable-updates``
+ - ``server-ip``
+ - ``server-port``
+ - ``sender-ip``
+ - ``sender-port``
+ - ``max-queue-size``
+ - ``ncr-protocol``
+ - ``ncr-format"``
+
+2. Behavioral Parameters
+
+ These parameters influence behavior such as how client host names and
+ FQDN options are handled. They have been moved out of the ``dhcp-ddns``
+ section so that they may be specified at the global, shared-network,
+ and/or subnet levels. Furthermore, they are inherited downward from global to
+ shared-network to subnet. In other words, if a parameter is not specified at
+ a given level, the value for that level comes from the level above it.
+ The behavioral parameters are as follows:
+
+ - ``ddns-send-updates``
+ - ``ddns-override-no-update``
+ - ``ddns-override-client-update``
+ - ``ddns-replace-client-name"``
+ - ``ddns-generated-prefix``
+ - ``ddns-qualifying-suffix``
+ - ``ddns-update-on-renew``
+ - ``ddns-conflict-resolution-mode``
+ - ``ddns-ttl-percent``
+ - ``hostname-char-set``
+ - ``hostname-char-replacement``
+
+.. note::
+
+ For backward compatibility, configuration parsing still recognizes
+ the original behavioral parameters specified in ``dhcp-ddns``,
+ by translating the parameter into its global equivalent. If a
+ parameter is specified both globally and in ``dhcp-ddns``, the latter
+ value is ignored. In either case, a log is emitted explaining
+ what has occurred. Specifying these values within ``dhcp-ddns`` is
+ deprecated and support for it will be removed.
+
+The default configuration and values would appear as follows:
+
+::
+
+ "Dhcp6": {
+ "dhcp-ddns": {
+ // Connectivity parameters
+ "enable-updates": false,
+ "server-ip": "127.0.0.1",
+ "server-port":53001,
+ "sender-ip":"",
+ "sender-port":0,
+ "max-queue-size":1024,
+ "ncr-protocol":"UDP",
+ "ncr-format":"JSON"
+ },
+
+ // Behavioral parameters (global)
+ "ddns-send-updates": true,
+ "ddns-override-no-update": false,
+ "ddns-override-client-update": false,
+ "ddns-replace-client-name": "never",
+ "ddns-generated-prefix": "myhost",
+ "ddns-qualifying-suffix": "",
+ "ddns-update-on-renew": false,
+ "ddns-conflict-resolution-mode": "check-with-dhcid",
+ "hostname-char-set": "",
+ "hostname-char-replacement": "",
+ ...
+ }
+
+There are two parameters which determine if :iscman:`kea-dhcp6`
+can generate DDNS requests to D2: the existing ``dhcp-ddns:enable-updates``
+parameter, which now only controls whether :iscman:`kea-dhcp6` connects to D2;
+and the new behavioral parameter, ``ddns-send-updates``, which determines
+whether DDNS updates are enabled at a given level (i.e. global, shared-network,
+or subnet). The following table shows how the two parameters function
+together:
+
+.. table:: Enabling and disabling DDNS updates
+
+ +-----------------+--------------------+-------------------------------------+
+ | dhcp-ddns: | Global | Outcome |
+ | enable-updates | ddns-send-updates | |
+ +=================+====================+=====================================+
+ | false (default) | false | no updates at any scope |
+ +-----------------+--------------------+-------------------------------------+
+ | false | true (default) | no updates at any scope |
+ +-----------------+--------------------+-------------------------------------+
+ | true | false | updates only at scopes with |
+ | | | a local value of ``true`` for |
+ | | | ``ddns-enable-updates`` |
+ +-----------------+--------------------+-------------------------------------+
+ | true | true | updates at all scopes except those |
+ | | | with a local value of ``false`` |
+ | | | for ``ddns-enable-updates`` |
+ +-----------------+--------------------+-------------------------------------+
+
+Kea 1.9.1 added two new parameters; the first is ``ddns-update-on-renew``.
+Normally, when leases are renewed, the server only updates DNS if the DNS
+information for the lease (e.g. FQDN, DNS update direction flags) has changed.
+Setting ``ddns-update-on-renew`` to ``true`` instructs the server to always update
+the DNS information when a lease is renewed, even if its DNS information has not
+changed. This allows Kea to "self-heal" if it was previously unable
+to add DNS entries or they were somehow lost by the DNS server.
+
+.. note::
+
+ Setting ``ddns-update-on-renew`` to ``true`` may impact performance, especially
+ for servers with numerous clients that renew often.
+
+The second parameter added in Kea 1.9.1 is ``ddns-use-conflict-resolution``. This
+boolean parameter was passed through to D2 and enabled or disabled conflict resolution
+as described in `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__. Beginning with
+Kea 2.5.0, it is deprecated and replaced by ``ddns-conflict-resolution-mode`` which
+offers four modes of conflict resolution-related behavior:
+
+ - ``check-with-dhcid`` - The default mode, it instructs D2 to carry out RFC
+ 4703-compliant conflict resolution. Existing DNS entries may only be
+ overwritten if they have a DHCID record and it matches the client's DHCID.
+ This is equivalent to ``ddns-use-conflict-resolution``: true;
+
+ - ``no-check-with-dhcid`` - Existing DNS entries may be overwritten by any
+ client, whether or not those entries include a DHCID record. The new entries
+ will include a DHCID record for the client to whom they belong.
+ This is equivalent to ``ddns-use-conflict-resolution``: false;
+
+ - ``check-exists-with-dhcid`` - Existing DNS entries may only be overwritten
+ if they have a DHCID record. The DHCID record need not match the client's DHCID.
+ This mode provides a way to protect static DNS entries (those that do not have
+ a DHCID record) while allowing dynamic entries (those that do have a DHCID
+ record) to be overwritten by any client. This behavior was not supported
+ prior to Kea 2.4.0.
+
+ - ``no-check-without-dhcid`` - Existing DNS entries may be overwritten by
+ any client. New entries will not include DHCID records. This behavior was
+ not supported prior to Kea 2.4.0.
+
+.. note::
+
+ For backward compatibility, ddns-use-conflict-resolution is still accepted in
+ JSON configuration. The server will replace the value internally, with the
+ ``ddns-conflict-resolution-mode`` and an appropriate value: `
+ `check-with-dhcid`` for ``true`` and ``no-check-with-dhcid`` for ``false``.
+
+.. note::
+
+ Setting ``ddns-conflict-resolution-mode`` to any value other than
+ ``check-with-dhcid`` disables the one or more overwrite safeguards
+ that the rules of conflict resolution (from
+ `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__) are intended to
+ prevent. This means that existing entries for an FQDN or an
+ IP address made for Client-A can be deleted or replaced by entries
+ for Client-B. Furthermore, there are two scenarios by which entries
+ for multiple clients for the same key (e.g. FQDN or IP) can be created.
+
+ 1. Client-B uses the same FQDN as Client-A but a different IP address.
+ In this case, the forward DNS entries (AAAA and DHCID RRs) for
+ Client-A will be deleted as they match the FQDN and new entries for
+ Client-B will be added. The reverse DNS entries (PTR and DHCID RRs)
+ for Client-A, however, will not be deleted as they belong to a different
+ IP address, while new entries for Client-B will still be added.
+
+ 2. Client-B uses the same IP address as Client-A but a different FQDN.
+ In this case the reverse DNS entries (PTR and DHCID RRs) for Client-A
+ will be deleted as they match the IP address, and new entries for
+ Client-B will be added. The forward DNS entries (AAAA and DHCID RRs)
+ for Client-A, however, will not be deleted, as they belong to a different
+ FQDN, while new entries for Client-B will still be added.
+
+ Disabling conflict resolution should be done only after careful review of
+ specific use cases. The best way to avoid unwanted DNS entries is to
+ always ensure lease changes are processed through Kea, whether they are
+ released, expire, or are deleted via the :isccmd:`lease6-del` command, prior to
+ reassigning either FQDNs or IP addresses. Doing so causes :iscman:`kea-dhcp6`
+ to generate DNS removal requests to D2.
+
+The DNS entries Kea creates contain a value for TTL (time to live).
+The :iscman:`kea-dhcp6` server calculates that value based on
+`RFC 4702, Section 5 <https://tools.ietf.org/html/rfc4702#section-5>`__,
+which suggests that the TTL value be 1/3 of the lease's lifetime, with
+a minimum value of 10 minutes.
+
+The parameter ``ddns-ttl-percent``, when specified,
+causes the TTL to be calculated as a simple percentage of the lease's
+lifetime, using the parameter's value as the percentage. It is specified
+as a decimal percent (e.g. .25, .75, 1.00) and may be specified at the
+global, shared-network, and subnet levels. By default it is unspecified.
+
+.. _dhcpv6-d2-io-config:
+
+DHCP-DDNS Server Connectivity
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For NCRs to reach the D2 server, :iscman:`kea-dhcp6` must be able to communicate
+with it. :iscman:`kea-dhcp6` uses the following configuration parameters to
+control this communication:
+
+- ``enable-updates`` - Enables connectivity to :iscman:`kea-dhcp-ddns` such that DDNS
+ updates can be constructed and sent.
+ It must be ``true`` for NCRs to be generated and sent to D2.
+ It defaults to ``false``.
+
+- ``server-ip`` - This is the IP address on which D2 listens for requests. The
+ default is the local loopback interface at address 127.0.0.1.
+ Either an IPv4 or IPv6 address may be specified.
+
+- ``server-port`` - This is the port on which D2 listens for requests. The default
+ value is ``53001``.
+
+- ``sender-ip`` - This is the IP address which :iscman:`kea-dhcp6` uses to send requests to
+ D2. The default value is blank, which instructs :iscman:`kea-dhcp6` to select a
+ suitable address.
+
+- ``sender-port`` - This is the port which :iscman:`kea-dhcp6` uses to send requests to D2.
+ The default value of ``0`` instructs :iscman:`kea-dhcp6` to select a suitable port.
+
+- ``max-queue-size`` - This is the maximum number of requests allowed to queue
+ while waiting to be sent to D2. This value guards against requests
+ accumulating uncontrollably if they are being generated faster than
+ they can be delivered. If the number of requests queued for
+ transmission reaches this value, DDNS updating is turned off
+ until the queue backlog has been sufficiently reduced. The intent is
+ to allow the :iscman:`kea-dhcp4` server to continue lease operations without
+ running the risk that its memory usage grows without limit. The
+ default value is ``1024``.
+
+- ``ncr-protocol`` - This specifies the socket protocol to use when sending requests to
+ D2. Currently only UDP is supported.
+
+- ``ncr-format`` - This specifies the packet format to use when sending requests to D2.
+ Currently only JSON format is supported.
+
+By default, :iscman:`kea-dhcp-ddns` is assumed to be running on the same machine
+as :iscman:`kea-dhcp6`, and all of the default values mentioned above should be
+sufficient. If, however, D2 has been configured to listen on a different
+address or port, these values must be altered accordingly. For example, if
+D2 has been configured to listen on 2001:db8::5 port 900, the following
+configuration is required:
+
+::
+
+ "Dhcp6": {
+ "dhcp-ddns": {
+ "server-ip": "2001:db8::5",
+ "server-port": 900,
+ ...
+ },
+ ...
+ }
+
+.. _dhcpv6-d2-rules-config:
+
+When Does the :iscman:`kea-dhcp6` Server Generate a DDNS Request?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :iscman:`kea-dhcp6` server follows the behavior prescribed for DHCP servers in
+`RFC 4704 <https://tools.ietf.org/html/rfc4704>`__. It is important to keep
+in mind that :iscman:`kea-dhcp6` makes the initial decision of when and what to
+update and forwards that information to D2 in the form of NCRs. Carrying
+out the actual DNS updates and dealing with such things as conflict
+resolution are within the purview of D2 itself
+(see :ref:`dhcp-ddns-server`). This section describes when :iscman:`kea-dhcp6`
+generates NCRs and the configuration parameters that can be used to
+influence this decision. It assumes that both the connectivity parameter
+``enable-updates`` and the behavioral parameter ``ddns-send-updates``,
+are ``true``.
+
+.. note::
+
+ Currently the interface between :iscman:`kea-dhcp6` and D2 only supports
+ requests which update DNS entries for a single IP address. If a lease
+ grants more than one address, :iscman:`kea-dhcp6` creates the DDNS update
+ request for only the first of these addresses.
+
+In general, :iscman:`kea-dhcp6` generates DDNS update requests when:
+
+1. A new lease is granted in response to a DHCPREQUEST;
+
+2. An existing lease is renewed but the FQDN associated with it has
+ changed; or
+
+3. An existing lease is released in response to a DHCPRELEASE.
+
+In the second case, lease renewal, two DDNS requests are issued: one
+request to remove entries for the previous FQDN, and a second request to
+add entries for the new FQDN. In the third case, a lease release - a
+single DDNS request - to remove its entries will be made.
+
+As for the first case, the decisions involved when granting a new lease are
+more complex. When a new lease is granted, :iscman:`kea-dhcp6` generates a
+DDNS update request only if the DHCPREQUEST contains the FQDN option
+(code 39).
+By default, :iscman:`kea-dhcp6` respects the FQDN N and S flags
+specified by the client as shown in the following table:
+
+.. table:: Default FQDN flag behavior
+
+ +------------+-----------------+-----------------+-------------+
+ | Client | Client Intent | Server Response | Server |
+ | Flags:N-S | | | Flags:N-S-O |
+ +============+=================+=================+=============+
+ | 0-0 | Client wants to | Server | 1-0-0 |
+ | | do forward | generates | |
+ | | updates, server | reverse-only | |
+ | | should do | request | |
+ | | reverse updates | | |
+ +------------+-----------------+-----------------+-------------+
+ | 0-1 | Server should | Server | 0-1-0 |
+ | | do both forward | generates | |
+ | | and reverse | request to | |
+ | | updates | update both | |
+ | | | directions | |
+ +------------+-----------------+-----------------+-------------+
+ | 1-0 | Client wants no | Server does not | 1-0-0 |
+ | | updates done | generate a | |
+ | | | request | |
+ +------------+-----------------+-----------------+-------------+
+
+The first row in the table above represents "client delegation." Here
+the DHCP client states that it intends to do the forward DNS updates and
+the server should do the reverse updates. By default, :iscman:`kea-dhcp6`
+honors the client's wishes and generates a DDNS request to the D2 server
+to update only reverse DNS data. The parameter
+``ddns-override-client-update`` can be used to instruct the server to
+override client delegation requests. When this parameter is ``true``,
+:iscman:`kea-dhcp6` disregards requests for client delegation and generates a
+DDNS request to update both forward and reverse DNS data. In this case,
+the N-S-O flags in the server's response to the client will be 0-1-1
+respectively.
+
+(Note that the flag combination N=1, S=1 is prohibited according to `RFC
+4702 <https://tools.ietf.org/html/rfc4702>`__. If such a combination is
+received from the client, the packet will be dropped by :iscman:`kea-dhcp6`.)
+
+To override client delegation, set the following values in the
+configuration file:
+
+::
+
+ "Dhcp6": {
+ "ddns-override-client-update": true,
+ ...
+ }
+
+The third row in the table above describes the case in which the client
+requests that no DNS updates be done. The parameter
+``ddns-override-no-update`` can be used to instruct the server to disregard
+the client's wishes. When this parameter is ``true``, :iscman:`kea-dhcp6`
+generates DDNS update requests to :iscman:`kea-dhcp-ddns` even if the client
+requests that no updates be done. The N-S-O flags in the server's response to
+the client will be 0-1-1.
+
+To override client delegation, issue the following commands:
+
+::
+
+ "Dhcp6": {
+ "ddns-override-no-update": true,
+ ...
+ }
+
+The :iscman:`kea-dhcp6` server always generates DDNS update requests if the
+client request only contains the Host Name option. In addition, it includes
+an FQDN option in the response to the client with the FQDN N-S-O flags
+set to 0-1-0, respectively. The domain name portion of the FQDN option
+is the name submitted to D2 in the DDNS update request.
+
+.. _dhcpv6-fqdn-name-generation:
+
+:iscman:`kea-dhcp6` Name Generation for DDNS Update Requests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each NameChangeRequest must of course include the fully qualified domain
+name whose DNS entries are to be affected. :iscman:`kea-dhcp6` can be configured
+to supply a portion or all of that name, based on what it receives
+from the client in the DHCPREQUEST.
+
+The default rules for constructing the FQDN that will be used for DNS
+entries are:
+
+1. If the DHCPREQUEST contains the client FQDN option, take the
+ candidate name from there.
+
+2. If the candidate name is a partial (i.e. unqualified) name, then add
+ a configurable suffix to the name and use the result as the FQDN.
+
+3. If the candidate name provided is empty, generate an FQDN using a
+ configurable prefix and suffix.
+
+4. If the client provides neither option, then take no DNS action.
+
+These rules can be amended by setting the ``ddns-replace-client-name``
+parameter, which provides the following modes of behavior:
+
+- ``never`` - use the name the client sent. If the client sent no name,
+ do not generate one. This is the default mode.
+
+- ``always`` - replace the name the client sent. If the client sent no
+ name, generate one for the client.
+
+- ``when-present`` - replace the name the client sent. If the client
+ sent no name, do not generate one.
+
+- ``when-not-present`` - use the name the client sent. If the client
+ sent no name, generate one for the client.
+
+.. note::
+
+ In early versions of Kea, this parameter was a boolean and permitted only
+ values of ``true`` and ``false``. Boolean values have been deprecated
+ and are no longer accepted. Administrators currently using booleans
+ must replace them with the desired mode name. A value of ``true``
+ maps to ``when-present``, while ``false`` maps to ``never``.
+
+For example, to instruct :iscman:`kea-dhcp6` to always generate the FQDN for a
+client, set the parameter ``ddns-replace-client-name`` to ``always`` as
+follows:
+
+::
+
+ "Dhcp6": {
+ "ddns-replace-client-name": "always",
+ ...
+ }
+
+The prefix used in the generation of an FQDN is specified by the
+``ddns-generated-prefix`` parameter. The default value is "myhost". To alter
+its value, simply set it to the desired string:
+
+::
+
+ "Dhcp6": {
+ "ddns-generated-prefix": "another.host",
+ ...
+ }
+
+The suffix used when generating an FQDN, or when qualifying a partial
+name, is specified by the ``ddns-qualifying-suffix`` parameter. It is
+strongly recommended that the user supply a value for the qualifying
+suffix when DDNS updates are enabled. For obvious reasons, we cannot
+supply a meaningful default.
+
+::
+
+ "Dhcp6": {
+ "ddns-qualifying-suffix": "foo.example.org",
+ ...
+ }
+
+When qualifying a partial name, :iscman:`kea-dhcp6` constructs the name in the
+format:
+
+``[candidate-name].[ddns-qualifying-suffix].``
+
+where ``candidate-name`` is the partial name supplied in the DHCPREQUEST.
+For example, if the FQDN domain name value is "some-computer" and the
+``ddns-qualifying-suffix`` is "example.com", the generated FQDN is:
+
+``some-computer.example.com.``
+
+When generating the entire name, :iscman:`kea-dhcp6` constructs the name in
+the format:
+
+``[ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix].``
+
+where ``address-text`` is simply the lease IP address converted to a
+hyphenated string. For example, if the lease address is 3001:1::70E, the
+qualifying suffix is "example.com", and the default value is used for
+``ddns-generated-prefix``, the generated FQDN is:
+
+``myhost-3001-1--70E.example.com.``
+
+.. _dhcp6-host-name-sanitization:
+
+Sanitizing Client FQDN Names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some DHCP clients may provide values in the name component of the FQDN
+option (option code 39) that contain undesirable
+characters. It is possible to configure :iscman:`kea-dhcp6` to sanitize these
+values. The most typical use case is ensuring that only characters that
+are permitted by RFC 1035 be included: A-Z, a-z, 0-9, and "-". This may be
+accomplished with the following two parameters:
+
+- ``hostname-char-set`` - a regular expression describing the invalid
+ character set. This can be any valid, regular expression using POSIX
+ extended expression syntax. Embedded nulls (0x00) are always
+ considered an invalid character to be replaced (or omitted).
+ The default is ``"[^A-Za-z0-9.-]"``. This matches any character that is not
+ a letter, digit, dot, hyphen, or null.
+
+- ``hostname-char-replacement`` - a string of zero or more characters
+ with which to replace each invalid character in the host name. An empty
+ string causes invalid characters to be OMITTED rather than replaced.
+ The default is ``""``.
+
+The following configuration replaces anything other than a letter,
+digit, dot, or hyphen with the letter "x":
+::
+
+ "Dhcp6": {
+ "hostname-char-set": "[^A-Za-z0-9.-]",
+ "hostname-char-replacement": "x",
+ ...
+ }
+
+Thus, a client-supplied value of "myhost-$[123.org" would become
+"myhost-xx123.org". Sanitizing is performed only on the portion of the
+name supplied by the client, and it is performed before applying a
+qualifying suffix (if one is defined and needed).
+
+.. note::
+
+ Name sanitizing is meant to catch the more common cases of invalid
+ characters through a relatively simple character-replacement scheme.
+ It is difficult to devise a scheme that works well in all cases.
+ Administrators who find they have clients with odd corner cases of
+ character combinations that cannot be readily handled with this
+ mechanism should consider writing a hook that can carry out
+ sufficiently complex logic to address their needs.
+
+ Make sure that the dot, "." is considered a valid character by the
+ ``hostname-char-set`` expression, such as this: ``"[^A-Za-z0-9.-]"``.
+ When scrubbing FQDNs, dots are treated as delimiters and used to separate
+ the option value into individual domain labels that are scrubbed and
+ then re-assembled.
+
+ If clients are sending values that differ only by characters
+ considered as invalid by the ``hostname-char-set``, be aware that
+ scrubbing them will yield identical values. In such cases, DDNS
+ conflict rules will permit only one of them to register the name.
+
+ Finally, given the latitude clients have in the values they send, it
+ is virtually impossible to guarantee that a combination of these two
+ parameters will always yield a name that is valid for use in DNS. For
+ example, using an empty value for ``hostname-char-replacement`` could
+ yield an empty domain label within a name, if that label consists
+ only of invalid characters.
+
+.. note::
+
+ It is possible to specify ``hostname-char-set``
+ and/or ``hostname-char-replacement`` at the global scope. This allows
+ host names to be sanitized without requiring a ``dhcp-ddns`` entry. When
+ a ``hostname-char`` parameter is defined at both the global scope and
+ in a ``dhcp-ddns`` entry, the second (local) value is used.
+
+ For the ability to generate host names procedurally, based on an expression, and
+ for the ability to skip DDNS updates on a per-client basis, or fine-tuning various
+ DNS update aspects, the :iscman:`kea-dhcp6` can load the premium hook library
+ `libdhcp_ddns_tuning.so` which is available from ISC. Please refer to
+ :ref:`hooks-ddns-tuning` documentation for the configuration options.
+
+.. _dhcp6-dhcp4o6-config:
+
+DHCPv4-over-DHCPv6: DHCPv6 Side
+-------------------------------
+
+The support of DHCPv4-over-DHCPv6 transport is described in `RFC
+7341 <https://tools.ietf.org/html/rfc7341>`__ and is implemented using
+cooperating DHCPv4 and DHCPv6 servers. This section is about the
+configuration of the DHCPv6 side (the DHCPv4 side is described in
+:ref:`dhcp4-dhcp4o6-config`).
+
+.. note::
+
+ DHCPv4-over-DHCPv6 support is experimental and the details of the
+ inter-process communication may change; for instance, the
+ support of port relay (RFC 8357) introduced an incompatible change.
+ Both the DHCPv4 and DHCPv6 sides should be running the same version of Kea.
+
+There is only one specific parameter for the DHCPv6 side:
+``dhcp4o6-port``, which specifies the first of the two consecutive ports
+of the UDP sockets used for the communication between the DHCPv6 and
+DHCPv4 servers. The DHCPv6 server is bound to ::1 on ``port`` and
+connected to ::1 on ``port`` + 1.
+
+Two other configuration entries are generally required: unicast traffic
+support (see :ref:`dhcp6-unicast`) and the DHCP 4o6
+server address option (name "dhcp4o6-server-addr", code 88).
+
+ISC tested the following configuration:
+
+::
+
+ {
+
+ # DHCPv6 conf
+ "Dhcp6": {
+
+ "interfaces-config": {
+ "interfaces": [ "eno33554984/2001:db8:1:1::1" ]
+ },
+
+ "lease-database": {
+ "type": "memfile",
+ "name": "leases6"
+ },
+
+ "preferred-lifetime": 3000,
+ "valid-lifetime": 4000,
+ "renew-timer": 1000,
+ "rebind-timer": 2000,
+
+ "subnet6": [ {
+ "id": 1,
+ "subnet": "2001:db8:1:1::/64",
+ "interface": "eno33554984",
+ "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ]
+ } ],
+
+ "dhcp4o6-port": 6767,
+
+ "option-data": [ {
+ "name": "dhcp4o6-server-addr",
+ "code": 88,
+ "space": "dhcp6",
+ "csv-format": true,
+ "data": "2001:db8:1:1::1"
+ } ],
+
+
+ "loggers": [ {
+ "name": "kea-dhcp6",
+ "output-options": [ {
+ "output": "/tmp/kea-dhcp6.log"
+ } ],
+ "severity": "DEBUG",
+ "debuglevel": 0
+ } ]
+ }
+
+ }
+
+.. note::
+
+ Relayed DHCPv4-QUERY DHCPv6 messages are not supported.
+
+.. _sanity-checks6:
+
+Sanity Checks in DHCPv6
+-----------------------
+
+An important aspect of a well-running DHCP system is an assurance that
+the data remains consistent; however, in some cases it may be convenient
+to tolerate certain inconsistent data. For example, a network
+administrator who temporarily removes a subnet from a configuration
+would not want all the leases associated with it to disappear from the
+lease database. Kea has a mechanism to implement sanity checks for situations
+like this.
+
+Kea supports a configuration scope called ``sanity-checks``.
+A parameter, called ``lease-checks``,
+governs the verification carried out when a new lease is loaded from a
+lease file. This mechanism permits Kea to attempt to correct inconsistent data.
+
+Every subnet has a ``subnet-id`` value; this is how Kea internally
+identifies subnets. Each lease has a ``subnet-id`` parameter as well, which
+identifies the subnet it belongs to. However, if the configuration has
+changed, it is possible that a lease could exist with a ``subnet-id`` but
+without any subnet that matches it. Also, it is possible that the
+subnet's configuration has changed and the ``subnet-id`` now belongs to a
+subnet that does not match the lease.
+
+Kea's corrective algorithm first
+checks to see if there is a subnet with the ``subnet-id`` specified by the
+lease. If there is, it verifies whether the lease belongs to that
+subnet. If not, depending on the ``lease-checks`` setting, the lease is
+discarded, a warning is displayed, or a new subnet is selected for the
+lease that matches it topologically.
+
+Since delegated prefixes do not have to belong to a subnet in which
+they are offered, there is no way to implement such a mechanism for IPv6
+prefixes. As such, the mechanism works for IPv6 addresses only.
+
+There are five levels which are supported:
+
+- ``none`` - do no special checks; accept the lease as is.
+
+- ``warn`` - if problems are detected display a warning, but
+ accept the lease data anyway. This is the default value.
+
+- ``fix`` - if a data inconsistency is discovered, try to
+ correct it. If the correction is not successful, insert the incorrect data
+ anyway.
+
+- ``fix-del`` - if a data inconsistency is discovered, try to
+ correct it. If the correction is not successful, reject the lease.
+ This setting ensures the data's correctness, but some
+ incorrect data may be lost. Use with care.
+
+- ``del`` - if any inconsistency is
+ detected, reject the lease. This is the strictest mode; use with care.
+
+This feature is currently implemented for the memfile backend. The
+sanity check applies to the lease database in memory, not to the lease file,
+i.e. inconsistent leases will stay in the lease file.
+
+An example configuration that sets this parameter looks as follows:
+
+::
+
+ "Dhcp6": {
+ "sanity-checks": {
+ "lease-checks": "fix-del"
+ },
+ ...
+ }
+
+.. _store-extended-info-v6:
+
+Storing Extended Lease Information
+----------------------------------
+To support such features as DHCPv6 Reconfigure
+(`RFC 3315 <https://tools.ietf.org/html/rfc3315>`__) and Leasequery
+(`RFC 5007 <https://tools.ietf.org/html/rfc5007>`__),
+additional information must be stored with each lease. Because the amount
+of information stored for each lease has ramifications in terms of
+performance and system resource consumption, storage of this additional
+information is configurable through the ``store-extended-info`` parameter.
+It defaults to ``false`` and may be set at the global, shared-network, and
+subnet levels.
+
+::
+
+ "Dhcp6": {
+ "store-extended-info": true,
+ ...
+ }
+
+When set to ``true``, information relevant to the DHCPv6 query (e.g. REQUEST, RENEW,
+or REBIND) asking for the lease is added into the lease's ``user-context`` as a
+map element labeled "ISC". Currently, the information contained in the map
+is a list of relays, one for each relay message layer that encloses the
+client query. The lease's
+``user-context`` for a two-hop query might look something like this (shown
+pretty-printed for clarity):
+
+::
+
+ {
+ "ISC": {
+ "relay-info": [
+ {
+ "hop": 3,
+ "link": "2001:db8::1",
+ "peer": "2001:db8::2"
+ },
+ {
+ "hop": 2,
+ "link": "2001:db8::3",
+ "options": "0x00C800080102030405060708",
+ "peer": "2001:db8::4"
+ },
+ {
+ "hop": 1,
+ "link": "2001:db8::5",
+ "options": "0x00250006010203040506003500086464646464646464",
+ "remote-id": "010203040506",
+ "relay-id": "6464646464646464"
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ Prior to Kea version 2.3.2, this entry was named ``relays``; remote and relay
+ identifier options were not decoded.
+
+.. note::
+
+ It is possible that other hook libraries are already using
+ ``user-context``. Enabling ``store-extended-info`` should not interfere with
+ any other ``user-context`` content, as long as it does not also use an element
+ labeled "ISC". In other words, ``user-context`` is intended to be a flexible
+ container serving multiple purposes. As long as no other purpose also
+ writes an "ISC" element to ``user-context`` there should not be a conflict.
+
+Extended lease information is also subject to configurable sanity checking.
+The parameter in the ``sanity-checks`` scope is named ``extended-info-checks``
+and supports these levels:
+
+- ``none`` - do no check nor upgrade. This level should be used only when
+ extended info is not used at all or when no badly formatted extended
+ info, including using the old format, is expected.
+
+- ``fix`` - fix some common inconsistencies and upgrade extended info
+ using the old format to the new one. It is the default level and is
+ convenient when the Leasequery hook library is not loaded.
+
+- ``strict`` - fix all inconsistencies which have an impact on the (Bulk)
+ Leasequery hook library.
+
+- ``pedantic`` - enforce full conformance to the format produced by the
+ Kea code; for instance, no extra entries are allowed with the exception
+ of ``comment``.
+
+.. note::
+
+ This feature is currently implemented only for the memfile
+ backend. The sanity check applies to the lease database in memory,
+ not to the lease file, i.e. inconsistent leases stay in the lease
+ file.
+
+.. _dhcp6-multi-threading-settings:
+
+Multi-Threading Settings
+------------------------
+
+The Kea server can be configured to process packets in parallel using multiple
+threads. These settings can be found under the ``multi-threading`` structure and are
+represented by:
+
+- ``enable-multi-threading`` - use multiple threads to process packets in
+ parallel. The default is ``true``.
+
+- ``thread-pool-size`` - specify the number of threads to process packets in
+ parallel. It may be set to ``0`` (auto-detect), or any positive number that
+ explicitly sets the thread count. The default is ``0``.
+
+- ``packet-queue-size`` - specify the size of the queue used by the thread
+ pool to process packets. It may be set to ``0`` (unlimited), or any positive
+ number that explicitly sets the queue size. The default is ``64``.
+
+An example configuration that sets these parameters looks as follows:
+
+::
+
+ "Dhcp6": {
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "thread-pool-size": 4,
+ "packet-queue-size": 16
+ },
+ ...
+ }
+
+Multi-Threading Settings With Different Database Backends
+---------------------------------------------------------
+
+The Kea DHCPv6 server is benchmarked by ISC to determine which settings
+give the best performance. Although this section describes our results, they are merely
+recommendations and are very dependent on the particular hardware used
+for benchmarking. We strongly advise that administrators run their own performance benchmarks.
+
+A full report of performance results for the latest stable Kea version can be found
+`here <https://reports.kea.isc.org/>`_.
+This includes hardware and benchmark scenario descriptions, as well as
+current results.
+
+After enabling multi-threading, the number of threads is set by the ``thread-pool-size``
+parameter. Results from our experiments show that the best settings for
+:iscman:`kea-dhcp6` are:
+
+- ``thread-pool-size``: 4 when using ``memfile`` for storing leases.
+
+- ``thread-pool-size``: 12 or more when using ``mysql`` for storing leases.
+
+- ``thread-pool-size``: 6 when using ``postgresql``.
+
+Another very important parameter is ``packet-queue-size``; in our benchmarks we
+used it as a multiplier of ``thread-pool-size``. The actual setting strongly depends
+on ``thread-pool-size``.
+
+We saw the best results in our benchmarks with the following settings:
+
+- ``packet-queue-size``: 150 * ``thread-pool-size`` when using ``memfile`` for
+ storing leases; in our case it was 150 * 4 = 600. This means that at any given
+ time, up to 600 packets could be queued.
+
+- ``packet-queue-size``: 200 * ``thread-pool-size`` when using ``mysql`` for
+ storing leases; in our case it was 200 * 12 = 2400. This means that up to
+ 2400 packets could be queued.
+
+- ``packet-queue-size``: 11 * ``thread-pool-size`` when using ``postgresql`` for
+ storing leases; in our case it was 11 * 6 = 66.
+
+Lease Caching
+-------------
+
+Clients that attempt multiple renewals in a short period can cause the server to update
+and write to the database frequently, resulting in a performance impact
+on the server. The cache parameters instruct the DHCP server to avoid
+updating leases too frequently, thus avoiding this behavior. Instead,
+the server assigns the same lease (i.e. reuses it) with no
+modifications except for CLTT (Client Last Transmission Time), which
+does not require disk operations.
+
+The two parameters are the ``cache-threshold`` double and the
+``cache-max-age`` integer; they have no default setting, i.e. the lease caching
+feature must be explicitly enabled. These parameters can be configured
+at the global, shared-network, and subnet levels. The subnet level has
+the precedence over the shared-network level, while the global level is used
+as a last resort. For example:
+
+::
+
+ {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1:1::/64",
+ "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ],
+ "cache-threshold": .25,
+ "cache-max-age": 600,
+ "valid-lifetime": 2000,
+ ...
+ }
+ ],
+ ...
+ }
+
+When an already-assigned lease can fulfill a client query:
+
+ - any important change, e.g. for DDNS parameter, hostname, or
+ preferred or valid lifetime reduction, makes the lease not reusable.
+
+ - lease age, i.e. the difference between the creation or last modification
+ time and the current time, is computed (elapsed duration).
+
+ - if ``cache-max-age`` is explicitly configured, it is compared with the lease age;
+ leases that are too old are not reusable. This means that the value 0
+ for ``cache-max-age`` disables the lease cache feature.
+
+ - if ``cache-threshold`` is explicitly configured and is between 0.0 and 1.0,
+ it expresses the percentage of the lease valid lifetime which is
+ allowed for the lease age. Values below and including 0.0 and
+ values greater than 1.0 disable the lease cache feature.
+
+In our example, a lease with a valid lifetime of 2000 seconds can be
+reused if it was committed less than 500 seconds ago. With a lifetime
+of 3000 seconds, a maximum age of 600 seconds applies.
+
+In outbound client responses (e.g. DHCPV6_REPLY messages), the used
+preferred and valid lifetimes are the reusable values, i.e. the
+expiration dates do not change.
+
+.. _host-reservation-v6:
+
+Host Reservations in DHCPv6
+===========================
+
+There are many cases where it is useful to provide a configuration on a
+per-host basis. The most obvious one is to reserve a specific, static
+IPv6 address or/and prefix for exclusive use by a given client (host);
+the returning client receives the same address and/or prefix every time,
+and other clients will never get that address. Host
+reservations are also convenient when a host has specific requirements,
+e.g. a printer that needs additional DHCP options or a cable modem that
+needs specific parameters. Yet another possible use case is to define
+unique names for hosts.
+
+There may be cases when a new reservation has been made for a
+client for an address or prefix currently in use by another client. We
+call this situation a "conflict." These conflicts get resolved
+automatically over time, as described in subsequent sections. Once a
+conflict is resolved, the correct client will receive the reserved
+configuration when it renews.
+
+Host reservations are defined as parameters for each subnet. Each host
+must be identified by either DUID or its hardware/MAC address; see
+:ref:`mac-in-dhcpv6` for details. There
+is an optional ``reservations`` array in the ``subnet6`` structure; each
+element in that array is a structure that holds information about reservations for a
+single host. In particular, the structure has an identifier that
+uniquely identifies a host. In the DHCPv6 context, the identifier is
+usually a DUID, but it can also be a hardware or MAC address. One or more
+addresses or prefixes may also be specified, and it is possible to
+specify a hostname and DHCPv6 options for a given host.
+
+.. note::
+
+ The reserved address must be within the subnet.
+ This does not apply to reserved prefixes.
+
+The following example shows how to reserve addresses and prefixes for
+specific hosts:
+
+::
+
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [ { "pool": "2001:db8:1::/80" } ],
+ "pd-pools": [
+ {
+ "prefix": "2001:db8:1:8000::",
+ "prefix-len": 56,
+ "delegated-len": 64
+ }
+ ],
+ "reservations": [
+ {
+ "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
+ "ip-addresses": [ "2001:db8:1::100" ]
+ },
+ {
+ "hw-address": "00:01:02:03:04:05",
+ "ip-addresses": [ "2001:db8:1::101", "2001:db8:1::102" ]
+ },
+ {
+ "duid": "01:02:03:04:05:06:07:08:09:0A",
+ "ip-addresses": [ "2001:db8:1::103" ],
+ "prefixes": [ "2001:db8:2:abcd::/64" ],
+ "hostname": "foo.example.com"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+This example includes reservations for three different clients. The
+first reservation is for the address 2001:db8:1::100, for a client using
+DUID 01:02:03:04:05:0A:0B:0C:0D:0E. The second reservation is for two
+addresses, 2001:db8:1::101 and 2001:db8:1::102, for a client using MAC
+address 00:01:02:03:04:05. Lastly, address 2001:db8:1::103 and prefix
+2001:db8:2:abcd::/64 are reserved for a client using DUID
+01:02:03:04:05:06:07:08:09:0A. The last reservation also assigns a
+hostname to this client.
+
+DHCPv6 allows a single client to lease multiple addresses and
+multiple prefixes at the same time. Therefore ``ip-addresses`` and
+``prefixes`` are plural and are actually arrays. When the client sends
+multiple IA options (IA_NA or IA_PD), each reserved address or prefix is
+assigned to an individual IA of the appropriate type. If the number of
+IAs of a specific type is lower than the number of reservations of that
+type, the number of reserved addresses or prefixes assigned to the
+client is equal to the number of IA_NAs or IA_PDs sent by the client;
+that is, some reserved addresses or prefixes are not assigned. However,
+they still remain reserved for this client and the server will not
+assign them to any other client. If the number of IAs of a specific type
+sent by the client is greater than the number of reserved addresses or
+prefixes, the server will try to assign all reserved addresses or
+prefixes to the individual IAs and dynamically allocate addresses or
+prefixes to the remaining IAs. If the server cannot assign a reserved
+address or prefix because it is in use, the server will select the next
+reserved address or prefix and try to assign it to the client. If the
+server subsequently finds that there are no more reservations that can
+be assigned to the client at that moment, the server will try to assign
+leases dynamically.
+
+Making a reservation for a mobile host that may visit multiple subnets
+requires a separate host definition in each subnet that host is expected to
+visit. It is not possible to define multiple host definitions with the
+same hardware address in a single subnet. Multiple host definitions with
+the same hardware address are valid if each is in a different subnet.
+The reservation for a given host should include only one identifier,
+either DUID or hardware address; defining both for the same host is
+considered a configuration error.
+
+Adding host reservations incurs a performance penalty. In principle,
+when a server that does not support host reservation responds to a
+query, it needs to check whether there is a lease for a given address
+being considered for allocation or renewal. The server that does
+support host reservation has to perform additional checks: not only
+whether the address is currently used (i.e., if there is a lease for
+it), but also whether the address could be used by someone else (i.e.,
+if there is a reservation for it). That additional check incurs extra
+overhead.
+
+.. _reservation6-types:
+
+Address/Prefix Reservation Types
+--------------------------------
+
+In a typical Kea scenario there is an IPv6 subnet defined, with a certain
+part of it dedicated for dynamic address allocation by the DHCPv6
+server. There may be an additional address space defined for prefix
+delegation. Those dynamic parts are referred to as dynamic pools,
+address and prefix pools, or simply pools. In principle, a host
+reservation can reserve any address or prefix that belongs to the
+subnet. The reservations that specify addresses that belong to
+configured pools are called "in-pool reservations." In contrast, those
+that do not belong to dynamic pools are called "out-of-pool
+reservations." There is no formal difference in the reservation syntax
+and both reservation types are handled uniformly.
+
+Kea supports global host reservations. These are reservations that are
+specified at the global level within the configuration and that do not
+belong to any specific subnet. Kea still matches inbound client
+packets to a subnet as before, but when the subnet's reservation mode is
+set to "global", Kea looks for host reservations only among the
+global reservations defined. Typically, such reservations would be used
+to reserve hostnames for clients which may move from one subnet to
+another.
+
+.. note::
+
+ Global reservations, while useful in certain circumstances, have aspects
+ that must be given due consideration when using them. Please see
+ :ref:`reservation6-conflict` for more details.
+
+.. note::
+
+ Since Kea 1.9.1, reservation mode has been replaced by three
+ boolean flags, ``reservations-global``, ``reservations-in-subnet``
+ and ``reservations-out-of-pool``, which allow the configuration of
+ host reservations both globally and in a subnet. In such cases a subnet
+ host reservation has preference over a global reservation
+ when both exist for the same client.
+
+.. _reservation6-conflict:
+
+Conflicts in DHCPv6 Reservations
+--------------------------------
+
+As reservations and lease information are stored separately, conflicts
+may arise. Consider the following series of events: the server has
+configured the dynamic pool of addresses from the range of 2001:db8::10
+to 2001:db8::20. Host A requests an address and gets 2001:db8::10. Now
+the system administrator decides to reserve address 2001:db8::10 for
+Host B. In general, reserving an address that is currently assigned to
+someone else is not recommended, but there are valid use cases where
+such an operation is warranted.
+
+The server now has a conflict to resolve. If Host B boots up and
+requests an address, the server cannot immediately assign the reserved
+address 2001:db8::10. A naive approach would to be immediately remove
+the lease for Host A and create a new one for Host B. That would not
+solve the problem, though, because as soon as Host B gets the address,
+it will detect that the address is already in use (by Host
+A) and will send a DHCPDECLINE message. Therefore, in this situation,
+the server has to temporarily assign a different address from the
+dynamic pool (not matching what has been reserved) to Host B.
+
+When Host A renews its address, the server will discover that the
+address being renewed is now reserved for someone else - Host B.
+The server will remove the lease for 2001:db8::10, select a
+new address, and create a new lease for it. It will send two addresses
+in its response: the old address, with the lifetime set to 0 to explicitly
+indicate that it is no longer valid; and the new address, with a
+non-zero lifetime. When Host B tries to renew its temporarily assigned address,
+the server will detect that the existing lease does not match the
+reservation, so it will release the current address Host B has and will
+create a new lease matching the reservation. As before, the server will
+send two addresses: the temporarily assigned one with a zero lifetime,
+and the new one that matches the reservation with the proper lifetime set.
+
+This recovery will succeed, even if other hosts attempt to get the
+reserved address. If Host C requests the address 2001:db8::10 after the
+reservation is made, the server will propose a different address.
+
+This recovery mechanism allows the server to fully recover from a case
+where reservations conflict with existing leases; however, this procedure
+takes roughly as long as the value set for ``renew-timer``. The
+best way to avoid such a recovery is not to define new reservations that
+conflict with existing leases. Another recommendation is to use
+out-of-pool reservations; if the reserved address does not belong to a
+pool, there is no way that other clients can get it.
+
+.. note::
+
+ The conflict-resolution mechanism does not work for global
+ reservations. Although the global address reservations feature may be useful
+ in certain settings, it is generally recommended not to use
+ global reservations for addresses. Administrators who do choose
+ to use global reservations must manually ensure that the reserved
+ addresses are not in dynamic pools.
+
+.. _reservation6-hostname:
+
+Reserving a Hostname
+--------------------
+
+When the reservation for a client includes the ``hostname``, the server
+assigns this hostname to the client and sends it back in the Client
+FQDN option, if the client included the Client FQDN option in its message
+to the server. The reserved hostname always takes precedence over the
+hostname supplied by the client (via the FQDN option) or the autogenerated
+(from the IPv6 address) hostname.
+
+The server qualifies the reserved hostname with the value of the
+``ddns-qualifying-suffix`` parameter. For example, the following subnet
+configuration:
+
+::
+
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [ { "pool": "2001:db8:1::/80" } ],
+ "ddns-qualifying-suffix": "example.isc.org.",
+ "reservations": [
+ {
+ "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
+ "ip-addresses": [ "2001:db8:1::100" ],
+ "hostname": "alice-laptop"
+ }
+ ]
+ }
+ ],
+ "dhcp-ddns": {
+ "enable-updates": true
+ },
+ ...
+ }
+
+will result the "alice-laptop.example.isc.org." hostname being assigned to
+the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the
+``ddns-qualifying-suffix`` is not specified, the default (empty) value will
+be used, and in this case the value specified as a ``hostname`` will be
+treated as a fully qualified name. Thus, by leaving the
+``ddns-qualifying-suffix`` empty it is possible to qualify hostnames for
+different clients with different domain names:
+
+.. code-block:: json
+
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [ { "pool": "2001:db8:1::/80" } ],
+ "reservations": [
+ {
+ "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
+ "ip-addresses": [ "2001:db8:1::100" ],
+ "hostname": "mark-desktop.example.org."
+ }
+ ]
+ }
+ ],
+ "dhcp-ddns": {
+ "enable-updates": true
+ }
+ }
+
+The above example results in the assignment of the
+"mark-desktop.example.org." hostname to the client using the DUID
+"01:02:03:04:05:0A:0B:0C:0D:0E".
+
+.. _reservation6-options:
+
+Including Specific DHCPv6 Options in Reservations
+-------------------------------------------------
+
+Kea offers the ability to specify options on a per-host basis. These
+options follow the same rules as any other options. These can be
+standard options (see :ref:`dhcp6-std-options`),
+custom options (see :ref:`dhcp6-custom-options`),
+or vendor-specific options (see :ref:`dhcp6-vendor-opts`). The following
+example demonstrates how standard options can be defined.
+
+::
+
+ {
+ "reservations": [
+ {
+ "duid": "01:02:03:05:06:07:08",
+ "ip-addresses": [ "2001:db8:1::2" ],
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "3000:1::234"
+ },
+ {
+ "name": "nis-servers",
+ "data": "3000:1::234"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Vendor-specific options can be reserved in a similar manner:
+
+::
+
+ {
+ "reservations": [
+ {
+ "duid": "aa:bb:cc:dd:ee:ff",
+ "ip-addresses": [ "2001:db8::1" ],
+ "option-data": [
+ {
+ "name": "vendor-opts",
+ "data": 4491
+ },
+ {
+ "name": "tftp-servers",
+ "space": "vendor-4491",
+ "data": "3000:1::234"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Options defined at the host level have the highest priority. In other words,
+if there are options defined with the same type on global, subnet,
+class, and host levels, the host-specific values are used.
+
+.. _reservation6-client-classes:
+
+Reserving Client Classes in DHCPv6
+----------------------------------
+
+:ref:`classification-using-expressions` explains how to configure
+the server to assign classes to a client, based on the content of the
+options that this client sends to the server. Host reservation
+mechanisms also allow for the static assignment of classes to clients.
+The definitions of these classes are placed in the Kea configuration file or
+a database. The following configuration snippet shows how to specify that
+a client belongs to the classes ``reserved-class1`` and ``reserved-class2``. Those
+classes are associated with specific options sent to the clients which belong
+to them.
+
+::
+
+ {
+ "client-classes": [
+ {
+ "name": "reserved-class1",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::50"
+ }
+ ]
+ },
+ {
+ "name": "reserved-class2",
+ "option-data": [
+ {
+ "name": "nis-servers",
+ "data": "2001:db8:1::100"
+ }
+ ]
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [ { "pool": "2001:db8:1::/64" } ],
+ "subnet": "2001:db8:1::/48",
+ "reservations": [
+ {
+ "duid": "01:02:03:04:05:06:07:08",
+
+ "client-classes": [ "reserved-class1", "reserved-class2" ]
+
+ }
+ ]
+ } ]
+ }
+
+In some cases the host reservations can be used in conjunction with client
+classes specified within the Kea configuration. In particular, when a
+host reservation exists for a client within a given subnet, the "KNOWN"
+built-in class is assigned to the client. Conversely, when there is no
+static assignment for the client, the "UNKNOWN" class is assigned to the
+client. Class expressions within the Kea configuration file can
+refer to "KNOWN" or "UNKNOWN" classes using the "member" operator.
+For example:
+
+::
+
+ {
+ "client-classes": [
+ {
+ "name": "dependent-class",
+ "test": "member('KNOWN')",
+ "only-if-required": true
+ }
+ ]
+ }
+
+The ``only-if-required`` parameter is needed here to force
+evaluation of the class after the lease has been allocated and thus the
+reserved class has been also assigned.
+
+.. note::
+
+ The classes specified in non-global host reservations
+ are assigned to the processed packet after all classes with the
+ ``only-if-required`` parameter set to ``false`` have been evaluated.
+ This means that these classes must not depend on the
+ statically assigned classes from the host reservations. If
+ such a dependency is needed, the ``only-if-required`` must
+ be set to ``true`` for the dependent classes. Such classes are
+ evaluated after the static classes have been assigned to the packet.
+ This, however, imposes additional configuration overhead, because
+ all classes marked as ``only-if-required`` must be listed in the
+ ``require-client-classes`` list for every subnet where they are used.
+
+.. note::
+
+ Client classes specified within the Kea configuration file may
+ depend on the classes specified within the global host reservations.
+ In such a case the ``only-if-required`` parameter is not needed.
+ Refer to the :ref:`pool-selection-with-class-reservations6` and
+ :ref:`subnet-selection-with-class-reservations6`
+ for specific use cases.
+
+.. _reservations6-mysql-pgsql:
+
+Storing Host Reservations in MySQL or PostgreSQL
+------------------------------------------------
+
+Kea can store host reservations in MySQL or PostgreSQL.
+See :ref:`hosts6-storage` for information on how to
+configure Kea to use reservations stored in MySQL or PostgreSQL.
+Kea provides a dedicated hook for managing reservations in a
+database; section :ref:`hooks-host-cmds` provides detailed information.
+The `Kea wiki
+<https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands#23-host-reservations-hr-management>`__
+provides some examples of how to conduct common host reservation
+operations.
+
+.. note::
+
+ In Kea, the maximum length of an option specified per-host is
+ arbitrarily set to 4096 bytes.
+
+.. _reservations6-tuning:
+
+Fine-Tuning DHCPv6 Host Reservation
+-----------------------------------
+
+The host reservation capability introduces additional restrictions for
+the allocation engine (the component of Kea that selects an address for
+a client) during lease selection and renewal. In particular, three major
+checks are necessary. First, when selecting a new lease, it is not
+sufficient for a candidate lease to simply not be in use by another DHCP
+client; it also must not be reserved for another client. Similarly, when
+renewing a lease, an additional check must be performed to see whether
+the address being renewed is reserved for another client. Finally, when
+a host renews an address or a prefix, the server must check whether
+there is a reservation for this host, which would mean the existing (dynamically
+allocated) address should be revoked and the reserved one be used
+instead.
+
+Some of those checks may be unnecessary in certain deployments, and not
+performing them may improve performance. The Kea server provides the
+``reservation-mode`` configuration parameter to select the types of
+reservations allowed for a particular subnet. Each reservation type has
+different constraints for the checks to be performed by the server when
+allocating or renewing a lease for the client. Allowed values are:
+
+- ``all`` - enables both in-pool and out-of-pool host reservation
+ types. This setting is the default value, and is the safest and most
+ flexible. However, as all checks are conducted, it is also the slowest.
+ It does not check against global reservations.
+
+- ``out-of-pool`` - allows only out-of-pool host reservations. With
+ this setting in place, the server assumes that all host
+ reservations are for addresses that do not belong to the dynamic
+ pool. Therefore, it can skip the reservation checks when dealing with
+ in-pool addresses, thus improving performance. Do not use this mode
+ if any reservations use in-pool addresses. Caution is advised
+ when using this setting; Kea does not sanity-check the reservations
+ against ``reservation-mode`` and misconfiguration may cause problems.
+
+- ``global`` - allows only global host reservations. With this setting
+ in place, the server searches for reservations for a client only
+ among the defined global reservations. If an address is specified,
+ the server skips the reservation checks carried out in
+ other modes, thus improving performance. Caution is advised when
+ using this setting; Kea does not sanity-check the reservations when
+ ``global`` is set, and misconfiguration may cause problems.
+
+- ``disabled`` - host reservation support is disabled. As there are no
+ reservations, the server skips all checks. Any reservations
+ defined are completely ignored. As checks are skipped, the
+ server may operate faster in this mode.
+
+Since Kea 1.9.1, the ``reservation-mode`` parameter is replaced by the
+``reservations-global``, ``reservations-in-subnet`` and
+``reservations-out-of-pool`` flags.
+The flags can be activated independently and can produce various combinations,
+some of them being unsupported by the deprecated ``reservation-mode``.
+
+The ``reservation-mode`` parameter can be specified at:
+
+- global level: ``.Dhcp6["reservation-mode"]`` (lowest priority: gets overridden
+ by all others)
+
+- subnet level: ``.Dhcp6.subnet6[]["reservation-mode"]`` (low priority)
+
+- shared-network level: ``.Dhcp6["shared-networks"][]["reservation-mode"]``
+ (high priority)
+
+- shared-network subnet-level:
+ ``.Dhcp6["shared-networks"][].subnet6[]["reservation-mode"]`` (highest
+ priority: overrides all others)
+
+To decide which ``"reservation-mode"`` to choose, the
+following decision diagram may be useful:
+
+::
+
+ O
+ |
+ v
+ +-----------------------------+------------------------------+
+ | Is per-host configuration needed, such as |
+ | reserving specific addresses, |
+ | assigning specific options or |
+ | assigning packets to specific classes on per-device basis? |
+ +-+-----------------+----------------------------------------+
+ | |
+ no| yes|
+ | | +--------------------------------------+
+ | | | For all given hosts, |
+ +--> "disabled" +-->+ can the reserved resources |
+ | be used in all configured subnets? |
+ +--------+---------------------------+-+
+ | |
+ +----------------------------+ |no |yes
+ | Is | | |
+ | at least one reservation +<--+ "global" <--+
+ | used to reserve addresses |
+ | or prefixes? |
+ +-+------------------------+-+
+ | |
+ no| yes| +---------------------------+
+ | | | Is high leases-per-second |
+ +--> "out-of-pool" +-->+ performance or efficient |
+ ^ | resource usage |
+ | | (CPU ticks, RAM usage, |
+ | | database roundtrips) |
+ | | important to your setup? |
+ | +-+----------------+--------+
+ | | |
+ | yes| no|
+ | | |
+ | +-------------+ |
+ | | |
+ | | +----------------------+ |
+ | | | Can it be guaranteed | |
+ | +-->+ that the reserved | |
+ | | addresses/prefixes | |
+ | | aren't part of the | |
+ | | pools configured | |
+ | | in the respective | |
+ | | subnet? | |
+ | +-+------------------+-+ |
+ | | | |
+ | yes| no| |
+ | | | V
+ +----------------+ +--> "all"
+
+An example configuration that disables reservations looks as follows:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::100"
+ }
+ ],
+ "reservation-mode": "disabled",
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+An example configuration using global reservations is shown below:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservation-mode": "global",
+ "reservations": [
+ {
+ "duid": "00:03:00:01:11:22:33:44:55:66",
+ "hostname": "host-one"
+ },
+ {
+ "duid": "00:03:00:01:99:88:77:66:55:44",
+ "hostname": "host-two"
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::100"
+ }
+ ],
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+The meaning of the reservation flags are:
+
+- ``reservations-global``: fetch global reservations.
+
+- ``reservations-in-subnet``: fetch subnet reservations. For a shared network
+ this includes all subnet members of the shared network.
+
+- ``reservations-out-of-pool``: this makes sense only when the
+ ``reservations-in-subnet`` flag is ``true``. When ``reservations-out-of-pool``
+ is ``true``, the server assumes that all host reservations are for addresses
+ that do not belong to the dynamic pool. Therefore, it can skip the reservation
+ checks when dealing with in-pool addresses, thus improving performance.
+ The server will not assign reserved addresses that are inside the dynamic
+ pools to the respective clients. This also means that the addresses matching
+ the respective reservations from inside the dynamic pools (if any) can be
+ dynamically assigned to any client.
+
+The ``disabled`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": false,
+ "reservations-in-subnet": false
+ }
+ }
+
+The ``global`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": true,
+ "reservations-in-subnet": false
+ }
+ }
+
+The ``out-of-pool`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": false,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": true
+ }
+ }
+
+And the ``all`` value from the deprecated ``reservation-mode`` corresponds to:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": false,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": false
+ }
+ }
+
+To activate both ``global`` and ``all``, the following combination can be used:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": true,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": false
+ }
+ }
+
+To activate both ``global`` and ``out-of-pool``, the following combination can
+be used:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations-global": true,
+ "reservations-in-subnet": true,
+ "reservations-out-of-pool": true
+ }
+ }
+
+Enabling ``out-of-pool`` and disabling ``in-subnet`` at the same time
+is not recommended because ``out-of-pool`` applies to host reservations in a
+subnet, which are fetched only when the ``in-subnet`` flag is ``true``.
+
+The parameter can be specified at the global, subnet, and shared-network
+levels.
+
+An example configuration that disables reservations looks as follows:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "reservations-global": false,
+ "reservations-in-subnet": false,
+ "subnet": "2001:db8:1::/64",
+ "id": 1
+ }
+ ]
+ }
+ }
+
+An example configuration using global reservations is shown below:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "reservations": [
+ {
+ "duid": "00:03:00:01:11:22:33:44:55:66",
+ "hostname": "host-one"
+ },
+ {
+ "duid": "00:03:00:01:99:88:77:66:55:44",
+ "hostname": "host-two"
+ }
+ ],
+ "reservations-global": true,
+ "reservations-in-subnet": false,
+ "subnet6": [
+ {
+ "pools": [
+ {
+ "pool": "2001:db8:1::-2001:db8:1::100"
+ }
+ ],
+ "subnet": "2001:db8:1::/64",
+ "id": 1
+ }
+ ]
+ }
+ }
+
+For more details regarding global reservations, see :ref:`global-reservations6`.
+
+Another aspect of host reservations is the different types of
+identifiers. Kea currently supports two types of identifiers in DHCPv6:
+hardware address and DUID. This is beneficial from a usability
+perspective; however, there is one drawback. For each incoming packet
+Kea has to extract each identifier type and then query the database
+to see if there is a reservation by this particular identifier. If
+nothing is found, the next identifier is extracted and the next query is
+issued. This process continues until either a reservation is found or
+all identifier types have been checked. Over time, with an increasing
+number of supported identifier types, Kea would become slower and
+slower.
+
+To address this problem, a parameter called
+``host-reservation-identifiers`` is available. It takes a list of
+identifier types as a parameter. Kea checks only those identifier
+types enumerated in ``host-reservation-identifiers``. From a performance
+perspective, the number of identifier types should be kept to a minimum,
+ideally one. If the deployment uses several reservation types, please
+enumerate them from most- to least-frequently used, as this increases
+the chances of Kea finding the reservation using the fewest queries. An
+example of a ``host-reservation-identifiers`` configuration looks as follows:
+
+::
+
+ {
+ "host-reservation-identifiers": [ "duid", "hw-address" ],
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ ...
+ }
+ ],
+ ...
+ }
+
+If not specified, the default value is:
+
+::
+
+ "host-reservation-identifiers": [ "hw-address", "duid" ]
+
+.. note::
+
+ As soon as a host reservation is found the search is stopped so
+ when a client has two host reservations using different enabled
+ identifier types the first is always returned and the second
+ ignored. In other words, this is usually a configuration mistake.
+ In rare cases when having two reservations for the same host makes sense,
+ you can control which of those will be used by ordering the list of
+ identifier types in `host-reservation-identifiers`.
+
+
+.. _global-reservations6:
+
+Global Reservations in DHCPv6
+-----------------------------
+
+In some deployments, such as mobile, clients can roam within the network
+and certain parameters must be specified regardless of the client's
+current location. To meet such a need, Kea offers a global reservation
+mechanism. The idea behind it is that regular host
+reservations are tied to specific subnets, by using a specific
+subnet ID. Kea can specify a global reservation that can be used in
+every subnet that has global reservations enabled.
+
+This feature can be used to assign certain parameters, such as hostname
+or other dedicated, host-specific options. It can also be used to assign
+addresses or prefixes.
+
+An address assigned via global host reservation must be feasible for the
+subnet the server selects for the client. In other words, the address must
+lie within the subnet; otherwise, it is ignored and the server will
+attempt to dynamically allocate an address. If the selected subnet
+belongs to a shared network, the server checks for feasibility against
+the subnet's siblings, selecting the first in-range subnet. If no such
+subnet exists, the server falls back to dynamically allocating the address.
+This does not apply to globally reserved prefixes.
+
+.. note::
+
+ Prior to release 2.3.5, the server did not perform feasibility checks on
+ globally reserved addresses, which allowed the server to be configured to
+ hand out nonsensical leases for arbitrary address values. Later versions
+ of Kea perform these checks.
+
+To use global host reservations, a configuration similar to the
+following can be used:
+
+::
+
+ "Dhcp6": {
+ # This specifies global reservations.
+ # They will apply to all subnets that
+ # have global reservations enabled.
+
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ "hostname": "hw-host-dynamic"
+ },
+ {
+ "hw-address": "01:02:03:04:05:06",
+ "hostname": "hw-host-fixed",
+
+ # Use of IP addresses in global reservations is risky.
+ # If used outside of matching subnet, such as 3001::/64,
+ # it will result in a broken configuration being handed
+ # to the client.
+ "ip-address": "2001:db8:ff::77"
+ },
+ {
+ "duid": "01:02:03:04:05",
+ "hostname": "duid-host"
+ }
+ ],
+ "valid-lifetime": 600,
+ "subnet4": [ {
+ "subnet": "2001:db8:1::/64",
+ # It is replaced by the "reservations-global",
+ # "reservations-in-subnet", and "reservations-out-of-pool"
+ # parameters.
+ # "reservation-mode": "global",
+ # Specify if the server should look up global reservations.
+ "reservations-global": true,
+ # Specify if the server should look up in-subnet reservations.
+ "reservations-in-subnet": false,
+ # Specify if the server can assume that all reserved addresses
+ # are out-of-pool. It can be ignored because "reservations-in-subnet"
+ # is false.
+ # "reservations-out-of-pool": false,
+ "pools": [ { "pool": "2001:db8:1::-2001:db8:1::100" } ]
+ } ]
+ }
+
+When using database backends, the global host reservations are
+distinguished from regular reservations by using a ``subnet-id`` value of
+0.
+
+.. _pool-selection-with-class-reservations6:
+
+Pool Selection with Client Class Reservations
+---------------------------------------------
+
+Client classes can be specified both in the Kea configuration file and/or
+via host reservations. The classes specified in the Kea configuration file are
+evaluated immediately after receiving the DHCP packet and therefore can be
+used to influence subnet selection using the ``client-class`` parameter
+specified in the subnet scope. The classes specified within the host
+reservations are fetched and assigned to the packet after the server has
+already selected a subnet for the client. This means that the client
+class specified within a host reservation cannot be used to influence
+subnet assignment for this client, unless the subnet belongs to a
+shared network. If the subnet belongs to a shared network, the server may
+dynamically change the subnet assignment while trying to allocate a lease.
+If the subnet does not belong to a shared network, once selected, the subnet
+is not changed once selected.
+
+If the subnet does not belong to a shared network, it is possible to
+use host reservation-based client classification to select an address pool
+within the subnet as follows:
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "reserved_class"
+ },
+ {
+ "name": "unreserved_class",
+ "test": "not member('reserved_class')"
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:fe",
+ "client-classes": [ "reserved_class" ]
+ }
+ ],
+ "pools": [
+ {
+ "pool": "2001:db8:1::10-2001:db8:1::20",
+ "client-class": "reserved_class"
+ },
+ {
+ "pool": "2001:db8:1::30-2001:db8:1::40",
+ "client-class": "unreserved_class"
+ }
+ ]
+ }
+ ]
+ }
+
+The ``reserved_class`` is declared without the ``test`` parameter because
+it may be only assigned to the client via host reservation mechanism. The
+second class, ``unreserved_class``, is assigned to clients which do not
+belong to the ``reserved_class``. The first pool within the subnet is only
+used for clients having a reservation for the ``reserved_class``. The
+second pool is used for clients not having such a reservation. The
+configuration snippet includes one host reservation which causes the client
+with the MAC address aa:bb:cc:dd:ee:fe to be assigned to the
+``reserved_class``. Thus, this client will be given an IP address from the
+first address pool.
+
+.. _subnet-selection-with-class-reservations6:
+
+Subnet Selection with Client Class Reservations
+-----------------------------------------------
+
+There is one specific use case when subnet selection may be influenced by
+client classes specified within host reservations: when the
+client belongs to a shared network. In such a case it is possible to use
+classification to select a subnet within this shared network. Consider the
+following example:
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "reserved_class"
+ },
+ {
+ "name": "unreserved_class",
+ "test": "not member('reserved_class')"
+ }
+ ],
+ "reservations": [
+ {
+ "hw-address": "aa:bb:cc:dd:ee:fe",
+ "client-classes": [ "reserved_class" ]
+ }
+ ],
+ # It is replaced by the "reservations-global",
+ # "reservations-in-subnet", and "reservations-out-of-pool" parameters.
+ # Specify if the server should look up global reservations.
+ "reservations-global": true,
+ # Specify if the server should look up in-subnet reservations.
+ "reservations-in-subnet": false,
+ # Specify if the server can assume that all reserved addresses
+ # are out-of-pool. It can be ignored because "reservations-in-subnet"
+ # is false, but if specified, it is inherited by "shared-networks"
+ # and "subnet6" levels.
+ # "reservations-out-of-pool": false,
+ "shared-networks": [
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::10-2001:db8:1::20",
+ "client-class": "reserved_class"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:2::10-2001:db8:2::20",
+ "client-class": "unreserved_class"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+This is similar to the example described in the
+:ref:`pool-selection-with-class-reservations6`. This time, however, there
+are two subnets, each of which has a pool associated with a different
+class. The clients that do not have a reservation for the ``reserved_class``
+are assigned an address from the subnet 2001:db8:2::/64. Clients with
+a reservation for the ``reserved_class`` are assigned an address from
+the subnet 2001:db8:1::/64. The subnets must belong to the same shared network.
+In addition, the reservation for the client class must be specified at the
+global scope (global reservation) and ``reservations-global`` must be
+set to ``true``.
+
+In the example above, the ``client-class`` could also be specified at the
+subnet level rather than the pool level, and would yield the same effect.
+
+.. _multiple-reservations-same-ip6:
+
+Multiple Reservations for the Same IP
+-------------------------------------
+
+Host reservations were designed to preclude the creation of multiple
+reservations for the same IP address or delegated prefix within a
+particular subnet, to avoid having two different clients
+compete for the same lease. When using the default settings, the server
+returns a configuration error when it finds two or more reservations for
+the same lease within a subnet in the Kea configuration file.
+:ischooklib:`libdhcp_host_cmds.so` returns an error in response to the
+:isccmd:`reservation-add` command when it detects that the reservation exists
+in the database for the lease for which the new reservation is being added.
+
+Similar to DHCPv4 (see :ref:`multiple-reservations-same-ip4`), the DHCPv6
+server can also be configured to allow the creation of multiple reservations
+for the same IPv6 address and/or delegated prefix in a given subnet. This
+is supported since Kea release 1.9.1 as an optional mode of operation
+enabled with the ``ip-reservations-unique`` global parameter.
+
+The ``ip-reservations-unique`` is a boolean parameter that defaults to
+``true``, which forbids the specification of more than one reservation
+for the same lease in a given subnet. Setting this parameter to ``false``
+allows such reservations to be created both in the Kea configuration
+file and in the host database backend, via :ischooklib:`libdhcp_host_cmds.so`.
+
+Setting ``ip-reservations-unique`` to ``false`` when using memfile, MySQL or PostgreSQL is supported.
+This setting is not supported when using Host Cache (see :ref:`hooks-host-cache`), and the RADIUS backend
+(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the
+same IP. If either of these hooks are loaded and ``ip-reservations-unique`` is set to ``false``, then a
+configuration error will be emitted and the server will fail to start.
+
+.. note::
+
+ When ``ip-reservations-unique`` is set to ``true`` (the default value),
+ the server ensures that IP reservations are unique for a subnet within
+ a single host backend and/or Kea configuration file. It does not
+ guarantee that the reservations are unique across multiple backends.
+ On server startup, only IP reservations defined in the Kea configuration
+ file are checked for uniqueness.
+
+
+The following is an example configuration with two reservations for
+the same IPv6 address but different MAC addresses:
+
+::
+
+ "Dhcp6": {
+ "ip-reservations-unique": false,
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "reservations": [
+ {
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "ip-address": "2001:db8:1::11"
+ },
+ {
+ "hw-address": "2a:2b:2c:2d:2e:2f",
+ "ip-address": "2001:db8:1::11"
+ }
+ ]
+ }
+ ]
+ }
+
+It is possible to control the ``ip-reservations-unique`` parameter via the
+:ref:`dhcp6-cb`. If the new setting of this parameter conflicts with
+the currently used backends (i.e. backends do not support the new setting),
+the new setting is ignored and a warning log message is generated.
+The backends continue to use the default setting, expecting that
+IP reservations are unique within each subnet. To allow the
+creation of non-unique IP reservations, the administrator must remove
+the backends which lack support for them from the configuration file.
+
+Administrators must be careful when they have been using multiple
+reservations for the same IP address and/or delegated prefix and later
+decide to return to the default mode in which this is no longer allowed.
+They must make sure that at most one reservation for
+a given IP address or delegated prefix exists within a subnet, prior
+to switching back to the default mode. If such duplicates are left in
+the configuration file, the server reports a configuration error.
+Leaving such reservations in the host databases does not cause
+configuration errors but may lead to lease allocation errors during
+the server's operation, when it unexpectedly finds multiple reservations
+for the same IP address or delegated prefix.
+
+.. note::
+
+ Currently the Kea server does not verify whether multiple reservations for
+ the same IP address and/or delegated prefix exist in
+ MySQL and/or PostgreSQL) host databases when ``ip-reservations-unique``
+ is updated from ``false`` to ``true``. This may cause issues with
+ lease allocations. The administrator must ensure that there is at
+ most one reservation for each IP address and/or delegated prefix
+ within each subnet, prior to the configuration update.
+
+The ``reservations-lookup-first`` is a boolean parameter which controls whether
+host reservations lookup should be performed before lease lookup. This parameter
+has effect only when multi-threading is disabled. When multi-threading is
+enabled, host reservations lookup is always performed first to avoid lease-lookup
+resource locking. The ``reservations-lookup-first`` parameter defaults to ``false``
+when multi-threading is disabled.
+
+.. _host_reservations_as_basic_access_control6:
+
+Host Reservations as Basic Access Control
+-----------------------------------------
+
+Starting with Kea 2.3.5, it is possible to define a host reservation that
+contains just an identifier, without any address, options, or values. In some
+deployments this is useful, as the hosts that have a reservation belong to
+the KNOWN class while others do not. This can be used as a basic access control
+mechanism.
+
+The following example demonstrates this concept. It indicates a single IPv6 subnet
+and all clients will get an address from it. However, only known clients (those that
+have reservations) will get their default DNS server configured. Empty reservations
+i.e. reservations that only have the identification criterion, can be
+specifically useful in this regard of making the clients known.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "KNOWN",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::1"
+ }
+ ]
+ }
+ ],
+ "reservations": [
+ // Clients on this list will be added to the KNOWN class.
+ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E" },
+ { "duid": "02:03:04:05:0A:0B:0C:0D:0E:0F" }
+ ],
+ "reservations-in-subnet": true,
+
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [
+ {
+ "pool": "2001:db8:1:1::/64"
+ }
+ ]
+ }
+ ]
+ }
+
+This concept can be extended further. A good real-life scenario might be a
+situation where some customers of an ISP have not paid their bills. A new class can be
+defined to use an alternative default DNS server that, instead of giving access
+to the Internet, redirects those customers to a captive portal urging them to bring
+their accounts up to date.
+
+::
+
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "blocked",
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::2"
+ }
+ ]
+ }
+ ],
+ "reservations": [
+ // Clients on this list will be added to the KNOWN class. Some
+ // will also be added to the blocked class.
+ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
+ "client-classes": [ "blocked" ] },
+ { "duid": "02:03:04:05:0A:0B:0C:0D:0E:0F" }
+ ],
+ "reservations-in-subnet": true,
+
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [
+ {
+ "pool": "2001:db8:1:1::/64"
+ }
+ ],
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::1"
+ }
+ ]
+ }
+ ]
+ }
+
+.. _shared-network6:
+
+Shared Networks in DHCPv6
+=========================
+
+DHCP servers use subnet information in two ways. It is used to
+both determine the point of attachment, i.e. where the client is
+connected to the network, and to
+group information pertaining to a specific location in the network.
+Sometimes it is useful to have more than one
+logical IP subnet being deployed on the same physical link.
+Understanding that two or more subnets are used on the same link requires
+additional logic in the DHCP server. This capability is called "shared
+networks" in Kea, and sometimes also
+"shared subnets"; in Microsoft's nomenclature it is called
+"multinet."
+
+There are many cases where the shared networks feature is useful; here we explain
+just a handful of the most common ones. The first and by far most common
+use case is an existing IPv4 network that has grown and
+is running out of available
+address space. This is less common in IPv6, but shared networks
+are still useful: for example, with the exhaustion of IPv6-
+delegated prefixes within a subnet, or the desire to
+experiment with an addressing scheme. With the advent of IPv6 deployment
+and a vast address space, many organizations split the address space
+into subnets, deploy it, and then after a while discover that they want
+to split it differently. In the transition period, they want both the old
+and new addressing to be available: thus the need for more than one
+subnet on the same physical link.
+
+Finally, the case of cable networks is directly applicable in IPv6.
+There are two types of devices in cable networks: cable modems and the
+end-user devices behind them. It is a common practice to use different
+subnets for cable modems to prevent users from tinkering with them. In
+this case, the distinction is based on the type of device, rather than
+on address-space exhaustion.
+
+A client connected to a shared network may be assigned a lease (address
+or prefix) from any of the pools defined within the subnets belonging to
+the shared network. Internally, the server selects one of the subnets
+belonging to a shared network and tries to allocate a lease from this
+subnet. If the server is unable to allocate a lease from the selected
+subnet (e.g., due to pool exhaustion), it uses another subnet from
+the same shared network and tries to allocate a lease from this subnet.
+The server typically allocates all leases
+available in a given subnet before it starts allocating leases from
+other subnets belonging to the same shared network. However, in certain
+situations the client can be allocated a lease from another subnet
+before the pools in the first subnet get exhausted; this sometimes occurs
+when the client provides a hint that belongs to another subnet, or the client has
+reservations in a subnet other than the default.
+
+.. note::
+
+ Deployments should not assume that Kea waits until it has allocated
+ all the addresses from the first subnet in a shared network before
+ allocating addresses from other subnets.
+
+To define a shared network, an additional configuration scope is
+introduced:
+
+::
+
+ {
+ "Dhcp6": {
+ "shared-networks": [
+ {
+ # Name of the shared network. It may be an arbitrary string
+ # and it must be unique among all shared networks.
+ "name": "ipv6-lab-1",
+
+ # The subnet selector can be specified on the shared network
+ # level. Subnets from this shared network will be selected
+ # for clients communicating via relay agent having
+ # the specified IP address.
+ "relay": {
+ "ip-addresses": [ "2001:db8:2:34::1" ]
+ },
+
+ # This starts a list of subnets in this shared network.
+ # There are two subnets in this example.
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/48",
+ "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "3ffe:ffe::/64",
+ "pools": [ { "pool": "3ffe:ffe::/64" } ]
+ }
+ ]
+ }
+ ],
+ # end of shared-networks
+
+ # It is likely that in the network there will be a mix of regular,
+ # "plain" subnets and shared networks. It is perfectly valid
+ # to mix them in the same configuration file.
+ #
+ # This is a regular subnet. It is not part of any shared-network.
+ "subnet6": [
+ {
+ "id": 3,
+ "subnet": "2001:db9::/48",
+ "pools": [ { "pool": "2001:db9::/64" } ],
+ "relay": {
+ "ip-addresses": [ "2001:db8:1:2::1" ]
+ }
+ }
+ ]
+ }
+ }
+
+As demonstrated in the example, it is possible to mix shared and regular
+("plain") subnets. Each shared network must have a unique name. This is
+similar to the ID for subnets, but gives administrators more
+flexibility. It is used for logging, but also internally for
+identifying shared networks.
+
+In principle it makes sense to define only shared networks that consist
+of two or more subnets. However, for testing purposes, an empty subnet
+or a network with just a single subnet is allowed. This
+is not a recommended practice in production networks, as the shared
+network logic requires additional processing and thus lowers the
+server's performance. To avoid unnecessary performance degradation,
+shared subnets should only be defined when required by the deployment.
+
+Shared networks provide an ability to specify many parameters in the
+shared network scope that apply to all subnets within it. If
+necessary, it is possible to specify a parameter in the shared-network scope and
+then override its value in the subnet scope. For example:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "lab-network3",
+ "relay": {
+ "ip-addresses": [ "2001:db8:2:34::1" ]
+ },
+
+ # This applies to all subnets in this shared network, unless
+ # values are overridden on subnet scope.
+ "valid-lifetime": 600,
+
+ # This option is made available to all subnets in this shared
+ # network.
+ "option-data": [ {
+ "name": "dns-servers",
+ "data": "2001:db8::8888"
+ } ],
+
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/48",
+ "pools": [ { "pool": "2001:db8:1::1 - 2001:db8:1::ffff" } ],
+
+ # This particular subnet uses different values.
+ "valid-lifetime": 1200,
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8::1:2"
+ },
+ {
+ "name": "unicast",
+ "data": "2001:abcd::1"
+ } ]
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/48",
+ "pools": [ { "pool": "2001:db8:2::1 - 2001:db8:2::ffff" } ],
+
+ # This subnet does not specify its own valid-lifetime value,
+ # so it is inherited from shared network scope.
+ "option-data": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:cafe::1"
+ } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+In this example, there is a ``dns-servers`` option defined that is available
+to clients in both subnets in this shared network. Also, the valid
+lifetime is set to 10 minutes (600s). However, the first subnet
+overrides some of the values (the valid lifetime is 20 minutes, there is a different IP
+address for ``dns-servers``), but also adds its own option (the unicast
+address). Assuming a client asking for server unicast and ``dns-servers``
+options is assigned a lease from this subnet, it will get a lease for 20
+minutes and ``dns-servers``, and be allowed to use server unicast at address
+2001:abcd::1. If the same client is assigned to the second subnet, it
+will get a 10-minute lease, a ``dns-servers`` value of 2001:db8:cafe::1, and
+no server unicast.
+
+Some parameters must be the same in all subnets in the same shared
+network. This restriction applies to the ``interface`` and
+``rapid-commit`` settings. The most convenient way is to define them on
+the shared-network scope, but they can be specified for each subnet.
+However, each subnet must have the same value.
+
+.. note::
+
+ There is an inherent ambiguity when using clients that send multiple IA
+ options in a single request, and shared-networks whose subnets have
+ different values for options and configuration parameters. The server
+ sequentially processes IA options in the order that they occur in the
+ client's query; if the leases requested in the IA options end up being
+ fulfilled from different subnets, which parameters and options should
+ apply? Currently, the code uses the values from the last subnet of
+ the last IA option fulfilled.
+
+ We view this largely as a site configuration issue. A shared network
+ generally means the same physical link, so services configured by options
+ from subnet A should be as easily reachable from subnet B and vice versa.
+ There are a number of ways to avoid this situation:
+
+ - Use the same values for options and parameters for subnets within the shared network.
+ - Use subnet selectors or client class guards that ensure that for a single client's query, the same subnet is used for all IA options in that query.
+ - Avoid using shared networks with clients that send multiple IA options per query.
+
+Local and Relayed Traffic in Shared Networks
+--------------------------------------------
+
+It is possible to specify an interface name at the shared-network level,
+to tell the server that this specific shared network is reachable
+directly (not via relays) using the local network interface. As all
+subnets in a shared network are expected to be used on the same physical
+link, it is a configuration error to attempt to define a shared network
+using subnets that are reachable over different interfaces. In other
+words, all subnets within the shared network must have the same value
+for the ``interface`` parameter. The following configuration is an example
+of what **NOT** to do:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "office-floor-2",
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ],
+ "interface": "eth0"
+ },
+ {
+ "id": 2,
+ "subnet": "3ffe:abcd::/64",
+ "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ],
+ ...
+ # Specifying a different interface name is a configuration
+ # error. This value should rather be "eth0" or the interface
+ # name in the other subnet should be "eth1".
+ # "interface": "eth1"
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+To minimize the chance of configuration errors, it is often more convenient
+to simply specify the interface name once, at the shared-network level, as
+shown in the example below.
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "office-floor-2",
+
+ # This tells Kea that the whole shared network is reachable over a
+ # local interface. This applies to all subnets in this network.
+ "interface": "eth0",
+
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "3ffe:abcd::/64",
+ "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+
+With relayed traffic, subnets are typically selected using
+the relay agents' addresses. If the subnets are used independently (not
+grouped within a shared network), a different relay
+address can be specified for each of these subnets. When multiple subnets belong to a
+shared network they must be selected via the same relay address and,
+similarly to the case of the local traffic described above, it is a
+configuration error to specify different relay addresses for the respective
+subnets in the shared network. The following configuration is another example
+of what **NOT** to do:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "kakapo",
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "relay": {
+ "ip-addresses": [ "2001:db8::1234" ]
+ },
+ "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "3ffe:abcd::/64",
+ "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ],
+ "relay": {
+ # Specifying a different relay address for this
+ # subnet is a configuration error. In this case
+ # it should be 2001:db8::1234 or the relay address
+ # in the previous subnet should be 3ffe:abcd::cafe.
+ "ip-addresses": [ "3ffe:abcd::cafe" ]
+ }
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+Again, it is better to specify the relay address at the shared-network
+level; this value will be inherited by all subnets belonging to the
+shared network.
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "kakapo",
+ "relay": {
+ # This relay address is inherited by both subnets.
+ "ip-addresses": [ "2001:db8::1234" ]
+ },
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "3ffe:abcd::/64",
+ "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ]
+ }
+ ]
+ }
+ ],
+ ...
+ }
+
+Even though it is technically possible to configure two (or more) subnets
+within the shared network to use different relay addresses, this will almost
+always lead to a different behavior than what the user would expect. In this
+case, the Kea server will initially select one of the subnets by matching
+the relay address in the client's packet with the subnet's configuration.
+However, it MAY end up using the other subnet (even though it does not match
+the relay address) if the client already has a lease in this subnet or has a
+host reservation in this subnet, or simply if the initially selected subnet has no
+more addresses available. Therefore, it is strongly recommended to always
+specify subnet selectors (interface or relay address) at the shared-network
+level if the subnets belong to a shared network, as it is rarely useful to
+specify them at the subnet level and may lead to the configuration errors
+described above.
+
+Client Classification in Shared Networks
+----------------------------------------
+
+Sometimes it is desirable to segregate clients into specific subnets
+based on certain properties. This mechanism is called client
+classification and is described in :ref:`classify`. Client
+classification can be applied to subnets belonging to shared networks in
+the same way as it is used for subnets specified outside of shared
+networks. It is important to understand how the server selects subnets
+for clients when client classification is in use, to ensure that the
+appropriate subnet is selected for a given client type.
+
+If a subnet is associated with a class, only the clients belonging to
+this class can use this subnet. If there are no classes specified for a
+subnet, any client connected to a given shared network can use this
+subnet. A common mistake is to assume that the subnet that includes a client
+class is preferred over subnets without client classes. Consider the
+following example:
+
+.. code-block:: json
+
+ {
+ "client-classes": [
+ {
+ "name": "b-devices",
+ "test": "option[1234].hex == 0x0002"
+ }
+ ],
+ "shared-networks": [
+ {
+ "name": "galah",
+ "relay": {
+ "ip-address": [ "2001:db8:2:34::1" ]
+ },
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [ { "pool": "2001:db8:1::20 - 2001:db8:1::ff" } ]
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:3::/64",
+ "pools": [ { "pool": "2001:db8:3::20 - 2001:db8:3::ff" } ],
+ "client-class": "b-devices"
+ }
+ ]
+ }
+ ]
+ }
+
+If the client belongs to the "b-devices" class (because it includes
+option 1234 with a value of 0x0002), that does not guarantee that the
+subnet 2001:db8:3::/64 will be used (or preferred) for this client. The
+server can use either of the two subnets, because the subnet
+2001:db8:1::/64 is also allowed for this client. The client
+classification used in this case should be perceived as a way to
+restrict access to certain subnets, rather than as a way to express subnet
+preference. For example, if the client does not belong to the "b-devices"
+class, it may only use the subnet 2001:db8:1::/64 and will never use the
+subnet 2001:db8:3::/64.
+
+A typical use case for client classification is in a cable network,
+where cable modems should use one subnet and other devices should use
+another subnet within the same shared network. In this case it is
+necessary to apply classification on all subnets. The following example
+defines two classes of devices, and the subnet selection is made based
+on option 1234 values.
+
+::
+
+ {
+ "client-classes": [
+ {
+
+ "name": "a-devices",
+ "test": "option[1234].hex == 0x0001"
+ },
+ {
+ "name": "b-devices",
+ "test": "option[1234].hex == 0x0002"
+ }
+ ],
+ "shared-networks": [
+ {
+ "name": "galah",
+ "relay": {
+ "ip-addresses": [ "2001:db8:2:34::1" ]
+ },
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [ { "pool": "2001:db8:1::20 - 2001:db8:1::ff" } ],
+ "client-class": "a-devices"
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:3::/64",
+ "pools": [ { "pool": "2001:db8:3::20 - 2001:db8:3::ff" } ],
+ "client-class": "b-devices"
+ }
+ ]
+ }
+ ]
+ }
+
+In this example each class has its own restriction. Only clients that
+belong to class "a-devices" are able to use subnet 2001:db8:1::/64
+and only clients belonging to "b-devices" are able to use subnet
+2001:db8:3::/64. Care should be taken not to define too-restrictive
+classification rules, as clients that are unable to use any subnets will
+be refused service. However, this may be a desired outcome if one wishes
+to provide service only to clients with known properties (e.g. only VoIP
+phones allowed on a given link).
+
+It is possible to achieve an effect similar to the one
+presented in this section without the use of shared networks. If the
+subnets are placed in the global subnets scope, rather than in the
+shared network, the server will still use classification rules to pick
+the right subnet for a given class of devices. The major benefit of
+placing subnets within the shared network is that common parameters for
+the logically grouped subnets can be specified once, in the shared
+network scope, e.g. the ``interface`` or ``relay`` parameter. All subnets
+belonging to this shared network will inherit those parameters.
+
+Host Reservations in Shared Networks
+------------------------------------
+
+Subnets that are part of a shared network allow host reservations,
+similar to regular subnets:
+
+::
+
+ {
+ "shared-networks": [
+ {
+ "name": "frog",
+ "relay": {
+ "ip-addresses": [ "2001:db8:2:34::1" ]
+ },
+ "subnet6": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "id": 100,
+ "pools": [ { "pool": "2001:db8:1::1 - 2001:db8:1::64" } ],
+ "reservations": [
+ {
+ "duid": "00:03:00:01:11:22:33:44:55:66",
+ "ip-addresses": [ "2001:db8:1::28" ]
+ }
+ ]
+ },
+ {
+ "subnet": "2001:db8:3::/64",
+ "id": 101,
+ "pools": [ { "pool": "2001:db8:3::1 - 2001:db8:3::64" } ],
+ "reservations": [
+ {
+ "duid": "00:03:00:01:aa:bb:cc:dd:ee:ff",
+ "ip-addresses": [ "2001:db8:2::28" ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+
+It is worth noting that Kea conducts additional checks when processing a
+packet if shared networks are defined. First, instead of simply checking
+whether there is a reservation for a given client in its initially
+selected subnet, Kea looks through all subnets in a shared network for a
+reservation. This is one of the reasons why defining a shared network
+may impact performance. If there is a reservation for a client in any
+subnet, that particular subnet is picked for the client. Although
+it is technically not an error, it is considered bad practice to define
+reservations for the same host in multiple subnets belonging to the same
+shared network.
+
+While not strictly mandatory, it is strongly recommended to use explicit
+"id" values for subnets if database storage will be used for host
+reservations. If an ID is not specified, the values for it are
+auto generated, i.e. Kea assigns increasing integer values starting from
+1. Thus, the auto-generated IDs are not stable across configuration
+changes.
+
+.. _dhcp6-serverid:
+
+Server Identifier in DHCPv6
+===========================
+
+The DHCPv6 protocol uses a "server identifier" (also known as a DUID) to
+allow clients to discriminate between several servers present on the
+same link. `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__ currently
+defines four DUID types: DUID-LLT, DUID-EN, DUID-LL, and DUID-UUID.
+
+The Kea DHCPv6 server generates a server identifier once, upon the first
+startup, and stores it in a file. This identifier is not modified across
+restarts of the server and so is a stable identifier.
+
+Kea follows the recommendation from `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__ to use DUID-LLT as the
+default server identifier. However, ISC has received reports that some
+deployments require different DUID types, and that there is a need to
+administratively select both the DUID type and/or its contents.
+
+The server identifier can be configured using parameters within the
+``server-id`` map element in the global scope of the Kea configuration
+file. The following example demonstrates how to select DUID-EN as a
+server identifier:
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "EN"
+ },
+ ...
+ }
+
+Currently supported values for the ``type`` parameter are: "LLT", "EN", and
+"LL", for DUID-LLT, DUID-EN, and DUID-LL respectively.
+
+When a new DUID type is selected, the server generates its value and
+replaces any existing DUID in the file. The server then uses the new
+server identifier in all future interactions with clients.
+
+.. note::
+
+ If the new server identifier is created after some clients have
+ obtained their leases, the clients using the old identifier are not
+ able to renew their leases; the server will ignore messages containing
+ the old server identifier. Clients will continue sending RENEW until
+ they transition to the rebinding state. In this state, they will
+ start sending REBIND messages to the multicast address without a
+ server identifier. The server will respond to the REBIND messages
+ with a new server identifier, and the clients will associate the new
+ server identifier with their leases. Although the clients will be
+ able to keep their leases and will eventually learn the new server
+ identifier, this will be at the cost of an increased number of
+ renewals and multicast traffic due to a need to rebind. Therefore, it
+ is recommended that modification of the server-identifier type and
+ value be avoided if the server has already assigned leases and these
+ leases are still valid.
+
+There are cases when an administrator needs to explicitly specify a DUID
+value rather than allow the server to generate it. The following example
+demonstrates how to explicitly set all components of a DUID-LLT.
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "LLT",
+ "htype": 8,
+ "identifier": "A65DC7410F05",
+ "time": 2518920166
+ },
+ ...
+ }
+
+where:
+
+- ``htype`` is a 16-bit unsigned value specifying hardware type,
+
+- ``identifier`` is a link-layer address, specified as a string of
+ hexadecimal digits, and
+
+- ``time`` is a 32-bit unsigned time value.
+
+The hexadecimal representation of the DUID generated as a result of the
+configuration specified above is:
+
+::
+
+ 00:01:00:08:96:23:AB:E6:A6:5D:C7:41:0F:05
+ |type |htype| time | identifier |
+
+A special value of "0" for ``htype`` and ``time`` is allowed, which indicates
+that the server should use ANY value for these components. If the server
+already uses a DUID-LLT, it will use the values from this DUID; if the
+server uses a DUID of a different type or does not yet use any DUID, it
+will generate these values. Similarly, if the ``identifier`` is assigned
+an empty string, the value of the ``identifier`` will be generated. Omitting
+any of these parameters is equivalent to setting them to those special
+values.
+
+For example, the following configuration:
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "LLT",
+ "htype": 0,
+ "identifier": "",
+ "time": 2518920166
+ },
+ ...
+ }
+
+indicates that the server should use ANY link-layer address and hardware
+type. If the server is already using DUID-LLT, it will use the
+link-layer address and hardware type from the existing DUID. If the
+server is not yet using any DUID, it will use the link-layer address and
+hardware type from one of the available network interfaces. The server
+will use an explicit value of time; if it is different than a time value
+present in the currently used DUID, that value will be replaced,
+effectively modifying the current server identifier.
+
+The following example demonstrates an explicit configuration of a
+DUID-EN:
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "EN",
+ "enterprise-id": 2495,
+ "identifier": "87ABEF7A5BB545"
+ },
+ ...
+ }
+
+where:
+
+- ``enterprise-id`` is a 32-bit unsigned value holding an enterprise
+ number, and
+
+- ``identifier`` is a variable- length identifier within DUID-EN.
+
+The hexadecimal representation of the DUID-EN created according to the
+configuration above is:
+
+::
+
+ 00:02:00:00:09:BF:87:AB:EF:7A:5B:B5:45
+ |type | ent-id | identifier |
+
+As in the case of the DUID-LLT, special values can be used for the
+configuration of the DUID-EN. If the ``enterprise-id`` is "0", the server
+will use a value from the existing DUID-EN. If the server is not using
+any DUID or the existing DUID has a different type, the ISC enterprise
+ID will be used. When an empty string is entered for ``identifier``, the
+identifier from the existing DUID-EN will be used. If the server is not
+using any DUID-EN, a new 6-byte-long ``identifier`` will be generated.
+
+DUID-LL is configured in the same way as DUID-LLT except that the
+``time`` parameter has no effect for DUID-LL, because this DUID type
+only comprises a hardware type and link-layer address. The following
+example demonstrates how to configure DUID-LL:
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "LL",
+ "htype": 8,
+ "identifier": "A65DC7410F05"
+ },
+ ...
+ }
+
+which will result in the following server identifier:
+
+::
+
+ 00:03:00:08:A6:5D:C7:41:0F:05
+ |type |htype| identifier |
+
+The server stores the generated server identifier in the following
+location: ``[kea-install-dir]/var/lib/kea/kea-dhcp6-serverid``.
+
+In some uncommon deployments where no stable storage is available, the
+server should be configured not to try to store the server identifier.
+This choice is controlled by the value of the ``persist`` boolean
+parameter:
+
+::
+
+ "Dhcp6": {
+ "server-id": {
+ "type": "EN",
+ "enterprise-id": 2495,
+ "identifier": "87ABEF7A5BB545",
+ "persist": false
+ },
+ ...
+ }
+
+The default value of the ``persist`` parameter is ``true``, which
+configures the server to store the server identifier on a disk.
+
+In the example above, the server is configured not to store the
+generated server identifier on a disk. But if the server identifier is
+not modified in the configuration, the same value is used after
+server restart, because the entire server identifier is explicitly
+specified in the configuration.
+
+.. _data-directory:
+
+DHCPv6 Data Directory
+=====================
+
+The Kea DHCPv6 server puts the server identifier file and the default
+memory lease file into its data directory. By default this directory is
+``prefix/var/lib/kea`` but this location can be changed using the
+``data-directory`` global parameter, as in:
+
+::
+
+ "Dhcp6": {
+ "data-directory": "/var/tmp/kea-server6",
+ ...
+ }
+
+.. _stateless-dhcp6:
+
+Stateless DHCPv6 (INFORMATION-REQUEST Message)
+==============================================
+
+Typically DHCPv6 is used to assign both addresses and options. These
+assignments (leases) have a state that changes over time, hence their
+description as "stateful." DHCPv6 also supports a "stateless" mode, where clients
+request only configuration options. This mode is considered lightweight
+from the server perspective, as it does not require any state tracking.
+
+The Kea server supports stateless mode. When clients send
+INFORMATION-REQUEST messages, the server sends back answers with the
+requested options, if they are available in the server
+configuration. The server attempts to use per-subnet options first; if
+that fails, it then tries to provide options
+defined in the global scope.
+
+Stateless and stateful mode can be used together. No special
+configuration directives are required to handle this; simply use the
+configuration for stateful clients and the stateless clients will get
+only the options they requested.
+
+It is possible to run a server that provides only options and no addresses or
+prefixes. If the options have the same value in each subnet, the
+configuration can define the required options in the global scope and skip
+subnet definitions altogether. Here's a simple example of such a
+configuration:
+
+::
+
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "ethX" ]
+ },
+ "option-data": [ {
+ "name": "dns-servers",
+ "data": "2001:db8::1, 2001:db8::2"
+ } ],
+ "lease-database": {
+ "type": "memfile"
+ }
+ }
+
+This very simple configuration provides DNS server information to
+all clients in the network, regardless of their location. The
+memfile lease database must be specified, as Kea
+requires a lease database to be specified even if it is not used.
+
+.. _dhcp6-rfc7550:
+
+Support for RFC 7550 (now part of RFC 8415)
+===========================================
+
+`RFC 7550 <https://tools.ietf.org/html/rfc7550>`__ introduced some
+changes to the previous DHCPv6 specifications, `RFC
+3315 <https://tools.ietf.org/html/rfc3315>`__ and `RFC
+3633 <https://tools.ietf.org/html/rfc3633>`__, to resolve issues
+with the coexistence of multiple stateful options in the messages sent
+between clients and servers. Those changes were later included in
+the most recent DHCPv6 protocol specification, `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__, which obsoleted `RFC
+7550 <https://tools.ietf.org/html/rfc7550>`__. Kea supports `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__ along with these protocol
+changes, which are briefly described below.
+
+When a client, such as a requesting router, requests an allocation of
+both addresses and prefixes during the 4-way (SARR) exchange with the
+server, and the server is not configured to allocate any prefixes but
+can allocate some addresses, it will respond with the IA_NA(s)
+containing allocated addresses and the IA_PD(s) containing the
+NoPrefixAvail status code. According to the updated specifications, if
+the client can operate without prefixes it should accept allocated
+addresses and transition to the "bound" state. When the client
+subsequently sends RENEW/REBIND messages to the server to extend the
+lifetimes of the allocated addresses, according to the T1 and T2 times, and
+if the client is still interested in obtaining prefixes from the server,
+it may also include an IA_PD in the RENEW/REBIND to request allocation
+of the prefixes. If the server still cannot allocate the prefixes, it
+will respond with the IA_PD(s) containing the NoPrefixAvail status code.
+However, if the server can allocate the prefixes, it allocates and
+sends them in the IA_PD(s) to the client. A similar situation occurs when
+the server is unable to allocate addresses for the client but can
+delegate prefixes: the client may request allocation of the addresses
+while renewing the delegated prefixes. Allocating leases for other IA
+types while renewing existing leases is by default supported by the Kea
+DHCPv6 server, and the server provides no configuration mechanisms to
+disable this behavior.
+
+The following are the other behaviors first introduced in `RFC
+7550 <https://tools.ietf.org/html/rfc7550>`__ (now part of `RFC
+8415 <https://tools.ietf.org/html/rfc8415>`__) and supported by the Kea
+DHCPv6 server:
+
+- Set T1/T2 timers to the same value for all stateful (IA_NA and IA_PD)
+ options to facilitate renewal of all of a client's leases at the same
+ time (in a single message exchange).
+
+- Place NoAddrsAvail and NoPrefixAvail status codes in the IA_NA and
+ IA_PD options in the ADVERTISE message, rather than as the top-level
+ options.
+
+.. _dhcp6-relay-override:
+
+Using a Specific Relay Agent for a Subnet
+=========================================
+
+The DHCPv6 server follows the same principles as the DHCPv4 server to
+select a subnet for the client, with noticeable differences mainly for
+relays.
+
+.. note::
+
+ When the selected subnet is a member of a shared network, the
+ whole shared network is selected.
+
+A relay must have an interface connected to the link on which the
+clients are being configured. Typically the relay has a global IPv6
+address configured on that interface, which belongs to the subnet from
+which the server assigns addresses. Normally, the server is able to
+use the IPv6 address inserted by the relay (in the ``link-addr`` field in
+the RELAY-FORW message) to select the appropriate subnet.
+
+However, that is not always the case; the relay address may not match
+the subnet in certain deployments. This usually means that there is more
+than one subnet allocated for a given link. The two most common examples
+of this are long-lasting network renumbering (where both the
+old and new address spaces are still being used) and a cable network. In a
+cable network, both cable modems and the devices behind them are
+physically connected to the same link, yet they use distinct addressing.
+In such a case, the DHCPv6 server needs additional information (the
+value of the ``interface-id`` option or the IPv6 address inserted in the
+``link-addr`` field in the RELAY-FORW message) to properly select an
+appropriate subnet.
+
+The following example assumes that there is a subnet 2001:db8:1::/64
+that is accessible via a relay that uses 3000::1 as its IPv6 address.
+The server is able to select this subnet for any incoming packets that
+come from a relay that has an address in the 2001:db8:1::/64 subnet. It also
+selects that subnet for a relay with address 3000::1.
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::ffff"
+ }
+ ],
+ "relay": {
+ "ip-addresses": [ "3000::1" ]
+ }
+ }
+ ]
+ }
+
+If ``relay`` is specified, the ``ip-addresses`` parameter within it is
+mandatory. The ``ip-addresses`` parameter supports specifying a list of addresses.
+
+.. _dhcp6-client-class-relay:
+
+Segregating IPv6 Clients in a Cable Network
+===========================================
+
+In certain cases, it is useful to mix relay address information
+(introduced in :ref:`dhcp6-relay-override`) with client classification (explained
+in :ref:`classify`). One specific example is in a cable network,
+where modems typically get addresses from a different subnet than all
+the devices connected behind them.
+
+Let us assume that there is one Cable Modem Termination System (CMTS)
+with one CM MAC (a physical link that modems are connected to). We want
+the modems to get addresses from the 3000::/64 subnet, while everything
+connected behind the modems should get addresses from the 2001:db8:1::/64
+subnet. The CMTS that acts as a relay uses address 3000::1.
+The following configuration can serve that situation:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "3000::/64",
+ "pools": [
+ { "pool": "3000::2 - 3000::ffff" }
+ ],
+ "client-class": "VENDOR_CLASS_docsis3.0",
+ "relay": {
+ "ip-addresses": [ "3000::1" ]
+ }
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::ffff"
+ }
+ ],
+ "relay": {
+ "ip-addresses": [ "3000::1" ]
+ }
+ }
+ ]
+ }
+
+.. _mac-in-dhcpv6:
+
+MAC/Hardware Addresses in DHCPv6
+================================
+
+MAC/hardware addresses are available in DHCPv4 messages from
+clients, and administrators frequently use that information to perform
+certain tasks like per-host configuration and address reservation for
+specific MAC addresses. Unfortunately, the DHCPv6 protocol does not
+provide any completely reliable way to retrieve that information. To
+mitigate that issue, a number of mechanisms have been implemented in
+Kea. Each of these mechanisms works in certain cases, but may not in
+others. Whether the mechanism works in a particular deployment is
+somewhat dependent on the network topology and the technologies used.
+
+Kea allows specification of which of the supported methods should be
+used and in what order, via the ``mac-sources`` parameter. This configuration
+may be considered a fine
+tuning of the DHCP deployment.
+
+Here is an example:
+
+::
+
+ "Dhcp6": {
+ "mac-sources": [
+ "method1",
+ "method2",
+ "method3",
+ ...
+ ],
+
+ "subnet6": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+When not specified, a value of "any" is used, which instructs
+the server to attempt to try all the methods in sequence and use the
+value returned by the first one that succeeds. In a typical deployment the default value
+of "any" is sufficient and there is no need to select specific
+methods. Changing the value of this parameter is most useful in
+cases when an administrator wants to disable certain methods; for
+example, if the administrator trusts the network infrastructure more
+than the information provided by the clients themselves, they may prefer
+information provided by the relays over that provided by clients.
+
+If specified, ``mac-sources`` must have at least one value.
+
+Supported methods are:
+
+- ``any`` - this is not an actual method, just a keyword that instructs Kea to
+ try all other methods and use the first one that succeeds. This is
+ the default operation if no ``mac-sources`` are defined.
+
+- ``raw`` - in principle, a DHCPv6 server could use raw sockets to
+ receive incoming traffic and extract MAC/hardware address
+ information. This is currently not implemented for DHCPv6 and this
+ value has no effect.
+
+- ``duid`` - DHCPv6 uses DUID identifiers instead of MAC addresses.
+ There are currently four DUID types defined, and two of them
+ (DUID-LLT, which is the default, and DUID-LL) convey MAC address
+ information. Although `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__
+ forbids it, it is possible to
+ parse those DUIDs and extract necessary information from them. This
+ method is not completely reliable, as clients may use other DUID
+ types, namely DUID-EN or DUID-UUID.
+
+- ``ipv6-link-local`` - another possible acquisition method comes from
+ the source IPv6 address. In typical usage, clients are sending their
+ packets from IPv6 link-local addresses. There is a good chance that
+ those addresses are based on EUI-64, which contains a MAC address.
+ This method is not completely reliable, as clients may use other
+ link-local address types. In particular, privacy extensions, defined
+ in `RFC 4941 <https://tools.ietf.org/html/rfc4941>`__, do not use MAC
+ addresses. Also note that successful extraction requires that the
+ address's u-bit must be set to "1" and its g-bit set to "0", indicating
+ that it is an interface identifier as per `RFC 2373, section
+ 2.5.1 <https://tools.ietf.org/html/rfc2373#section-2.5.1>`__.
+
+- ``client-link-addr-option`` - one extension defined to alleviate
+ missing MAC issues is the client link-layer address option, defined
+ in `RFC 6939 <https://tools.ietf.org/html/rfc6939>`__. This is an
+ option that is inserted by a relay and contains information about a
+ client's MAC address. This method requires a relay agent that
+ supports the option and is configured to insert it. This method is
+ useless for directly connected clients. The value ``rfc6939`` is an alias for
+ ``client-link-addr-option``.
+
+- ``remote-id`` - `RFC 4649 <https://tools.ietf.org/html/rfc4649>`__
+ defines a ``remote-id`` option that is inserted by a relay agent.
+ Depending on the relay agent configuration, the inserted option may
+ convey the client's MAC address information. The value ``rfc4649``
+ is an alias for ``remote-id``.
+
+- ``subscriber-id`` - Defined in `RFC 4580 <https://tools.ietf.org/html/rfc4580>`__,
+ ``subscriber-id`` is somewhat similar to ``remote-id``; it is also inserted
+ by a relay agent. The value ``rfc4580`` is an alias for
+ ``subscriber-id``. This method is currently not implemented.
+
+- ``docsis-cmts`` - Yet another possible source of MAC address
+ information are the DOCSIS options inserted by a CMTS that acts as a
+ DHCPv6 relay agent in cable networks. This method attempts to extract
+ MAC address information from sub-option 1026 (cm mac) of the
+ vendor-specific option with ``vendor-id=4491``. This vendor option is
+ extracted from the Relay-forward message, not the original client's
+ message.
+
+- ``docsis-modem`` - The final possible source of MAC address
+ information are the DOCSIS options inserted by the cable modem
+ itself. This method attempts to extract MAC address information from
+ sub-option 36 (``device-id``) of the vendor-specific option with
+ ``vendor-id=4491``. This vendor option is extracted from the original
+ client's message, not from any relay options.
+
+An empty ``mac-sources`` parameter is not allowed. Administrators who do not want to specify it
+should either simply omit the ``mac-sources`` definition or specify it with the
+"any" value, which is the default.
+
+.. _dhcp6-decline:
+
+Duplicate Addresses (DHCPDECLINE Support)
+=========================================
+
+The DHCPv6 server is configured with a certain pool of addresses that it
+is expected to hand out to DHCPv6 clients. It is assumed that the server
+is authoritative and has complete jurisdiction over those addresses.
+However, for various reasons such as misconfiguration or a faulty
+client implementation that retains its address beyond the valid
+lifetime, there may be devices connected that use those addresses
+without the server's approval or knowledge.
+
+Such an unwelcome event can be detected by legitimate clients (using
+Duplicate Address Detection) and reported to the DHCPv6 server using a
+DHCPDECLINE message. The server does a sanity check (to see whether
+the client declining an address really was supposed to use it), then
+conducts a clean-up operation, and confirms the DHCPDECLINE by sending back a REPLY
+message. Any DNS entries related to that address are removed, the
+event is logged, and hooks are triggered. After that is
+complete, the address is marked as declined (which indicates that
+it is used by an unknown entity and thus not available for assignment)
+and a probation time is set on it. Unless otherwise configured, the
+probation period lasts 24 hours; after that time, the server will
+recover the lease (i.e. put it back into the available state) and the
+address will be available for assignment again. It should be noted that
+if the underlying issue of a misconfigured device is not resolved, the
+duplicate-address scenario will repeat. If reconfigured correctly, this
+mechanism provides an opportunity to recover from such an event
+automatically, without any system administrator intervention.
+
+To configure the decline probation period to a value other than the
+default, the following syntax can be used:
+
+::
+
+ "Dhcp6": {
+ "decline-probation-period": 3600,
+ "subnet6": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+The parameter is expressed in seconds, so the example above
+instructs the server to recycle declined leases after one hour.
+
+There are several statistics and hook points associated with the decline
+handling procedure. The ``lease6_decline`` hook point is triggered after the
+incoming DHCPDECLINE message has been sanitized and the server is about
+to decline the lease. The ``declined-addresses`` statistic is increased
+after the hook returns (both the global and subnet-specific variants). (See
+:ref:`dhcp6-stats` and :ref:`hooks-libraries`
+for more details on DHCPv6 statistics and Kea hook points.)
+
+Once the probation time elapses, the declined lease is recovered using
+the standard expired-lease reclamation procedure, with several
+additional steps. In particular, both ``declined-addresses`` statistics
+(global and subnet-specific) are decreased. At the same time,
+``reclaimed-declined-addresses`` statistics (again in two variants, global
+and subnet-specific) are increased.
+
+A note about statistics: The Kea server does not decrease the
+``assigned-nas`` statistics when a DHCPDECLINE message is received and
+processed successfully. While technically a declined address is no
+longer assigned, the primary usage of the ``assigned-nas`` statistic
+is to monitor pool utilization. Most people would forget to include
+``declined-addresses`` in the calculation, and would simply use
+``assigned-nas``/``total-nas``. This would cause a bias towards
+under-representing pool utilization. As this has a potential to cause serious
+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-stats:
+
+Statistics in the DHCPv6 Server
+===============================
+
+The DHCPv6 server supports the following statistics:
+
+.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}|
+
+.. table:: DHCPv6 statistics
+ :class: longtable
+ :widths: 20 10 70
+
+
+ +---------------------------------------------------+----------------+------------------------------------+
+ | Statistic | Data Type | Description |
+ +===================================================+================+====================================+
+ | pkt6-received | integer | Number of DHCPv6 packets received. |
+ | | | This includes all packets: valid, |
+ | | | bogus, corrupted, rejected, etc. |
+ | | | This statistic is expected to grow |
+ | | | rapidly. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-receive-drop | integer | Number of incoming packets that |
+ | | | were dropped. The exact reason for |
+ | | | dropping packets is logged, but |
+ | | | the most common reasons may be: an |
+ | | | unacceptable or not supported |
+ | | | packet type is received, direct |
+ | | | responses are forbidden, the |
+ | | | server-id sent by the client does |
+ | | | not match the server's server-id, |
+ | | | or the packet is malformed. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-parse-failed | integer | Number of incoming packets that |
+ | | | could not be parsed. A non-zero |
+ | | | value of this statistic indicates |
+ | | | that the server received a |
+ | | | malformed or truncated packet. |
+ | | | This may indicate problems in the |
+ | | | network, faulty clients, faulty |
+ | | | relay agents, or a bug in the |
+ | | | server. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-solicit-received | integer | Number of SOLICIT packets |
+ | | | received. This statistic is |
+ | | | expected to grow; its increase |
+ | | | means that clients that just |
+ | | | booted started their configuration |
+ | | | process and their initial packets |
+ | | | reached the Kea server. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-advertise-received | integer | Number of ADVERTISE packets |
+ | | | received. ADVERTISE packets are |
+ | | | sent by the server and the server |
+ | | | is never expected to receive them. |
+ | | | A non-zero value of this statistic |
+ | | | indicates an error occurring in |
+ | | | the network. One likely cause |
+ | | | would be a misbehaving relay |
+ | | | agent that incorrectly forwards |
+ | | | ADVERTISE messages towards the |
+ | | | server, rather than back to the |
+ | | | clients. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-request-received | integer | Number of DHCPREQUEST packets |
+ | | | received. This statistic is |
+ | | | expected to grow. Its increase |
+ | | | means that clients that just |
+ | | | booted received the server's |
+ | | | response (DHCPADVERTISE) and |
+ | | | accepted it, and are now |
+ | | | requesting an address |
+ | | | (DHCPREQUEST). |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-reply-received | integer | Number of REPLY packets received. |
+ | | | This statistic is expected to |
+ | | | remain zero at all times, as 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 |
+ | | | REPLY messages towards the server, |
+ | | | rather than back to the clients. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-renew-received | integer | Number of RENEW packets received. |
+ | | | This statistic is expected to |
+ | | | grow; its increase means that |
+ | | | clients received their addresses |
+ | | | and prefixes and are trying to |
+ | | | renew them. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-rebind-received | integer | Number of REBIND packets received. |
+ | | | A non-zero value indicates that |
+ | | | clients did not receive responses |
+ | | | to their RENEW messages (through |
+ | | | the regular lease-renewal |
+ | | | mechanism) and are attempting to |
+ | | | find any server that is able to |
+ | | | take over their leases. It may |
+ | | | mean that some servers' REPLY |
+ | | | messages never reached the |
+ | | | clients. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-release-received | integer | Number of RELEASE packets |
+ | | | received. This statistic is |
+ | | | expected to grow when a device is |
+ | | | being shut down in the network; it |
+ | | | indicates that the address or |
+ | | | prefix assigned is reported as no |
+ | | | longer needed. Note that many |
+ | | | devices, especially wireless, do |
+ | | | not send RELEASE packets either |
+ | | | because of design choice or due to |
+ | | | the client moving out of range. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-decline-received | integer | Number of DECLINE packets |
+ | | | received. This statistic is |
+ | | | expected to remain close to zero. |
+ | | | Its increase means that a client |
+ | | | leased an address, but discovered |
+ | | | that the address is currently used |
+ | | | by an unknown device in the |
+ | | | network. If this statistic is |
+ | | | growing, it may indicate a |
+ | | | misconfigured server or devices |
+ | | | that have statically assigned |
+ | | | conflicting addresses. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-infrequest-received | integer | Number of INFORMATION-REQUEST |
+ | | | packets received. This statistic |
+ | | | is expected to grow if there are |
+ | | | devices that are using stateless |
+ | | | DHCPv6. INFORMATION-REQUEST |
+ | | | messages are used by clients that |
+ | | | request stateless configuration, |
+ | | | i.e. options and parameters other |
+ | | | than addresses or prefixes. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-dhcpv4-query-received | integer | Number of DHCPv4-QUERY packets |
+ | | | received. This statistic is |
+ | | | expected to grow if there are |
+ | | | devices that are using |
+ | | | DHCPv4-over-DHCPv6. DHCPv4-QUERY |
+ | | | messages are used by DHCPv4 |
+ | | | clients on an IPv6-only line which |
+ | | | encapsulates the requests over |
+ | | | DHCPv6. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-dhcpv4-response-received | integer | Number of DHCPv4-RESPONSE packets |
+ | | | received. This statistic is |
+ | | | expected to remain zero at all |
+ | | | times, as DHCPv4-RESPONSE 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 |
+ | | | DHCPv4-RESPONSE 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 |
+ | | | server received a packet that it |
+ | | | was unable to recognize; either it |
+ | | | had an unsupported type or was |
+ | | | possibly malformed. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-sent | integer | Number of DHCPv6 packets sent. |
+ | | | This statistic is expected to grow |
+ | | | every time the server transmits a |
+ | | | packet. In general, it should |
+ | | | roughly match pkt6-received, as |
+ | | | most incoming packets cause the |
+ | | | server to respond. There are |
+ | | | exceptions (e.g. server receiving |
+ | | | a REQUEST with server-id matching |
+ | | | another server), so do not worry |
+ | | | if it is less than pkt6-received. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-advertise-sent | integer | Number of ADVERTISE packets sent. |
+ | | | This statistic is expected to grow |
+ | | | in most cases after a SOLICIT is |
+ | | | processed. There are certain |
+ | | | uncommon, but valid, cases where |
+ | | | incoming SOLICIT packets are |
+ | | | dropped, but in general this |
+ | | | statistic is expected to be close |
+ | | | to pkt6-solicit-received. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-reply-sent | integer | Number of REPLY packets sent. This |
+ | | | statistic is expected to grow in |
+ | | | most cases after a SOLICIT (with |
+ | | | rapid-commit), REQUEST, RENEW, |
+ | | | REBIND, RELEASE, DECLINE, or |
+ | | | INFORMATION-REQUEST is processed. |
+ | | | There are certain cases where |
+ | | | there is no response. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | pkt6-dhcpv4-response-sent | integer | Number of DHCPv4-RESPONSE packets |
+ | | | sent. This statistic is expected |
+ | | | to grow in most cases after a |
+ | | | DHCPv4-QUERY is processed. There |
+ | | | are certain cases where there is |
+ | | | no response. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].total-nas | big integer | Total number of NA addresses |
+ | | | available for DHCPv6 management |
+ | | | for a given subnet; in other |
+ | | | words, this is the count of all |
+ | | | addresses in all configured pools. |
+ | | | This statistic changes only during |
+ | | | configuration changes. It does not |
+ | | | take into account any addresses |
+ | | | that may be reserved due to host |
+ | | | reservation. 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].pool[pid].total-nas | big integer | Total number of NA addresses |
+ | | | available for DHCPv6 management |
+ | | | for a given subnet pool; in other |
+ | | | words, this is the count of all |
+ | | | addresses in configured subnet |
+ | | | pool. This statistic changes only |
+ | | | during configuration changes. It |
+ | | | does not take into account any |
+ | | | addresses that may be reserved due |
+ | | | to host reservation. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of a |
+ | | | given pool. This statistic is |
+ | | | exposed for each subnet pool |
+ | | | separately, and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | cumulative-assigned-nas | integer | Cumulative number of NA addresses |
+ | | | that have been assigned since |
+ | | | server startup. It is incremented |
+ | | | each time a NA address is assigned |
+ | | | and is not reset when the server |
+ | | | is reconfigured. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].cumulative-assigned-nas | integer | Cumulative number of NA addresses |
+ | | | in a given subnet that were |
+ | | | assigned. It increases every time |
+ | | | a new lease is allocated (as a |
+ | | | result of receiving a REQUEST |
+ | | | 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].pool[pid].cumulative-assigned-nas | integer | Cumulative number of NA addresses |
+ | | | in a given subnet pool that were |
+ | | | assigned. It increases every time |
+ | | | a new lease is allocated (as a |
+ | | | result of receiving a REQUEST |
+ | | | message) and is never decreased. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. The *pid* is the |
+ | | | pool-id of a given pool. This |
+ | | | statistic is exposed for each |
+ | | | subnet pool separately, and is |
+ | | | reset during a reconfiguration |
+ | | | event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].assigned-nas | integer | Number of NA addresses in a given |
+ | | | subnet that are assigned. It |
+ | | | increases every time a new lease |
+ | | | is allocated (as a result of |
+ | | | receiving a REQUEST message) and |
+ | | | is decreased every time a lease is |
+ | | | released (a RELEASE message is |
+ | | | received) or expires. 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].pool[pid].assigned-nas | integer | Number of NA addresses in a given |
+ | | | subnet pool that are assigned. It |
+ | | | increases every time a new lease |
+ | | | is allocated (as a result of |
+ | | | receiving a REQUEST message) and |
+ | | | is decreased every time a lease is |
+ | | | released (a RELEASE message is |
+ | | | received) or expires. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately, |
+ | | | and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].total-pds | big integer | Total number of PD prefixes |
+ | | | available for DHCPv6 management |
+ | | | for a given subnet; in other |
+ | | | words, this is the count of all |
+ | | | prefixes in all configured pools. |
+ | | | This statistic changes only during |
+ | | | configuration changes. Note it |
+ | | | does not take into account any |
+ | | | prefixes that may be reserved due |
+ | | | to host reservation. 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].pd-pool[pid].total-pds | big integer | Total number of PD prefixes |
+ | | | available for DHCPv6 management |
+ | | | for a given subnet pool; in other |
+ | | | words, this is the count of all |
+ | | | prefixes in configured subnet |
+ | | | pd-pool. This statistic changes |
+ | | | only during configuration changes. |
+ | | | It does not take into account any |
+ | | | prefixes that may be reserved due |
+ | | | to host reservation. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of a |
+ | | | given pool. This statistic is |
+ | | | exposed for each subnet pd-pool |
+ | | | separately, and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | cumulative-assigned-pds | integer | Cumulative number of PD prefixes |
+ | | | that have been assigned since |
+ | | | server startup. It is incremented |
+ | | | each time a PD prefix is assigned |
+ | | | and is not reset when the server |
+ | | | is reconfigured. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].cumulative-assigned-pds | integer | Cumulative number of PD prefixes |
+ | | | in a given subnet that were |
+ | | | assigned. It increases every time |
+ | | | a new lease is allocated (as a |
+ | | | result of receiving a REQUEST |
+ | | | 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].pd-pool[pid].cumulative-assigned-pds | integer | Cumulative number of PD prefixes |
+ | | | in a given subnet pd-pool that |
+ | | | were assigned. It increases every |
+ | | | time a new lease is allocated (as |
+ | | | a result of receiving a REQUEST |
+ | | | message) and is never decreased. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. The *pid* is the |
+ | | | pool-id of a given pd-pool. This |
+ | | | statistic is exposed for each |
+ | | | subnet pd-pool separately, and is |
+ | | | reset during a reconfiguration |
+ | | | event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].assigned-pds | integer | Number of PD prefixes in a given |
+ | | | subnet that are assigned. It |
+ | | | increases every time a new lease |
+ | | | is allocated (as a result of |
+ | | | receiving a REQUEST message) and |
+ | | | is decreased every time a lease is |
+ | | | released (a RELEASE message is |
+ | | | received) or expires. 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].pd-pool[pid].assigned-pds | integer | Number of PD prefixes in a given |
+ | | | subnet pd-pool that are assigned. |
+ | | | It increases every time a new |
+ | | | lease is allocated (as a result of |
+ | | | receiving a REQUEST message) and |
+ | | | is decreased every time a lease is |
+ | | | released (a RELEASE message is |
+ | | | received) or expires. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pd-pool. This statistic is exposed |
+ | | | for each subnet pd-pool |
+ | | | separately, and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | reclaimed-leases | integer | Number of expired leases that have |
+ | | | been reclaimed since server |
+ | | | startup. It is incremented each |
+ | | | time an expired lease is reclaimed |
+ | | | (counting both NA and PD |
+ | | | reclamations). This statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual leases have been reclaimed. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].reclaimed-leases | integer | Number of expired leases |
+ | | | associated with a given subnet |
+ | | | that have been reclaimed since |
+ | | | server startup. It is incremented |
+ | | | each time an expired lease is |
+ | | | reclaimed (counting both NA and PD |
+ | | | reclamations). The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].reclaimed-leases | integer | Number of expired NA addresses |
+ | | | associated with a given subnet |
+ | | | pool that have been reclaimed |
+ | | | since server startup. It is |
+ | | | incremented each time an expired |
+ | | | lease is reclaimed. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately, |
+ | | | and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pd-pool[pid].reclaimed-leases | integer | Number of expired PD prefixes |
+ | | | associated with a given subnet |
+ | | | pd-pool that have been reclaimed |
+ | | | since server startup. It is |
+ | | | incremented each time an expired |
+ | | | lease is reclaimed. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pd-pool. This statistic is exposed |
+ | | | for each subnet pd-pool |
+ | | | separately, and is reset during a |
+ | | | reconfiguration event. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | declined-addresses | integer | Number of IPv6 addresses that are |
+ | | | currently declined; a count of the |
+ | | | number of leases currently |
+ | | | unavailable. Once a lease is |
+ | | | recovered, this statistic will be |
+ | | | decreased; ideally, this statistic |
+ | | | should be zero. If this statistic |
+ | | | is non-zero or increasing, a |
+ | | | network administrator should |
+ | | | investigate whether there is a |
+ | | | misbehaving device in the network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].declined-addresses | integer | Number of IPv6 addresses that are |
+ | | | currently declined in a given |
+ | | | subnet; a count of the number of |
+ | | | leases currently unavailable. Once |
+ | | | a lease is recovered, this |
+ | | | statistic will be decreased; |
+ | | | ideally, this statistic should be |
+ | | | zero. If this statistic is |
+ | | | non-zero or increasing, a network |
+ | | | administrator should investigate |
+ | | | whether there is a misbehaving |
+ | | | device in the network. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | This statistic is exposed for each |
+ | | | subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].declined-addresses | integer | Number of IPv6 addresses that are |
+ | | | currently declined in a given |
+ | | | subnet pool; a count of the number |
+ | | | of leases currently unavailable. |
+ | | | Once a lease is recovered, this |
+ | | | statistic will be decreased; |
+ | | | ideally, this statistic should be |
+ | | | zero. If this statistic is |
+ | | | non-zero or increasing, a network |
+ | | | administrator should investigate |
+ | | | whether there is a misbehaving |
+ | | | device in the network. The *id* is |
+ | | | the subnet-id of a given subnet. |
+ | | | The *pid* is the pool-id of the |
+ | | | pool. This statistic is exposed |
+ | | | for each subnet pool separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | reclaimed-declined-addresses | integer | Number of IPv6 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. This |
+ | | | is a global statistic that covers |
+ | | | all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].reclaimed-declined-addresses | integer | Number of IPv6 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. The |
+ | | | *id* is the subnet-id of a given |
+ | | | subnet. This statistic is exposed |
+ | | | for each subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].pool[pid].reclaimed-declined-addresses | integer | Number of IPv6 addresses that were |
+ | | | declined, but have now been |
+ | | | recovered. Unlike |
+ | | | declined-addresses, this statistic |
+ | | | never decreases. It can be used as |
+ | | | a long-term indicator of how many |
+ | | | actual valid declines were |
+ | | | processed and recovered from. The |
+ | | | *id* is the subnet-id of a given |
+ | | | subnet. The *pid* is the pool-id |
+ | | | of the pool. This statistic is |
+ | | | exposed for each subnet pool |
+ | | | separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-allocation-fail | integer | Number of total address allocation |
+ | | | failures for a particular client. |
+ | | | This consists in the number of |
+ | | | lease allocation attempts that the |
+ | | | server made before giving up and |
+ | | | was unable to use any of the |
+ | | | address pools. This is a global |
+ | | | statistic that covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-allocation-fail | integer | Number of total address allocation |
+ | | | failures for a particular client. |
+ | | | This consists in the number of |
+ | | | lease allocation attempts that the |
+ | | | server made before giving up and |
+ | | | was unable to use any of the |
+ | | | address pools. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-allocation-fail-shared-network | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a shared network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-allocation-fail-shared-network | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a shared network. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. This statistic is |
+ | | | exposed for each subnet |
+ | | | separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-allocation-fail-subnet | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a subnet that does |
+ | | | not belong to a shared network. |
+ | | | This is a global statistic that |
+ | | | covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-allocation-fail-subnet | integer | Number of address allocation |
+ | | | failures for a particular client |
+ | | | connected to a subnet that does |
+ | | | not belong to a shared network. |
+ | | | The *id* is the subnet-id of a |
+ | | | given subnet. This statistic is |
+ | | | exposed for each subnet |
+ | | | separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-allocation-fail-no-pools | integer | Number of address allocation |
+ | | | failures because the server could |
+ | | | not use any configured pools for |
+ | | | a particular client. It is also |
+ | | | possible that all of the subnets |
+ | | | from which the server attempted to |
+ | | | assign an address lack address |
+ | | | pools. In this case, it should be |
+ | | | considered misconfiguration if an |
+ | | | operator expects that some clients |
+ | | | should be assigned dynamic |
+ | | | addresses. This is a global |
+ | | | statistic that covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-allocation-fail-no-pools | integer | Number of address allocation |
+ | | | failures because the server could |
+ | | | not use any configured pools for |
+ | | | a particular client. It is also |
+ | | | possible that all of the subnets |
+ | | | from which the server attempted to |
+ | | | assign an address lack address |
+ | | | pools. In this case, it should be |
+ | | | considered misconfiguration if an |
+ | | | operator expects that some clients |
+ | | | should be assigned dynamic |
+ | | | addresses. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-allocation-fail-classes | integer | Number of address allocation |
+ | | | failures when the client's packet |
+ | | | belongs to one or more classes. |
+ | | | There may be several reasons why a |
+ | | | lease was not assigned. One of |
+ | | | them may be a case when all pools |
+ | | | require packet to belong to |
+ | | | certain classes and the incoming |
+ | | | packet didn't belong to any of |
+ | | | them. Another case where this |
+ | | | information may be useful is to |
+ | | | point out that the pool reserved |
+ | | | to a given class has ran out of |
+ | | | addresses. This is a global |
+ | | | statistic that covers all subnets. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-allocation-fail-classes | integer | Number of address allocation |
+ | | | failures when the client's packet |
+ | | | belongs to one or more classes. |
+ | | | There may be several reasons why a |
+ | | | lease was not assigned. One of |
+ | | | them may be a case when all pools |
+ | | | require packet to belong to |
+ | | | certain classes and the incoming |
+ | | | packet didn't belong to any of |
+ | | | them. Another case where this |
+ | | | information may be useful is to |
+ | | | point out that the pool reserved |
+ | | | to a given class has ran out of |
+ | | | addresses. The *id* is the |
+ | | | subnet-id of a given subnet. This |
+ | | | statistic is exposed for each |
+ | | | subnet separately. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-ia-na-lease-reuses | integer | Number of times an IA_NA lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is global. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-ia-na-lease-reuses | integer | Number of times an IA_NA lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is on a per-subnet |
+ | | | basis. The *id* is the subnet-id |
+ | | | of a given subnet. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | v6-ia-pd-lease-reuses | integer | Number of times an IA_PD lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is global. |
+ +---------------------------------------------------+----------------+------------------------------------+
+ | subnet[id].v6-ia-pd-lease-reuses | integer | Number of times an IA_PD lease had |
+ | | | its CLTT increased in memory and |
+ | | | its expiration time left unchanged |
+ | | | in persistent storage as part of |
+ | | | the lease caching feature. This is |
+ | | | referred to as a lease reuse. |
+ | | | This statistic is on a per-subnet |
+ | | | basis. The *id* is the subnet-id |
+ | | | of a given subnet. |
+ +---------------------------------------------------+----------------+------------------------------------+
+
+.. note::
+
+ The pool ID can be configured on each pool by explicitly setting the ``pool-id``
+ parameter in the pool parameter map. If not configured, ``pool-id`` defaults to 0.
+ The statistics related to pool ID 0 refer to all the statistics of all the pools
+ that have unconfigured ``pool-id``.
+ The pool ID does not need to be unique within the subnet or across subnets.
+ The statistics regarding a specific pool ID within a subnet will be combined with the
+ other statistics of all other pools with the same pool ID in the respective subnet.
+
+.. note::
+
+ This section describes DHCPv6-specific statistics. For a general
+ overview and usage of statistics, see :ref:`stats`.
+
+The DHCPv6 server provides two global parameters to control the default sample
+limits of statistics:
+
+- ``statistic-default-sample-count`` - determines the default maximum
+ number of samples which are kept. The special value of 0
+ indicates that a default maximum age should be used.
+
+- ``statistic-default-sample-age`` - determines the default maximum
+ age in seconds of samples which are kept.
+
+For instance, to reduce the statistic-keeping overhead, set
+the default maximum sample count to 1 so only one sample is kept:
+
+::
+
+ "Dhcp6": {
+ "statistic-default-sample-count": 1,
+ "subnet6": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+Statistics can be retrieved periodically to gain more insight into Kea operations. One tool that
+leverages that capability is ISC Stork. See :ref:`stork` for details.
+
+
+.. _dhcp6-ctrl-channel:
+
+Management API for the DHCPv6 Server
+====================================
+
+The management API allows the issuing of specific management commands,
+such as statistics retrieval, reconfiguration, or shutdown. For more
+details, see :ref:`ctrl-channel`. Currently, the only supported
+communication channel type is the UNIX stream socket. By default there are
+no sockets open; to instruct Kea to open a socket, the following entry
+in the configuration file can be used:
+
+::
+
+ "Dhcp6": {
+ "control-socket": {
+ "socket-type": "unix",
+ "socket-name": "/path/to/the/unix/socket"
+ },
+
+ "subnet6": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+The length of the path specified by the ``socket-name`` parameter is
+restricted by the maximum length for the UNIX socket name on the administrator's
+operating system, i.e. the size of the ``sun_path`` field in the
+``sockaddr_un`` structure, decreased by 1. This value varies on
+different operating systems, between 91 and 107 characters. Typical
+values are 107 on Linux and 103 on FreeBSD.
+
+Communication over the control channel is conducted using JSON
+structures. See the
+`Control Channel section in the Kea Developer's Guide
+<https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__
+for more details.
+
+The DHCPv6 server supports the following operational commands:
+
+- :isccmd:`build-report`
+- :isccmd:`config-get`
+- :isccmd:`config-hash-get`
+- :isccmd:`config-reload`
+- :isccmd:`config-set`
+- :isccmd:`config-test`
+- :isccmd:`config-write`
+- :isccmd:`dhcp-disable`
+- :isccmd:`dhcp-enable`
+- :isccmd:`leases-reclaim`
+- :isccmd:`list-commands`
+- :isccmd:`shutdown`
+- :isccmd:`status-get`
+- :isccmd:`version-get`
+
+as described in :ref:`commands-common`. In addition, it supports the
+following statistics-related commands:
+
+- :isccmd:`statistic-get`
+- :isccmd:`statistic-reset`
+- :isccmd:`statistic-remove`
+- :isccmd:`statistic-get`-all
+- :isccmd:`statistic-reset`-all
+- :isccmd:`statistic-remove`-all
+- :isccmd:`statistic-sample-age-set`
+- :isccmd:`statistic-sample-age-set`-all
+- :isccmd:`statistic-sample-count-set`
+- :isccmd:`statistic-sample-count-set`-all
+
+as described in :ref:`command-stats`.
+
+.. _dhcp6-user-contexts:
+
+User Contexts in IPv6
+=====================
+
+Kea allows the loading of hook libraries that can sometimes benefit from
+additional parameters. If such a parameter is specific to the whole
+library, it is typically defined as a parameter for the hook library.
+However, sometimes there is a need to specify parameters that are
+different for each pool.
+
+See :ref:`user-context` for additional background regarding the
+user-context idea. See :ref:`user-context-hooks` for a discussion from the
+hooks perspective.
+
+User contexts can be specified at global scope; at the shared-network, subnet,
+pool, client-class, option-data, or definition level; and via host
+reservation. One other useful feature is the ability to store comments or
+descriptions.
+
+Let's consider an example deployment of lightweight 4over6, an
+IPv6 transition technology that allows mapping IPv6 prefixes into full
+or partial IPv4 addresses. In the DHCP context, these are specific
+parameters that are supposed to be delivered to clients in the form of
+additional options. Values of these options are correlated to delegated
+prefixes, so it is reasonable to keep these parameters together with the
+prefix delegation (PD) pool. On the other hand, lightweight 4over6 is not a commonly used
+feature, so it is not a part of the base Kea code. The solution to this
+problem is to specify a user context. For each PD pool that is expected to be
+used for lightweight 4over6, a user context with extra parameters is
+defined. Those extra parameters will be used by a hook library
+and loaded only when dynamic calculation of the lightweight 4over6
+option is actually needed. An example configuration looks as follows:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [ {
+ "pd-pools": [
+ {
+ "prefix": "2001:db8::",
+ "prefix-len": 56,
+ "delegated-len": 64,
+
+ # This is a pool specific context.
+ "user-context": {
+ "threshold-percent": 85,
+ "v4-network": "192.168.0.0/16",
+ "v4-overflow": "10.0.0.0/16",
+ "lw4over6-sharing-ratio": 64,
+ "lw4over6-v4-pool": "192.0.2.0/24",
+ "lw4over6-sysports-exclude": true,
+ "lw4over6-bind-prefix-len": 56
+ }
+ } ],
+ "id": 1,
+ "subnet": "2001:db8::/32",
+
+ # This is a subnet-specific context. Any type of
+ # information can be entered here as long as it is valid JSON.
+ "user-context": {
+ "comment": "Those v4-v6 migration technologies are tricky.",
+ "experimental": true,
+ "billing-department": 42,
+ "contacts": [ "Alice", "Bob" ]
+ }
+ } ]
+ }
+
+Kea does not interpret or use the user-context information; it simply
+stores it and makes it available to the hook libraries. It is up to each
+hook library to extract that information and use it. The parser
+translates a ``comment`` entry into a user context with the entry, which
+allows a comment to be attached inside the configuration itself.
+
+.. _dhcp6-std:
+
+Supported DHCPv6 Standards
+==========================
+
+The following standards are currently supported in Kea:
+
+- *Dynamic Host Configuration Protocol for IPv6*, `RFC
+ 3315 <https://tools.ietf.org/html/rfc3315>`__: Supported messages are
+ SOLICIT, ADVERTISE, REQUEST, RELEASE, RENEW, REBIND,
+ INFORMATION-REQUEST, CONFIRM, DECLINE and REPLY. The only
+ unsupported message is RECONFIGURE.
+
+- *Dynamic Host Configuration Protocol (DHCPv6) Options for
+ Session Initiation Protocol (SIP) Servers*, `RFC 3319
+ <https://tools.ietf.org/html/rfc3319>`__: All defined options are supported.
+
+- *IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP)
+ version 6*, `RFC 3633 <https://tools.ietf.org/html/rfc3633>`__:
+ Supported options are IA_PD and IA_PREFIX. Also supported is the
+ status code NoPrefixAvail.
+
+- *DNS Configuration options for Dynamic Host Configuration Protocol for IPv6
+ (DHCPv6)*, `RFC 3646 <https://tools.ietf.org/html/rfc3646>`__: All defined
+ options are supported.
+
+- *Stateless Dynamic Host Configuration Protocol (DHCP) Service for IPv6*, `RFC
+ 3736 <https://tools.ietf.org/html/rfc3736>`__: Server operation in
+ stateless mode is supported. Kea is currently server-only, so the client side
+ is not implemented.
+
+- *Information Refresh Time Option for Dynamic Host Configuration Protocol for
+ IPv6 (DHCPv6)*, `RFC 4242 <https://tools.ietf.org/html/rfc4242>`__: The
+ sole defined option (``information-refresh-time``) is supported.
+
+- *The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay
+ Agent Remote-ID Option*, `RFC
+ 4649 <https://tools.ietf.org/html/rfc4649>`__: The REMOTE-ID option is
+ supported.
+
+- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host
+ Configuration Protocol (DHCP) Clients*, `RFC 4703
+ <https://tools.ietf.org/html/rfc4703>`__: The DHCPv6 server uses the DHCP-DDNS
+ server to resolve conflicts.
+
+- *The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client
+ Fully Qualified Domain Name (FQDN) Option*, `RFC
+ 4704 <https://tools.ietf.org/html/rfc4704>`__: The supported option is
+ CLIENT_FQDN.
+
+- *Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Option for
+ Dual-Stack Lite*, `RFC 6334 <https://tools.ietf.org/html/rfc6334>`__:
+ The AFTR-Name DHCPv6 Option is supported.
+
+- *Relay-Supplied DHCP Options*, `RFC
+ 6422 <https://tools.ietf.org/html/rfc6422>`__: The full functionality is
+ supported: OPTION_RSOO; the ability of the server to echo back the
+ options; verification of whether an option is RSOO-enabled; the ability to mark
+ additional options as RSOO-enabled.
+
+- *Prefix Exclude Option for DHCPv6-based Prefix Delegation*, `RFC
+ 6603 <https://tools.ietf.org/html/rfc6603>`__: The Prefix Exclude option
+ is supported.
+
+- *Client Link-Layer Address Option in DHCPv6*, `RFC
+ 6939 <https://tools.ietf.org/html/rfc6939>`__: The supported option is
+ the client link-layer address option.
+
+- *Issues and Recommendations with Multiple Stateful DHCPv6 Options*,
+ `RFC 7550 <https://tools.ietf.org/html/rfc7550>`__: All
+ recommendations related to the DHCPv6 server operation are supported.
+
+- *DHCPv6 Options for Configuration of Softwire Address and Port-Mapped
+ Clients*, `RFC 7598 <https://tools.ietf.org/html/rfc7598>`__: All
+ options indicated in this specification are supported by the DHCPv6
+ server.
+
+- *Generalized UDP Source Port for DHCP Relay*, `RFC 8357
+ <https://tools.ietf.org/html/rfc8357>`__: The Kea server is able
+ to handle Relay Source Port option in a received Relay-forward
+ message, remembers the UDP port and sends back Relay-reply with a
+ copy of the option to the relay agent using this UDP port.
+
+- *Dynamic Host Configuration Protocol for IPv6 (DHCPv6)*, `RFC 8415
+ <https://tools.ietf.org/html/rfc8415>`__: This new DHCPv6 protocol specification
+ obsoletes RFC 3315, RFC 3633, RFC 3736, RFC 4242, RFC 7083, RFC 7283,
+ and RFC 7550. All features, with the exception of the RECONFIGURE mechanism and
+ the now-deprecated temporary addresses (IA_TA) mechanism, are supported.
+
+- *Captive-Portal Identification in DHCP and Router Advertisements (RAs)*, `RFC 8910
+ <https://tools.ietf.org/html/rfc8910>`__: The Kea server can configure both v4
+ and v6 versions of the captive portal options.
+
+- *DHCP and Router Advertisement Options for the Discovery of Network-designated
+ Resolvers (DNR)*, `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The Kea server
+ supports the DNR option. Part of its value (SvcParams) must be configured in
+ hex.
+
+.. _dhcp6-limit:
+
+DHCPv6 Server Limitations
+=========================
+
+These are the current known limitations of the Kea DHCPv6 server software. Most of
+them are reflections of the current stage of development and should be
+treated as “not implemented yet”, rather than actual limitations.
+
+- The server will allocate, renew, or rebind a maximum of one lease for
+ a particular IA option (IA_NA or IA_PD) sent by a client. `RFC
+ 8415 <https://tools.ietf.org/html/rfc8415>`__ allows for multiple
+ addresses or prefixes to be allocated for a single IA.
+
+- Temporary addresses are not supported. There is no intention to ever
+ implement this feature, as it is deprecated in `RFC 8415
+ <https://tools.ietf.org/html/rfc8415>`__.
+
+- Client reconfiguration (RECONFIGURE) is not yet supported.
+
+.. _dhcp6-srv-examples:
+
+Kea DHCPv6 Server Examples
+==========================
+
+A collection of simple-to-use examples for the DHCPv6 component of Kea
+is available with the source files, located in the ``doc/examples/kea6``
+directory.
+
+.. _dhcp6-cb:
+
+Configuration Backend in DHCPv6
+===============================
+
+In the :ref:`config-backend` section we have described the Configuration
+Backend (CB) feature, its applicability, and its limitations. This section focuses
+on the usage of the CB with the DHCPv6 server. It lists the supported
+parameters, describes limitations, and gives examples of DHCPv6
+server configurations to take advantage of the CB. Please also refer to
+the corresponding section :ref:`dhcp4-cb` for DHCPv4-specific usage of
+the CB.
+
+.. _dhcp6-cb-parameters:
+
+Supported Parameters
+--------------------
+
+The ultimate goal for the CB is to serve as a central configuration
+repository for one or multiple Kea servers connected to a database.
+In currently supported Kea versions, only a subset of
+the DHCPv6 server parameters can be configured in the database. All other
+parameters must be specified in the JSON configuration file, if
+required.
+
+All supported parameters can be configured via :ischooklib:`libdhcp_cb_cmds.so`.
+The general rule is that
+scalar global parameters are set using
+:isccmd:`remote-global-parameter6-set`; shared-network-specific parameters
+are set using :isccmd:`remote-network6-set`; and subnet-level and pool-level
+parameters are set using :isccmd:`remote-subnet6-set`. Whenever
+there is an exception to this general rule, it is highlighted in the
+table. Non-scalar global parameters have dedicated commands; for example,
+the global DHCPv6 options (``option-data``) are modified using
+:isccmd:`remote-option6-global-set`. Client classes, together with class-specific
+option definitions and DHCPv6 options, are configured using the
+:isccmd:`remote-class6-set` command.
+
+The :ref:`cb-sharing` section explains the concept of shareable
+and non-shareable configuration elements and the limitations for
+sharing them between multiple servers. In the DHCP configuration (both DHCPv4
+and DHCPv6), the shareable configuration elements are subnets and shared
+networks. Thus, they can be explicitly associated with multiple server tags.
+The global parameters, option definitions, and global options are non-shareable
+and can be associated with only one server tag. This rule does not apply
+to the configuration elements associated with ``all`` servers. Any configuration
+element associated with ``all`` servers (using the ``all`` keyword as a server tag) is
+used by all servers connecting to the configuration database.
+
+The following table lists DHCPv6-specific parameters supported by the
+Configuration Backend, with an indication of the level of the hierarchy
+at which it is currently supported.
+
+.. table:: List of DHCPv6 parameters supported by the Configuration Backend
+
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | Parameter | Global | Client | Shared | Subnet | Pool | Prefix |
+ | | | Class | Network | | | Delegation |
+ | | | | | | | Pool |
+ +=============================+============================+===========+===========+===========+===========+============+
+ | allocator | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | cache-max-age | yes | n/a | no | no | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | cache-threshold | yes | n/a | no | no | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | calculate-tee-times | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | client-class | n/a | n/a | yes | yes | yes | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-send-update | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-override-no-update | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-override-client-update | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-replace-client-name | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-generated-prefix | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | ddns-qualifying-suffix | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | decline-probation-period | yes | n/a | n/a | n/a | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | delegated-len | n/a | n/a | n/a | n/a | n/a | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | dhcp4o6-port | yes | n/a | n/a | n/a | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | excluded-prefix | n/a | n/a | n/a | n/a | n/a | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | excluded-prefix-len | n/a | n/a | n/a | n/a | n/a | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | hostname-char-set | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | hostname-char-replacement | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | interface | n/a | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | interface-id | n/a | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | max-preferred-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | max-valid-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | min-preferred-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | min-valid-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | option-data | yes (via | yes | yes | yes | yes | yes |
+ | | remote-option6-global-set) | | | | | |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | option-def | yes (via | yes | n/a | n/a | n/a | n/a |
+ | | remote-option-def6-set) | | | | | |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | pd-allocator | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | preferred-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | prefix | n/a | n/a | n/a | n/a | n/a | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | prefix-len | n/a | n/a | n/a | n/a | n/a | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | rapid-commit | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | rebind-timer | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | relay | n/a | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | renew-timer | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | require-client-classes | n/a | n/a | yes | yes | yes | yes |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | reservation-mode | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | reservations-global | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | reservations-in-subnet | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | reservations-out-of-pool | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | t1-percent | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | t2-percent | yes | n/a | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+ | valid-lifetime | yes | yes | yes | yes | n/a | n/a |
+ +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+
+
+- ``yes`` - indicates that the parameter is supported at the given
+ level of the hierarchy and can be configured via the Configuration Backend.
+
+- ``no`` - indicates that a parameter is supported at the given level
+ of the hierarchy but cannot be configured via the Configuration Backend.
+
+- ``n/a`` - indicates that a given parameter is not applicable
+ at the particular level of the hierarchy or that the
+ server does not support the parameter at that level.
+
+Some scalar parameters contained by top level global maps are supported by the Configuration Backend.
+
+.. table:: List of DHCPv6 map parameters supported by the Configuration Backend
+
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | Parameter name (flat naming format) | Global map | Parameter name |
+ +==================================================================+==============================+==================================+
+ | compatibility.lenient-option-parsing | compatibility | lenient-option-parsing |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | control-socket.socket-name | control-socket | socket-name |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | control-socket.socket-type | control-socket | socket-type |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.enable-updates | dhcp-ddns | enable-updates |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.max-queue-size | dhcp-ddns | max-queue-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.ncr-format | dhcp-ddns | ncr-format |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.ncr-protocol | dhcp-ddns | ncr-protocol |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.sender-ip | dhcp-ddns | sender-ip |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.sender-port | dhcp-ddns | sender-port |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.server-ip | dhcp-ddns | server-ip |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.server-port | dhcp-ddns | server-port |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.generated-prefix | dhcp-ddns | generated-prefix |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.hostname-char-replacement | dhcp-ddns | hostname-char-replacement |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.hostname-char-set | dhcp-ddns | hostname-char-set |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.override-client-update | dhcp-ddns | override-client-update |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.override-no-update | dhcp-ddns | override-no-update |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.qualifying-suffix | dhcp-ddns | qualifying-suffix |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-ddns.replace-client-name | dhcp-ddns | replace-client-name |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.flush-reclaimed-timer-wait-time | expired-leases-processing | flush-reclaimed-timer-wait-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.hold-reclaimed-time | expired-leases-processing | hold-reclaimed-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.max-reclaim-leases | expired-leases-processing | max-reclaim-leases |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.max-reclaim-time | expired-leases-processing | max-reclaim-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.reclaim-timer-wait-time | expired-leases-processing | reclaim-timer-wait-time |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | expired-leases-processing.unwarned-reclaim-cycles | expired-leases-processing | unwarned-reclaim-cycles |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.enable-multi-threading | multi-threading | enable-multi-threading |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.thread-pool-size | multi-threading | thread-pool-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | multi-threading.packet-queue-size | multi-threading | packet-queue-size |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | sanity-checks.lease-checks | sanity-checks | lease-checks |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | sanity-checks.extended-info-checks | sanity-checks | extended-info-checks |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | server-id.type | server-id | type |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | server-id.enterprise-id | server-id | enterprise-id |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | server-id.identifier | server-id | identifier |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | server-id.persist | server-id | persist |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.enable-queue | dhcp-queue-control | enable-queue |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.queue-type | dhcp-queue-control | queue-type |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+ | dhcp-queue-control.capacity | dhcp-queue-control | capacity |
+ +------------------------------------------------------------------+------------------------------+----------------------------------+
+
+.. _dhcp6-cb-json:
+
+Enabling the Configuration Backend
+----------------------------------
+
+Consider the following configuration snippet, which uses a MySQL configuration
+database:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "server-tag": "my DHCPv6 server",
+ "config-control": {
+ "config-databases": [
+ {
+ "type": "mysql",
+ "name": "kea",
+ "user": "kea",
+ "password": "kea",
+ "host": "2001:db8:1::1",
+ "port": 3302
+ }
+ ],
+ "config-fetch-wait-time": 20
+ },
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_mysql_cb.so"
+ },
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so"
+ }
+ ]
+ }
+ }
+
+The configuration structure is almost identical to that of the DHCPv4 server
+(see :ref:`dhcp4-cb-json` for the detailed description).
+
+.. _dhcp6-compatibility:
+
+Kea DHCPv6 Compatibility Configuration Parameters
+=================================================
+
+ISC's intention is for Kea to follow the RFC documents to promote better standards
+compliance. However, many buggy DHCP implementations already exist that cannot be
+easily fixed or upgraded. Therefore, Kea provides an easy-to-use compatibility
+mode for broken or non-compliant clients. For that purpose, the compatibility option must be
+enabled to permit uncommon practices:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "compatibility": {
+ }
+ }
+ }
+
+
+Lenient Option Parsing
+----------------------
+
+By default, DHCPv6 option 16's ``vendor-class-data`` field is parsed as a set of
+length-value pairs. Same for tuple fields defined in custom options.
+
+With ``"lenient-option-parsing": true``, if a length ever exceeds the rest of
+the option's buffer, previous versions of Kea returned a log message ``unable to
+parse the opaque data tuple, the buffer length is x, but the tuple length is y``
+with ``x < y``; this no longer occurs. Instead, the value is considered to be the rest of the buffer,
+or in terms of the log message above, the tuple length ``y`` becomes ``x``.
+
+Enabling this flag is expected to improve compatibility with devices such as RAD
+MiNID.
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "compatibility": {
+ "lenient-option-parsing": true
+ }
+ }
+ }
+
+.. _dhcp6_allocation_strategies:
+
+Allocation Strategies in DHCPv6
+===============================
+
+A DHCP server follows a complicated algorithm to select a DHCPv6 lease for a client.
+It prefers assigning specific addresses or delegated prefixes requested by the client
+and the ones for which the client has reservations.
+
+When the client requests a specific delegated prefix, there are a few steps that
+:iscman:`kea-dhcp6` goes through to try to satisfy the request, in the following
+order:
+
+1. It searches for a lease that matches the requested prefix and prefix length.
+2. It searches for a lease that matches the prefix length.
+3. It searches for a lease with a larger address space (smaller prefix length).
+4. It searches for a lease with a smaller address space (larger prefix length).
+
+If the client requests no particular
+lease and has no reservations, or other clients are already using any requested leases, the server must
+find another available lease within the configured pools. A server function called
+an "allocator" is responsible in Kea for finding an available lease in such a case.
+
+The Kea DHCPv6 server provides configuration parameters to select different allocators
+at the global, shared-network, and subnet levels. It also
+allows for selecting different allocation strategies for address assignments and
+prefix delegation.
+
+Consider the following example:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "allocator": "iterative",
+ "pd-allocator": "random",
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "allocator": "random"
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/64",
+ "pd-allocator": "iterative"
+ }
+ ]
+ }
+ }
+
+The iterative allocator is globally selected for address assignments, while the
+random allocator is globally selected for prefix delegation. These settings
+are selectively overridden at the subnet level.
+
+The following sections describe the supported allocators and their
+recommended uses.
+
+
+Allocators Comparison
+---------------------
+
+In the table below, we briefly compare the supported allocators. The
+detailed allocators' descriptions are in later sections.
+
+.. table:: Comparison of the lease allocators supported by Kea DHCPv6
+
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Allocator | Low Utilization Performance | High Utilization Performance | Lease Randomization | Startup/Configuration | Memory Usage |
+ +==================+=============================+==============================+=======================+==============================+================+
+ | Iterative | very high | low | no | very fast | low |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Random | high | low | yes | very fast | high (varying) |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+ | Free Lease Queue | high | high | yes | slow (depends on pool sizes) | high (varying) |
+ +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+
+
+
+Iterative Allocator
+-------------------
+This is the default allocator used by the Kea DHCPv6 server. It remembers the
+last offered lease and offers the following sequential lease to the next client.
+For example, it may offer addresses in this order: ``2001:db8:1::10``,
+``2001:db8:1::11``, ``2001:db8:1::12``, and so on. Similarly, it offers the
+next sequential delegated prefix after the previous one to the next client. The time to
+find and offer the next lease is very short; thus, this is the most performant
+allocator when pool utilization is low and there is a high probability
+that the next selected lease is available.
+
+The iterative allocation underperforms when multiple DHCP servers share a lease
+database or are connected to a cluster. The servers tend to offer and allocate
+the same blocks of addresses to different clients independently, which causes many
+allocation conflicts between the servers and retransmissions by clients. A random
+allocation addresses this issue by dispersing the allocation order.
+
+Random Allocator
+----------------
+
+The random allocator uses a uniform randomization function to select offered
+addresses and delegated prefixes from subnet pools. It is suitable in deployments
+where multiple servers are connected
+to a shared database or a database cluster. By dispersing the offered leases, the
+servers minimize the risk of allocating the same lease to two different clients at
+the same or nearly the same time. In addition, it improves the server's
+resilience against attacks based on allocation predictability.
+
+The random allocator is, however, slightly slower than the iterative allocator.
+Moreover, it increases the server's memory consumption because it must remember
+randomized leases to avoid offering them repeatedly. Memory consumption grows
+with the number of offered leases; in other words, larger pools and more
+clients increase memory consumption by random allocation.
+
+Free Lease Queue Allocator (Prefix Delegation Only)
+---------------------------------------------------
+
+This is a sophisticated allocator whose use should be considered in subnets
+with highly utilized delegated prefix pools. In such cases, it can take a
+considerable amount of time for the iterative or random allocator to find
+an available prefix, because they must repeatedly check whether there is a
+valid lease for a prefix they will offer. The number of checks can be as
+high as the number of delegated prefixes in the subnet when the subnet pools
+are exhausted, which can have a direct negative impact on the DHCP response time for
+each request.
+
+The Free Lease Queue (FLQ) allocator tracks lease allocations and de-allocations
+and maintains a running list of available delegated prefixes for each pool.
+It allows an available lease to be selected within a constant time, regardless of
+the subnet pools' utilization. The allocator continuously updates the list of
+free leases by removing any allocated leases and adding released or
+reclaimed ones.
+
+The following configuration snippet shows how to select the FLQ allocator
+for prefix delegation in a subnet:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pd-allocator": "flq"
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ The Free Lease Queue allocator can only be used for DHCPv6 prefix delegation.
+ An attempt to use this allocator for address assignment (with the ``allocator``
+ parameter) will cause a configuration error. DHCPv6 address pools are
+ typically very large and their utilization is low; in these situation, the benefits
+ of using the FLQ allocator diminish. The amount of time required for the
+ allocator to populate the free lease queue would cause the server to freeze
+ upon startup.
+
+There are several considerations that the administrator should take into account
+before using this allocator for prefix delegation. The FLQ allocator can heavily
+impact the server's startup and reconfiguration time, because the allocator
+has to populate the list of free leases for each subnet where it is used.
+These delays can be observed both during the configuration reload and when
+the subnets are created using :ischooklib:`libdhcp_subnet_cmds.so`. The allocator
+increases the memory consumption to hold the list of free leases,
+proportional to the total size of the pools for which this allocator is used.
+Finally, lease reclamation must be enabled with a low value of the
+``reclaim-timer-wait-time`` parameter, to ensure that the server frequently
+collects expired leases and makes them available for allocation via the
+free lease queue. Expired leases are not considered free by
+the allocator until they are reclaimed by the server. See
+:ref:`lease-reclamation` for more details about the lease reclamation process.
+
+We recommend that the FLQ allocator be selected
+only after careful consideration. The server puts no restrictions on the
+delegated prefix pool sizes used with the FLQ allocator, so we advise users to
+test how long it takes for the server to load the pools before deploying the
+configuration using the FLQ allocator in production. We also recommend
+specifying another allocator type in the global configuration settings
+and overriding this selection at the subnet or shared-network level, to use
+the FLQ allocator only for selected subnets. That way, when a new subnet is
+added without an allocator specification, the global setting is used, thus
+avoiding unnecessary impact on the server's startup time.
+
+Like the random allocator, the FLQ allocator offers leases in
+random order, which makes it suitable for use with a shared lease database.
diff --git a/doc/sphinx/arm/ext-gss-tsig.rst b/doc/sphinx/arm/ext-gss-tsig.rst
new file mode 100644
index 0000000..404a15e
--- /dev/null
+++ b/doc/sphinx/arm/ext-gss-tsig.rst
@@ -0,0 +1,1303 @@
+.. _gss-tsig:
+
+GSS-TSIG
+========
+
+.. _gss-tsig-overview:
+
+GSS-TSIG Overview
+-----------------
+
+Kea provides support for DNS updates, which can be protected using
+Transaction Signatures (or TSIG). This protection is often adequate.
+However, some systems, in particular Active Directory (AD) on Microsoft
+Windows servers, have chosen to adopt a more complex GSS-TSIG approach that offers
+additional capabilities, such as using negotiated dynamic keys.
+
+Kea supports GSS-TSIG to protect DNS updates sent by
+the Kea DHCP-DDNS (D2) server in a premium hook, called :ischooklib:`libddns_gss_tsig.so`.
+
+GSS-TSIG is defined in `RFC 3645 <https://tools.ietf.org/html/rfc3645>`__.
+The GSS-TSIG protocol itself is an implementation of generic GSS-API v2
+services, defined in `RFC 2743 <https://tools.ietf.org/html/rfc2743>`__.
+
+Many protocols are involved in this mechanism:
+
+ - Kerberos 5 - `RFC 4120 <https://tools.ietf.org/html/rfc4120>`__, which
+ provides the security framework;
+ - GSS-API (Generic Security Services Application Program Interface) -
+ `RFC 2743 <https://tools.ietf.org/html/rfc2743>`__ for the API,
+ `RFC 2744 <https://tools.ietf.org/html/rfc2743>`__ for the C bindings, and
+ `RFC 4121 <https://tools.ietf.org/html/rfc4121>`__ for the application
+ to Kerberos 5;
+ - SPNEGO (Simple and Protected GSS-API Negotiation Mechanism) -
+ `RFC 4178 <https://tools.ietf.org/html/rfc4178>`__ for the negotiation;
+ - DNS update `RFC 2136 <https://tools.ietf.org/html/rfc2136>`__;
+ - TSIG (Secret Key Transaction Authentication for DNS) -
+ `RFC 8945 <https://tools.ietf.org/html/rfc8945>`__, which
+ protects DNS exchanges;
+ - Secure Domain Name System (DNS) Dynamic Update -
+ `RFC 3007 <https://tools.ietf.org/html/rfc3007>`__, which is the
+ application of TSIG to DNS update protection;
+ - TKEY (Secret Key Establishment for DNS) -
+ `RFC 2930 <https://tools.ietf.org/html/rfc2930>`__, which establishes
+ secret keys for TSIG by transmitting crypto payloads between DNS
+ parties; and
+ - GSS-TSIG - `RFC 3645 <https://tools.ietf.org/html/rfc3645>`__, which
+ is the application of GSS-API to TSIG.
+
+To summarize, GSS-API for Kerberos 5 with SPNEGO and TKEY are used to
+negotiate a security context between the Kea D2 server and a DNS server:
+
+.. figure:: ../uml/tkey.*
+
+The security context is then used by GSS-TSIG to protect updates:
+
+.. figure:: ../uml/update.*
+
+The Kea implementation of GSS-TSIG uses a GSS-API for Kerberos 5 with
+the SPNEGO library. Two implementations meet this criteria: MIT Kerberos
+5 and Heimdal.
+
+.. _gss-tsig-install:
+
+GSS-TSIG Compilation
+--------------------
+
+The following procedure was tested on Ubuntu 20.10 and 21.04. A similar
+approach can be applied to other systems.
+
+1. Obtain the Kea sources and premium packages, extract the Kea sources,
+ and then extract the premium packages into the ``premium/`` directory within the Kea
+ source tree.
+
+2. Run autoreconf:
+
+.. code-block:: console
+
+ autoreconf -i
+
+3. Make sure ``./configure --help`` shows the ``--with-gssapi`` option.
+
+4. Install either the MIT (``libkrb5-dev``) or the Heimdal (``heimdal-dev``) library,
+ for instance:
+
+.. code-block:: console
+
+ sudo apt install libkrb5-dev
+
+5. Run ``configure`` with the ``--with-gssapi`` option:
+
+.. code-block:: console
+
+ ./configure --with-gssapi
+
+.. note:
+
+ It is ``--with-gssapi`` (with no dash between "gss" and "api"), to maintain
+ consistency with the BIND 9 option.
+
+The ``--with-gssapi`` parameter requires the ``krb5-config`` tool to be present. This
+tool is provided by both MIT Kerberos 5 and Heimdal; however, on some systems
+where both Kerberos 5 and Heimdal are installed, it is a symbolic link
+to one of them. If the tool is not in the standard location, it can be specified
+with ``--with-gssapi=/path/to/krb5-config``. It is strongly recommended
+to use the default installation locations provided by the packages.
+
+The ``./configure`` script should complete with a successful GSS-API
+detection, similar to this:
+
+::
+
+ GSS-API support:
+ GSSAPI_CFLAGS: -isystem /usr/include/mit-krb5
+ GSSAPI_LIBS: -L/usr/lib/x86_64-linux-gnu/mit-krb5 -Wl,-Bsymbolic-functions -Wl,-z,relro -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err
+
+6. Compile ``make -jX``, where X is the number of CPU cores
+ available.
+
+7. After compilation, :ischooklib:`libddns_gss_tsig.so` is available in the
+ ``premium/src/hooks/d2/gss_tsig`` directory. It can be loaded by :iscman:`kea-dhcp-ddns`.
+
+:ischooklib:`libddns_gss_tsig.so` was developed using the MIT Kerberos 5 implementation, but
+Heimdal is also supported. Note that Heimdal is picky about
+security-sensitive file permissions and is known to emit an unclear error message.
+It is a good idea to keep these files plain, with one link and no
+access for the group or other users.
+
+The ``krb5-config`` script should provide an ``--all`` option which
+identifies the implementation.
+
+.. _gss-tsig-deployment:
+
+GSS-TSIG Deployment
+-------------------
+
+Before using GSS-TSIG, a GSS-TSIG capable DNS server, such as BIND 9
+or Microsoft Active Directory (AD), must be deployed. Other
+GSS-TSIG capable implementations may work, but have not been tested.
+
+Kerberos 5 Setup
+~~~~~~~~~~~~~~~~
+
+There are two kinds of key tables (keytab files): the system one used
+by servers, and client tables used by clients. For Kerberos 5, Kea is a
+**client**.
+
+Install the Kerberos 5 client library and ``kadmin`` tool:
+
+.. code-block:: console
+
+ sudo apt install krb5-kdc krb5-admin-server
+
+The following examples use the ``EXAMPLE.ORG`` realm to demonstrate required
+configuration steps and settings.
+
+The Kerberos 5 client library must be configured to accept incoming requests
+for the realm ``EXAMPLE.ORG`` by updating the ``krb5.conf`` file
+(e.g. on Linux: /etc/krb5.conf):
+
+.. code-block:: ini
+
+ [libdefaults]
+ default_realm = EXAMPLE.ORG
+ kdc_timesync = 1
+ ccache_type = 4
+ forwardable = true
+ proxiable = true
+
+ [realms]
+ EXAMPLE.ORG = {
+ kdc = kdc.example.org
+ admin_server = kdc.example.org
+ }
+
+In addition to the ``krb5.conf`` file, the ``kdc.conf`` file can be used
+(e.g. on Linux: /etc/krb5kdc/kdc.conf):
+
+.. code-block:: ini
+
+ [kdcdefaults]
+ kdc_ports = 750,88
+
+ [realms]
+ EXAMPLE.ORG = {
+ database_name = /var/lib/krb5kdc/principal
+ admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
+ acl_file = /etc/krb5kdc/kadm5.acl
+ key_stash_file = /etc/krb5kdc/stash
+ kdc_ports = 750,88
+ max_life = 10h 0m 0s
+ max_renewable_life = 7d 0h 0m 0s
+ master_key_type = des3-hmac-sha1
+ #supported_enctypes = aes256-cts:normal aes128-cts:normal
+ default_principal_flags = +preauth
+ }
+
+The ``kadmind`` daemon Access Control List (ACL) must be configured to give
+permissions to the DNS client principal to access the Kerberos 5 database
+(e.g. on Linux: /etc/krb5kdc/kadm5.acl):
+
+.. code-block:: ini
+
+ DHCP/admin.example.org@EXAMPLE.ORG *
+
+The administrator password for the default realm must be set:
+
+.. code-block:: console
+
+ krb5_newrealm
+
+After the following message is displayed, enter
+the password for the default realm:
+
+.. code-block:: console
+
+ This script should be run on the master KDC/admin server to initialize
+ a Kerberos realm. It will ask you to type in a master key password.
+ This password will be used to generate a key that is stored in
+ /etc/krb5kdc/stash. You should try to remember this password, but it
+ is much more important that it be a strong password than that it be
+ remembered. However, if you lose the password and /etc/krb5kdc/stash,
+ you cannot decrypt your Kerberos database.
+ Loading random data
+ Initializing database '/var/lib/krb5kdc/principal' for realm 'EXAMPLE.ORG',
+ master key name 'K/M@EXAMPLE.ORG'
+ You will be prompted for the database Master Password.
+ It is important that you NOT FORGET this password.
+ Enter KDC database master key:
+
+Then retype the password:
+
+.. code-block:: console
+
+ Re-enter KDC database master key to verify:
+
+If successfully applied, the following message is displayed:
+
+.. code-block:: console
+
+ Now that your realm is set up you may wish to create an administrative
+ principal using the addprinc subcommand of the kadmin.local program.
+ Then, this principal can be added to /etc/krb5kdc/kadm5.acl so that
+ you can use the kadmin program on other computers. Kerberos admin
+ principals usually belong to a single user and end in /admin. For
+ example, if jruser is a Kerberos administrator, then in addition to
+ the normal jruser principal, a jruser/admin principal should be
+ created.
+
+ Don't forget to set up DNS information so your clients can find your
+ KDC and admin servers. Doing so is documented in the administration
+ guide.
+
+The next step is to create the principals for the BIND 9 DNS server
+(the service protected by the GSS-TSIG TKEY) and for the DNS client
+(the Kea DHCP-DDNS server).
+
+The BIND 9 DNS server principal (used for authentication) is created the
+following way:
+
+.. code-block:: console
+
+ kadmin.local -q "addprinc -randkey DNS/server.example.org"
+
+If successfully created, the following message is displayed:
+
+.. code-block:: console
+
+ No policy specified for DNS/server.example.org@EXAMPLE.ORG; defaulting to no policy
+ Authenticating as principal root/admin@EXAMPLE.ORG with password.
+ Principal "DNS/server.example.org@EXAMPLE.ORG" created.
+
+The DNS server principal must be exported so that it can be used by the BIND 9
+DNS server. Only this principal is required, and it is exported to the keytab
+file with the name ``dns.keytab``.
+
+.. code-block:: console
+
+ kadmin.local -q "ktadd -k /tmp/dns.keytab DNS/server.example.org"
+
+If successfully exported, the following message is displayed:
+
+.. code-block:: console
+
+ Authenticating as principal root/admin@EXAMPLE.ORG with password.
+ Entry for principal DNS/server.example.org with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
+ Entry for principal DNS/server.example.org with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
+
+The DHCP client principal (used by the Kea DHCP-DDNS server) is created the
+following way:
+
+.. code-block:: console
+
+ kadmin.local -q "addprinc -randkey DHCP/admin.example.org"
+
+If successfully created, the following message is displayed:
+
+.. code-block:: console
+
+ No policy specified for DHCP/admin.example.org@EXAMPLE.ORG; defaulting to no policy
+ Authenticating as principal root/admin@EXAMPLE.ORG with password.
+ Principal "DHCP/admin.example.org@EXAMPLE.ORG" created.
+
+The DHCP client principal must be exported so that it can be used by the
+Kea DHCP-DDNS server and the GSS-TSIG hook library. It is exported to the client
+keytab file with the name ``dhcp.keytab``.
+
+.. code-block:: console
+
+ kadmin.local -q "ktadd -k /tmp/dhcp.keytab DHCP/admin.example.org"
+
+Finally, the ``krb5-admin-server`` must be restarted:
+
+.. code-block:: console
+
+ systemctl restart krb5-admin-server.service
+
+BIND 9 with GSS-TSIG Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The BIND 9 DNS server must be configured to use GSS-TSIG, and to use the
+previously exported DNS server principal from the keytab file ``dns.keytab``.
+Updating the ``named.conf`` file is required:
+
+.. code-block:: console
+
+ options {
+ ...
+ directory "/var/cache/bind";
+ dnssec-validation auto;
+ listen-on-v6 { any; };
+ tkey-gssapi-keytab "/etc/bind/dns.keytab";
+ };
+ zone "example.org" {
+ type master;
+ file "/var/lib/bind/db.example.org";
+ update-policy {
+ grant "DHCP/admin.example.org@EXAMPLE.ORG" zonesub any;
+ };
+ };
+ zone "84.102.10.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.10";
+ };
+
+The zone files should have an entry for the server principal FQDN
+``server.example.org``.
+
+The ``/etc/bind/db.10`` file needs to be created or updated:
+
+.. code-block:: console
+
+ ;
+ ; BIND reverse data file for local loopback interface
+ ;
+ $TTL 604800 ; 1 week
+ @ IN SOA server.example.org. root.example.org. (
+ 2 ; Serial
+ 604800 ; Refresh
+ 86400 ; Retry
+ 2419200 ; Expire
+ 604800 ; Negative Cache TTL
+ )
+ ;
+ @ IN NS ns.
+ 40 IN PTR ns.example.org.
+
+The ``/var/lib/bind/db.example.org`` file needs to be created or updated:
+
+.. code-block:: console
+
+ $ORIGIN .
+ $TTL 604800 ; 1 week
+ example.org IN SOA server.example.org. root.example.org. (
+ 8 ; serial
+ 604800 ; refresh (1 week)
+ 86400 ; retry (1 day)
+ 2419200 ; expire (4 weeks)
+ 604800 ; minimum (1 week)
+ )
+ NS example.org.
+ A ${BIND9_IP_ADDR}
+ AAAA ::1
+ $ORIGIN example.org.
+ kdc A ${KDC_IP_ADDR}
+ server A ${BIND9_IP_ADDR}
+
+After any configuration change the server must be reloaded or
+restarted:
+
+.. code-block:: console
+
+ systemctl restart named.service
+
+It is possible to get the status or restart the logs:
+
+.. code-block:: console
+
+ systemctl status named.service
+ journalctl -u named | tail -n 30
+
+Windows Active Directory Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This sub-section is based on an Amazon AWS provided Microsoft Windows Server
+2016 with Active Directory pre-installed, so it describes only the steps used
+for GSS-TSIG deployment. (For the complete configuration process, please refer to
+Microsoft's documentation or other external resources. We found `this <https://www.tenforums.com/tutorials/51456-windows-server-2016-setup-local-domain-controller.html>`__ tutorial very
+useful during configuration of our internal QA testing systems.)
+
+Two Active Directory (AD) user accounts are needed:
+ - the first account is used to download AD information, such as
+ the client key table of Kea
+ - the second account is mapped to the Kea DHCP client principal
+
+Kea needs to know:
+ - the server IP address
+ - the domain/realm name: the domain is in lower case, the realm in upper
+ case, both without a final dot
+ - the server name
+
+The second account (named ``kea`` below) is used to create a Service
+Principal Name (SPN):
+
+.. code-block:: console
+
+ setspn -S DHCP/kea.<domain> kea
+
+After a shared secret key is generated and put in a key table file:
+
+.. code-block:: console
+
+ ktpass -princ DHCP/kea.<domain>@<REALM> -mapuser kea +rndpass -mapop set -ptype KRB5_NT_PRINCIPAL -out dhcp.keytab
+
+The ``dhcp.keytab`` takes the same usage as for UNIX Kerberos.
+
+GSS-TSIG Troubleshooting
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+While testing GSS-TSIG integration with Active Directory we came across
+one very cryptic error:
+
+.. code-block:: console
+
+ INFO [kea-dhcp-ddns.gss-tsig-hooks/4678.139690935890624] GSS_TSIG_VERIFY_FAILED GSS-TSIG verify failed: gss_verify_mic failed with GSSAPI error:
+ Major = 'A token had an invalid Message Integrity Check (MIC)' (393216), Minor = 'Packet was replayed in wrong direction' (100002).
+
+In our case, the problem was that the Kea D2 server was trying to perform an update of a reverse
+DNS zone while it was not configured. An easy solution is to add a reverse DNS
+zone similar to the one configured in Kea. To do that, open the "DNS Manager" and choose
+"DNS" from the list; from the dropdown list, choose "Reverse Lookup Zones"; then
+click "Action" and "New Zone"; finally, follow the New Zone Wizard to add a new zone.
+
+The standard requires both anti-replay and sequence services. Experiences with the BIND 9 nsupdate
+showed the sequence service led to problems so it is disabled by default in the hook. It seems
+the anti-replay service can also lead to problems with Microsoft DNS servers so it is now
+configurable. Note that these security services are useless for DNS dynamic update which was
+designed to run over UDP so with out of order and duplicated messages.
+
+.. _gss-tsig-using:
+
+Using GSS-TSIG
+--------------
+
+There are a number of steps required to enable the GSS-TSIG mechanism:
+
+1. :ischooklib:`libddns_gss_tsig.so` must be loaded by :iscman:`kea-dhcp-ddns`.
+2. The GSS-TSIG-capable DNS servers must be specified with their parameters.
+
+An excerpt from a D2 server configuration is provided below; more examples are available in the
+``doc/examples/ddns`` directory in the Kea sources.
+
+.. code-block:: javascript
+ :linenos:
+ :emphasize-lines: 57-117
+
+
+ {
+ "DhcpDdns": {
+ // The following parameters are used to receive NCRs (NameChangeRequests)
+ // from the local Kea DHCP server. Make sure your kea-dhcp4 and kea-dhcp6
+ // matches this.
+ "ip-address": "127.0.0.1",
+ "port": 53001,
+ "dns-server-timeout" : 1000,
+
+ // Forward zone: secure.example.org. It uses GSS-TSIG. It is served
+ // by two DNS servers, which listen for DDNS requests at 192.0.2.1
+ // and 192.0.2.2.
+ "forward-ddns":
+ {
+ "ddns-domains":
+ [
+ // DdnsDomain for zone "secure.example.org."
+ {
+ "name": "secure.example.org.",
+ "comment": "DdnsDomain example",
+ "dns-servers":
+ [
+ { // This server has an entry in gss/servers and
+ // thus will use GSS-TSIG.
+ "ip-address": "192.0.2.1"
+ },
+ { // This server also has an entry there, so will
+ // use GSS-TSIG, too.
+ "ip-address": "192.0.2.2",
+ "port": 5300
+ }
+ ]
+ }
+ ]
+ },
+
+ // Reverse zone: we want to update the reverse zone "2.0.192.in-addr.arpa".
+ "reverse-ddns":
+ {
+ "ddns-domains":
+ [
+ {
+ "name": "2.0.192.in-addr.arpa.",
+ "dns-servers":
+ [
+ {
+ // There is a GSS-TSIG definition for this server (see
+ // DhcpDdns/gss-tsig/servers), so it will use
+ // Krb/GSS-TSIG.
+ "ip-address": "192.0.2.1"
+ }
+ ]
+ }
+ ]
+ },
+
+ // The GSS-TSIG hook is loaded and its configuration is specified here.
+ "hooks-libraries": [
+ {
+ "library": "/opt/lib/libddns_gss_tsig.so",
+ "parameters": {
+ // This section governs the GSS-TSIG integration. Each server
+ // mentioned in forward-ddns and/or reverse-ddns needs to have
+ // an entry here to be able to use GSS-TSIG defaults (optional,
+ // if specified they apply to all the GSS-TSIG servers, unless
+ // overwritten on specific server level).
+
+ "server-principal": "DNS/server.example.org@EXAMPLE.ORG",
+ "client-principal": "DHCP/admin.example.org@EXAMPLE.ORG",
+
+ // client-keytab and credentials-cache can both be used to
+ // store client keys. As credentials cache is more flexible,
+ // it is recommended to use it. Typically, using both at the
+ // same time may cause problems.
+ // "client-keytab": "FILE:/etc/dhcp.keytab", // toplevel only
+ "credentials-cache": "FILE:/etc/ccache", // toplevel only
+ "gss-replay-flag": true, // GSS anti replay service
+ "gss-sequence-flag": false, // no GSS sequence service
+ "tkey-lifetime": 3600, // 1 hour
+ "rekey-interval": 2700, // 45 minutes
+ "retry-interval": 120, // 2 minutes
+ "tkey-protocol": "TCP",
+ "fallback": false,
+
+ // The list of GSS-TSIG capable servers
+ "servers": [
+ {
+ // First server (identification is required)
+ "id": "server1",
+ "domain-names": [ ], // if not specified or empty, will
+ // match all domains that want to
+ // use this IP+port pair
+ "ip-address": "192.0.2.1",
+ "port": 53,
+ "server-principal": "DNS/server1.example.org@EXAMPLE.ORG",
+ "client-principal": "DHCP/admin1.example.org@EXAMPLE.ORG",
+ "gss-replay-flag": false, // no GSS anti replay service
+ "gss-sequence-flag": false, // no GSS sequence service
+ "tkey-lifetime": 7200, // 2 hours
+ "rekey-interval": 5400, // 90 minutes
+ "retry-interval": 240, // 4 minutes
+ "tkey-protocol": "TCP",
+ "fallback": true // if no key is available fallback to the
+ // standard behavior (vs skip this server)
+ },
+ {
+ // The second server (it has most of the parameters missing
+ // as those are using the defaults specified above)
+ "id": "server2",
+ "ip-address": "192.0.2.2",
+ "port": 5300
+ }
+ ]
+ }
+ }
+ ]
+
+ // Additional parameters, such as logging, control socket and
+ // others omitted for clarity.
+ }
+
+ }
+
+This configuration file contains a number of extra elements.
+
+First, a list of forward and/or reverse domains with related DNS servers
+identified by their IP+port pairs is defined. If the port is not
+specified, the default of 53 is assumed. This is similar to basic mode, with no
+authentication done using TSIG keys, with the
+exception that static TSIG keys are not referenced by name.
+
+Second, :ischooklib:`libddns_gss_tsig.so` must be specified on the
+``hooks-libraries`` list. This hook takes many parameters. The most important
+one is ``servers``, which is a list of GSS-TSIG-capable servers. If there are
+several servers and they share some characteristics, the values can be specified
+in the ``parameters`` scope as defaults. In the example above, the defaults that apply
+to all servers, unless otherwise specified on a per-server scope, are defined in
+lines 63 through 68. The defaults can be skipped if there is only one server
+defined, or if all servers have different values.
+
+.. table:: List of available parameters
+
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | Name | Scope | Type | Default value | Description |
+ | | | | | |
+ +===================+==========+=========+=====================+================================+
+ | client-keytab | global / | string | empty | the Kerberos **client** key |
+ | | server | | | table |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | credentials-cache | global / | string | empty | the Kerberos credentials cache |
+ | | server | | | |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | server-principal | global / | string | empty | the Kerberos principal name of |
+ | | server | | | the DNS server that will |
+ | | | | | receive updates |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | client-principal | global / | string | empty | the Kerberos principal name of |
+ | | server | | | the Kea D2 service |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | gss-replay-flag | global / | true / | true | require the GSS anti replay |
+ | | server | false | | service (GSS_C_REPLAY_FLAG) |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | gss-sequence-flag | global / | true / | false | require the GSS sequence |
+ | | server | false | | service (GSS_C_SEQUENCE_FLAG) |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | tkey-protocol | global / | string | "TCP" | the protocol used to establish |
+ | | server | "TCP" / | | the security context with the |
+ | | | "UDP" | | DNS servers |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | tkey-lifetime | global / | uint32 | | 3600 seconds | the lifetime of GSS-TSIG keys |
+ | | server | | | ( 1 hour ) | |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | rekey-interval | global / | uint32 | | 2700 seconds | the time interval the keys are |
+ | | server | | | ( 45 minutes ) | checked for rekeying |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | retry-interval | global / | uint32 | | 120 seconds | the time interval to retry to |
+ | | server | | | ( 2 minutes ) | create a key if any error |
+ | | | | | occurred previously |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | fallback | global / | true / | false | the behavior to fallback to |
+ | | server | false | | non-GSS-TSIG when GSS-TSIG |
+ | | | | | should be used but no GSS-TSIG |
+ | | | | | key is available. |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | exchange-timeout | global / | uint32 | | 3000 milliseconds | the time used to wait for the |
+ | | server | | | ( 3 seconds ) | GSS-TSIG TKEY exchange to |
+ | | | | | finish before it timeouts |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | user-context | global / | string | empty | the user-provided data in JSON |
+ | | server | | | format (not used by |
+ | | | | | the GSS-TSIG hook) |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | comment | global / | string | empty | ignored |
+ | | server | | | |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | id | server | string | empty | identifier to a DNS server |
+ | | | | | (required) |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | domain-names | server | list of | empty | the many-to-one relationship |
+ | | | strings | | between D2 DNS servers and |
+ | | | | | GSS-TSIG DNS servers |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | ip-address | server | IPv4 / | empty | the IP address at which the |
+ | | | IPv6 | | GSS-TSIG DNS server listens |
+ | | | address | | for DDNS and TKEY requests |
+ | | | | | (required) |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+ | port | server | uint16 | 53 | the DNS transport port at |
+ | | | | | which the GSS-TSIG DNS server |
+ | | | | | listens for DDNS and TKEY |
+ | | | | | requests |
+ +-------------------+----------+---------+---------------------+--------------------------------+
+
+The global parameters are described below:
+
+- ``client-keytab`` specifies the Kerberos **client** key table.
+ For instance, ``FILE:<filename>`` can be used to point to a specific file.
+ This parameter can be specified only once, in the parameters scope,
+ and is the equivalent of setting the ``KRB5_CLIENT_KTNAME`` environment
+ variable. An empty value is silently ignored.
+
+- ``credentials-cache`` specifies the Kerberos credentials cache.
+ For instance, ``FILE:<filename>`` can be used to point to a file or,
+ if using a directory which supports more than one principal,
+ ``DIR:<directory-path>``.
+ This parameter can be specified only once, in the parameters scope,
+ and is the equivalent of setting the ``KRB5CCNAME`` environment
+ variable. An empty value is silently ignored.
+
+- ``server-principal`` is the Kerberos principal name of the DNS
+ server that receives updates. In other words, this is the
+ DNS server's name in the Kerberos system. This parameter is
+ mandatory, and uses the typical Kerberos notation:
+ ``<SERVICE-NAME>/<server-domain-name>@<REALM>``.
+
+- ``client-principal`` is the Kerberos principal name of the Kea D2
+ service. It is optional, and uses the typical Kerberos notation:
+ ``<SERVICE-NAME>/<server-domain-name>@<REALM>``.
+
+- ``gss-replay-flag`` determines if the GSS anti replay service is
+ required. It is by default but this can be disabled.
+
+- ``gss-sequence-flag`` determines if the GSS sequence service is
+ required. It is not by default but is required by the standard
+ so it can be enabled.
+
+- ``tkey-protocol`` determines which protocol is used to establish the
+ security context with the DNS servers. Currently, the only supported
+ values are TCP (the default) and UDP.
+
+- ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the
+ TKEY protocol. The value must be greater than the ``rekey-interval``
+ value. It is expressed in seconds and defaults to 3600 (one hour).
+
+- ``rekey-interval`` governs the time interval at which the keys for each configured
+ server are checked for rekeying, i.e. when a new key is created to replace the
+ current usable one if its age is greater than the ``rekey-interval`` value.
+ The value must be smaller than the ``tkey-lifetime`` value (it is recommended
+ to be set between 50% and 80% of the ``tkey-lifetime`` value). It is expressed in
+ seconds and defaults to 2700 (45 minutes, or 75% of one hour).
+
+- ``retry-interval`` governs the time interval at which to retry to create a key if any
+ error occurred previously for any configured server. The value must be smaller
+ than the ``rekey-interval`` value, and should be at most 1/3 of the difference
+ between ``tkey-lifetime`` and ``rekey-interval``. It is expressed in seconds
+ and defaults to 120 (2 minutes).
+
+- ``fallback`` governs the behavior when GSS-TSIG should be used (a
+ matching DNS server is configured) but no GSS-TSIG key is available.
+ If set to ``false`` (the default), this server is skipped; if
+ set to ``true``, the DNS server is ignored and the DNS update
+ is sent with the configured DHCP-DDNS protection (e.g. TSIG key), or
+ without any protection when none was configured.
+
+- ``exchange-timeout`` governs the amount of time to wait for the GSS-TSIG TKEY
+ exchange to finish before the process times out. It is expressed in milliseconds and
+ defaults to 3000 (3 seconds).
+
+- ``user-context`` is an optional parameter (see :ref:`user-context`
+ for a general description of user contexts in Kea).
+
+- ``comment`` is allowed but currently ignored.
+
+- ``servers`` specifies the list of DNS servers where GSS-TSIG is enabled.
+
+The server map parameters are described below:
+
+- ``id`` assigns an identifier to a DNS server. It is used for statistics
+ and commands. It is required, and must be both not empty and unique.
+
+- ``domain-names`` governs the many-to-one relationship between D2 DNS
+ servers and GSS-TSIG DNS servers: for each domain name on this list,
+ Kea looks for a D2 DNS server for this domain with the specified IP address
+ and port. An empty list (the default) means that all domains
+ match.
+
+- ``ip-address`` specifies the IP address at which the GSS-TSIG DNS server
+ listens for DDNS and TKEY requests. It is a mandatory parameter.
+
+- ``port`` specifies the DNS transport port on which the GSS-TSIG DNS server
+ listens for DDNS and TKEY requests. It defaults to 53.
+
+- ``server-principal`` is the Kerberos principal name of the DNS server
+ that receives updates. The ``server-principal`` parameter set at the per-server
+ level takes precedence over one set at the global level. It is a mandatory parameter which must be specified at
+ either the global or the server level.
+
+- ``client-principal`` is the Kerberos principal name of the Kea D2
+ service for this DNS server. The ``client-principal`` parameter set at the per-server
+ level takes precedence over one set at the global level. It is an optional parameter.
+
+- ``gss-replay-flag`` determines if the GSS anti replay service is
+ required. The ``gss-replay-flag`` parameter set at the per-server
+ level takes precedence over one set at the global level. It is an optional parameter
+ which defaults to true.
+
+- ``gss-sequence-flag`` determines if the GSS sequence service is
+ required. The ``gss-sequence-flag`` parameter set at the per-server
+ level takes precedence over one set at the global level. It is an optional parameter
+ which defaults to false.
+
+- ``tkey-protocol`` determines which protocol is used to establish the
+ security context with the DNS server. The ``tkey-protocol`` parameter set at the per-server
+ level takes precedence over one set at the global level. The default and supported values
+ for the per-server level parameter are the same as
+ for the global-level parameter.
+
+- ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the
+ TKEY protocol for the DNS server. The ``tkey-lifetime`` parameter set at the per-server
+ level takes precedence over one set at the global level. The default and supported values
+ for the per-server level parameter are the same as
+ for the global-level parameter.
+
+- ``rekey-interval`` governs the time interval at which the keys for this particular
+ server are checked for rekeying, i.e. when a new key is created to replace the
+ current usable one if its age is greater than the ``rekey-interval`` value.
+ The value must be smaller than the ``tkey-lifetime`` value (it is recommended
+ to be set between 50% and 80% of the ``tkey-lifetime`` value). The ``rekey-interval``
+ parameter set at the per-server level takes precedence over one set at the global
+ level. The default and supported values for the per-server level parameter are the same as
+ for the global-level parameter.
+
+- ``retry-interval`` governs the time interval at which to retry to create a key if any
+ error occurred previously for this particular server. The value must be
+ smaller than the ``rekey-interval`` value, and should be at most 1/3 of the
+ difference between ``tkey-lifetime`` and ``rekey-interval``. The
+ ``retry-interval`` parameter set at the per-server level takes precedence over one set at the global
+ level. The default and supported values for the per-server level parameter are the same as
+ for the global-level parameter.
+
+- ``fallback`` governs the behavior when GSS-TSIG should be used (a
+ matching DNS server is configured) but no GSS-TSIG key is available.
+ The ``fallback`` parameter set at the per-server level takes precedence over one set at the global
+ level. The default and supported values for the per-server level parameter are the same as
+ for the global-level parameter..
+
+- ``exchange-timeout`` governs the amount of time to wait for the GSS-TSIG TKEY
+ exchange to finish before the process times out. The ``exchange-timeout`` parameter
+ set at the per-server level takes precedence over one set at the global
+ level. The default and supported values for the per-server level parameter are the same as
+ for the global-level parameter.
+
+- ``user-context`` is an optional parameter (see :ref:`user-context`
+ for a general description of user contexts in Kea).
+
+- ``comment`` is allowed but currently ignored.
+
+.. note::
+
+ Generally it is not recommended to specify both the client keytab (``client-keytab``)
+ and the credentials cache (``credentials-cache``), although this may
+ differ between Kerberos implementations. The client keytab is just for
+ the client key and is typically used to specify the key explicitly in more
+ static manner, while the credentials cache can be used to store multiple
+ credentials and can be dynamically updated by the Kerberos library. As such,
+ the credentials-cache is more flexible and thus the recommended alternative.
+
+ Also note that only the read access right is needed to use the cache.
+ Fetching credentials and updating the cache requires the write access
+ right.
+
+
+GSS-TSIG Automatic Key Removal
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server periodically deletes keys after they have been expired more than three times the
+length of the maximum key lifetime (the ``tkey-lifetime`` parameter).
+The user has the option to purge keys on demand by using the :isccmd:`gss-tsig-purge-all`
+command or the :isccmd:`gss-tsig-purge` command.
+
+
+GSS-TSIG Configuration for Deployment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using Kerberos 5 and BIND 9 as described in :ref:`gss-tsig-deployment`,
+the local resolver must point to the BIND 9 ``named`` server address. The
+local Kerberos must also be configured by putting the following text into the ``krb5.conf`` file:
+
+.. code-block:: ini
+
+ [libdefaults]
+ default_realm = EXAMPLE.ORG
+ kdc_timesync = 1
+ ccache_type = 4
+ forwardable = true
+ proxiable = true
+ [realms]
+ EXAMPLE.ORG = {
+ kdc = kdc.example.org
+ admin_server = kdc.example.org
+ }
+
+With Windows AD, the DNS service is provided by AD, which also provides
+the Kerberos service. The required text in the ``krb5.conf`` file becomes:
+
+.. code-block:: ini
+
+ [libdefaults]
+ default_realm = <REALM>
+ kdc_timesync = 1
+ ccache_type = 4
+ forwardable = true
+ proxiable = true
+ [realms]
+ ${REALM} = {
+ kdc = <AD_IP_ADDR>
+ admin_server = <AD_IP_ADDR>
+ }
+
+Even when the GSS-API library can use the secret from the client key
+table, it is far better for performance to get and cache credentials.
+
+This can be done manually via the command:
+
+.. code-block:: console
+
+ kinit -k -t /tmp/dhcp.keytab DHCP/admin.example.org
+
+or, when using AD:
+
+.. code-block:: console
+
+ kinit -k -t /tmp/dhcp.keytab DHCP/kea.<domain>
+
+The credential cache can be displayed using ``klist``.
+
+In production, it is better to rely on a Kerberos Credential Manager as
+the System Security Services Daemon (``sssd``).
+
+When using BIND 9, the server principal is in the form "DNS/server.example.org@EXAMPLE.ORG¨;
+with AD, the format is "DNS/<server>.<domain>@<REALM>".
+
+.. _stats-gss-tsig:
+
+GSS-TSIG Statistics
+-------------------
+
+The GSS-TSIG hook library introduces new statistics at global and
+per-DNS-server levels:
+
+- ``gss-tsig-key-created`` - the number of created GSS-TSIG keys
+- ``tkey-sent`` - the number of sent TKEY exchange initial requests
+- ``tkey-success`` - the number of TKEY exchanges which completed with a success
+- ``tkey-timeout`` - the number of TKEY exchanges which completed on timeout
+- ``tkey-error`` - the number of TKEY exchanges which completed with an error other than
+ a timeout
+
+The relationship between keys and DNS servers is very different between
+the D2 code and static TSIG keys, and GSS-TSIG keys and DNS servers:
+
+ - a static TSIG key can be shared between many DNS servers;
+ - a GSS-TSIG key is only used by one DNS server inside a dedicated
+ set of keys.
+
+.. _commands-gss-tsig:
+
+GSS-TSIG Commands
+-----------------
+
+The GSS-TSIG hook library supports some commands, which are described below.
+
+.. isccmd:: gss-tsig-get-all
+.. _command-gss-tsig-get-all:
+
+The ``gss-tsig-get-all`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command lists all the GSS-TSIG servers and keys.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-get-all"
+ }
+
+Here is an example of a response returning one GSS-TSIG server and one key:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 GSS-TSIG servers and 1 keys",
+ "arguments": {
+ "gss-tsig-servers": [
+ {
+ "id": "foo",
+ "ip-address": "192.1.2.3",
+ "port": 53,
+ "server-principal": "DNS/foo.com@FOO.COM",
+ "key-name-suffix": "foo.com.",
+ "tkey-lifetime": 3600,
+ "tkey-protocol": "TCP",
+ "keys": [
+ {
+ "name": "1234.sig-foo.com.",
+ "inception-date": "2021-09-05 12:23:36.281176",
+ "server-id": "foo",
+ "expire-date": "2021-09-05 13:23:36.281176",
+ "status": "not yet ready",
+ "tkey-exchange": true
+ }
+ ]
+ },
+ {
+ "id": "bar",
+ "ip-address": "192.1.2.4",
+ "port": 53,
+ "server-principal": "DNS/bar.com@FOO.COM",
+ "key-name-suffix": "bar.com.",
+ "tkey-lifetime": 7200,
+ "tkey-protocol": "UDP",
+ "keys": [ ]
+ }
+ ]
+ }
+ }
+
+.. isccmd:: gss-tsig-get
+.. _command-gss-tsig-get:
+
+The ``gss-tsig-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command retrieves information about the specified GSS-TSIG server.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-get",
+ "arguments": {
+ "server-id": "foo"
+ }
+ }
+
+Here is an example of a response returning information about the server "foo":
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "GSS-TSIG server[foo] found",
+ "arguments": {
+ "id": "foo",
+ "ip-address": "192.1.2.3",
+ "port": 53,
+ "server-principal": "DNS/foo.com@FOO.COM",
+ "key-name-suffix": "foo.com.",
+ "tkey-lifetime": 3600,
+ "tkey-protocol": "TCP",
+ "keys": [
+ {
+ "name": "1234.sig-foo.com.",
+ "server-id": "foo",
+ "inception-date": "2021-09-05 12:23:36.281176",
+ "expire-date": "2021-09-05 13:23:36.281176",
+ "status": "not yet ready",
+ "tkey-exchange": true
+ }
+ ]
+ }
+ }
+
+.. isccmd:: gss-tsig-list
+.. _command-gss-tsig-list:
+
+The ``gss-tsig-list`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command generates a list of GSS-TSIG server IDs and key names.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-list"
+ }
+
+Here is an example of a response returning two GSS-TSIG servers and three keys:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "2 GSS-TSIG servers and 3 keys",
+ "arguments": {
+ "gss-tsig-servers": [
+ "foo",
+ "bar"
+ ],
+ "gss-tsig-keys": [
+ "1234.example.com.",
+ "5678.example.com.",
+ "43888.example.org."
+ ]
+ }
+ }
+
+.. isccmd:: gss-tsig-key-get
+.. _command-gss-tsig-key-get:
+
+The ``gss-tsig-key-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command retrieves information about the specified GSS-TSIG key.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-key-get",
+ "arguments": {
+ "key-name": "1234.sig-foo.com."
+ }
+ }
+
+Here is an example of a response returning information about GSS-TSIG key "1234.sig-foo.com.":
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "GSS-TSIG key '1234.sig-foo.com.' found",
+ "arguments": {
+ "name": "1234.sig-foo.com.",
+ "server-id": "foo",
+ "inception-date": "2021-09-05 12:23:36.281176",
+ "expire-date": "2021-09-05 13:23:36.281176",
+ "status": "not yet ready",
+ "tkey-exchange": true
+ }
+ }
+
+.. isccmd:: gss-tsig-key-expire
+.. _command-gss-tsig-key-expire:
+
+The ``gss-tsig-key-expire`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command expires the specified GSS-TSIG key.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-key-expire",
+ "arguments": {
+ "key-name": "1234.sig-foo.com."
+ }
+ }
+
+Here is an example of a response indicating that GSS-TSIG key "1234.sig-foo.com." has been expired:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "GSS-TSIG key '1234.sig-foo.com.' expired"
+ }
+
+.. isccmd:: gss-tsig-key-del
+.. _command-gss-tsig-key-del:
+
+The ``gss-tsig-key-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command deletes the specified GSS-TSIG key.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-key-del",
+ "arguments": {
+ "key-name": "1234.sig-foo.com."
+ }
+ }
+
+Here is an example of a response indicating that GSS-TSIG key "1234.sig-foo.com." has been deleted:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "GSS-TSIG key '1234.sig-foo.com.' deleted"
+ }
+
+.. isccmd:: gss-tsig-purge-all
+.. _command-gss-tsig-purge-all:
+
+The ``gss-tsig-purge-all`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command removes all unusable GSS-TSIG keys.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-purge-all"
+ }
+
+Here is an example of a response indicating that two GSS-TSIG keys have been purged:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "2 purged GSS-TSIG keys"
+ }
+
+.. isccmd:: gss-tsig-purge
+.. _command-gss-tsig-purge:
+
+The ``gss-tsig-purge`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command removes unusable GSS-TSIG keys for the specified server.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-purge",
+ "arguments": {
+ "server-id": "foo"
+ }
+ }
+
+Here is an example of a response indicating that two GSS-TSIG keys for server "foo" have been purged:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "2 purged keys for GSS-TSIG server[foo]"
+ }
+
+.. isccmd:: gss-tsig-rekey-all
+.. _command-gss-tsig-rekey-all:
+
+The ``gss-tsig-rekey-all`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command unconditionally creates new GSS-TSIG keys (rekeys) for
+all DNS servers.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-rekey-all"
+ }
+
+Here is an example of a response indicating that a rekey was performed:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "rekeyed"
+ }
+
+This command is useful when, for instance, the DHCP-DDNS server is
+reconnected to the network.
+
+.. isccmd:: gss-tsig-rekey
+.. _command-gss-tsig-rekey:
+
+The ``gss-tsig-rekey`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command unconditionally creates new GSS-TSIG keys (rekeys) for
+a specified DNS server.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+ {
+ "command": "gss-tsig-rekey",
+ "arguments": {
+ "server-id": "foo"
+ }
+ }
+
+Here is an example of a response indicating that a rekey was performed:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "GSS-TSIG server[foo] rekeyed"
+ }
+
+This command is typically used when a DNS server has been rebooted, so
+that existing GSS-TSIG keys shared with this server can no longer be used.
diff --git a/doc/sphinx/arm/ext-netconf.rst b/doc/sphinx/arm/ext-netconf.rst
new file mode 100644
index 0000000..b21e7bb
--- /dev/null
+++ b/doc/sphinx/arm/ext-netconf.rst
@@ -0,0 +1,1159 @@
+.. _netconf:
+
+YANG/NETCONF
+============
+
+.. _netconf-overview:
+
+Overview
+--------
+
+The Network Configuration Protocol, or NETCONF, is a network management protocol defined
+in `RFC 4741 <https://tools.ietf.org/html/rfc4741>`__. It uses the YANG modeling language,
+defined in `RFC 6020 <https://tools.ietf.org/html/rfc6020>`__, to provide a uniform way
+of handling the configuration syntax of various networking devices. Kea provides optional
+support for a YANG/NETCONF interface with the :iscman:`kea-netconf` agent.
+
+.. _netconf-install:
+
+Installing NETCONF
+------------------
+
+To get its NETCONF capabilities, Kea requires the v2 versions of libyang and
+Sysrepo. The specific versions that have been thoroughly tested with Kea are:
+
+* libyang v2.1.4
+* sysrepo v2.2.12
+* libyang-cpp v1.1.0 (ae7d649ea75da081725c119dd553b2ef3121a6f8)
+* sysrepo-cpp v1.1.0 (02634174ffc60568301c3d9b9b7cf710cff6a586)
+
+.. note::
+
+ For users who are unable to upgrade to one of the versions of libyang
+ and Sysrepo listed above, these are the oldest versions known to work
+ reliably with current Kea releases:
+
+ * libyang v2.0.256 (56d4e07ef1cdeab3eb2e6700247f83ec9148edcc)
+ * sysrepo v2.1.84
+ * libyang-cpp v1.1.0 (7824d9a862f2dc1d8ad4f6a90ab6cee9200f7c81)
+ * sysrepo-cpp v1.1.0 (e66b2f0c53a428eeb743d355cf86fb30e8e491f1)
+
+.. note::
+
+ :iscman:`kea-netconf` may be compatible with later versions of libyang and
+ Sysrepo, but only the versions listed above have been thoroughly
+ tested by ISC.
+
+Installing from packages is recommended, if they are provided by the system. If
+not, users can build from sources following the directions below, which
+should work on all popular operating systems.
+
+.. _libyang-install-sources:
+
+Installing ``libyang`` From Sources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+ $ git clone https://github.com/CESNET/libyang.git
+ $ cd libyang
+ $ git checkout v2.1.4
+ $ mkdir build
+ $ cd build
+ $ cmake ..
+ $ make
+ $ make install
+
+.. _sysrepo-install-sources:
+
+Installing ``sysrepo`` From Sources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+ $ git clone https://github.com/sysrepo/sysrepo.git
+ $ cd sysrepo
+ $ git checkout v2.2.12
+ $ mkdir build
+ $ cd build
+ $ cmake -DREPO_PATH=/etc/sysrepo ..
+ $ make
+ $ make install # without sudo if you're doing development and want to run unit tests
+
+.. _libyang-cpp-install-sources:
+
+Installing ``libyang-cpp`` From Sources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+ $ git clone https://github.com/CESNET/libyang-cpp.git
+ $ cd libyang-cpp
+ $ git checkout ae7d649ea75da081725c119dd553b2ef3121a6f8
+ $ mkdir build
+ $ cd build
+ $ cmake -DBUILD_TESTING=OFF ..
+ $ make
+ $ make install
+
+.. _sysrepo-cpp-install-sources:
+
+Installing ``sysrepo-cpp`` From Sources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+ $ git clone https://github.com/sysrepo/sysrepo-cpp.git
+ $ cd sysrepo-cpp
+ $ git checkout 02634174ffc60568301c3d9b9b7cf710cff6a586
+ $ mkdir build
+ $ cd build
+ $ cmake -DBUILD_TESTING=OFF ..
+ $ make
+ $ make install
+
+.. _compiling-with-netconf:
+
+Compiling With NETCONF
+----------------------
+
+1. Obtain the Kea sources.
+
+.. code-block:: console
+
+ $ git clone gitlab.isc.org/isc-projects/kea.git
+ $ cd kea
+
+2. Configure the build.
+
+.. code-block:: console
+
+ $ autoreconf -f -i
+ $ ./configure --with-libyang --with-libyang-cpp --with-sysrepo --with-sysrepo-cpp
+
+.. note::
+
+ If any of the libraries are installed in a custom location, the
+ ``--with`` flags accept the installations paths as values.
+
+3. Check ``config.report`` to verify NETCONF support.
+
+::
+
+ NETCONF:
+ yes
+
+ libyang:
+ LIBYANG_CPPFLAGS:
+ LIBYANG_INCLUDEDIR: -I/usr/local/include
+ LIBYANG_LIBS: -L/usr/local/lib -lyang -Wl,-R/usr/local/lib -lyang
+ LIBYANG_PREFIX: /usr/local
+ LIBYANG_VERSION: 2.1.4
+
+ libyang-cpp:
+ LIBYANGCPP_CPPFLAGS:
+ LIBYANGCPP_INCLUDEDIR: -I/usr/local/include
+ LIBYANGCPP_LIBS: -L/usr/local/lib -lyang-cpp -Wl,-R/usr/local/lib -lyang-cpp
+ LIBYANGCPP_PREFIX: /usr/local
+ LIBYANGCPP_VERSION: 1.1.0
+
+ sysrepo:
+ SYSREPO_CPPFLAGS:
+ SYSREPO_INCLUDEDIR: -I/usr/local/include
+ SYSREPO_LIBS: -L/usr/local/lib -lsysrepo -Wl,-R/usr/local/lib -lsysrepo
+ SYSREPO_PREFIX: /usr/local
+ SYSREPO_VERSION: 2.2.12
+
+ SR_REPO_PATH: /etc/sysrepo
+ SR_PLUGINS_PATH: /usr/local/lib/sysrepo/plugins
+ SRPD_PLUGINS_PATH: /usr/local/lib/sysrepo-plugind/plugins
+
+ sysrepo-cpp:
+ SYSREPOCPP_CPPFLAGS:
+ SYSREPOCPP_INCLUDEDIR: -I/usr/local/include
+ SYSREPOCPP_LIBS: -L/usr/local/lib -lsysrepo-cpp -Wl,-R/usr/local/lib -lsysrepo-cpp
+ SYSREPOCPP_PREFIX : /usr/local
+ SYSREPOCPP_VERSION: 1.1.0
+
+4. Build as usual.
+
+ $ make
+
+.. _sysrepo-overview:
+
+Quick Sysrepo Overview
+----------------------
+
+This section offers a brief overview of a subset of available
+functions in Sysrepo. For more complete information, see the
+`Sysrepo homepage <https://www.sysrepo.org>`__.
+
+In YANG, configurations and state data are described in YANG syntax
+in module files named ``<module-name>[@<revision>].yang``
+
+The revision part is optional and follows the ``YYYY-MM-DD`` format. An alternate
+XML syntax YIN is defined but less user-friendly. Top-level modules are
+named in Kea models (a short version of schema models).
+
+There are two major modules that Kea is able to support: ``kea-dhcp4-server`` and
+``kea-dhcp6-server``. While there is an active effort in the DHC working group at
+IETF to develop a DHCPv6 YANG model, a similar initiative in the past for DHCPv4
+failed. Therefore, Kea uses its own dedicated models for DHCPv4 and DHCPv6 but
+partially supports the IETF model for DHCPv6.
+
+All of the models have extra modules as dependencies, which are also provided.
+All of the modules can be found in ``src/share/yang/modules`` in sources and in
+``share/kea/yang/modules`` in the installation directory. This directory is
+referred to as `${share_directory}` in the commands below.
+
+To install modules from sources or upgrade them from older revisions,
+run the following command. In the case of a revision upgrade, YANG
+data will be migrated automatically to the new module schema.
+
+.. code-block:: console
+
+ $ ${share_directory}/yang/modules/utils/reinstall.sh
+
+However, if there are any issues during the upgrade process, and data can be recreated from a NETCONF
+client or through other means, Kea modules can be easily uninstalled before installing again
+via this command:
+
+.. code-block:: console
+
+ $ ${share_directory}/yang/modules/utils/reinstall.sh -u
+
+This script should be able to reinstall Sysrepo. However, the ``-s``
+flag can also be used to specify a path:
+
+.. code-block:: console
+
+ $ ./src/share/yang/modules/utils/reinstall.sh -s /path/to/sysrepo
+
+To individually install all modules:
+
+.. code-block:: console
+
+ $ cd ./src/share/yang/modules
+ $ sysrepoctl -i ./ietf-dhcpv6-server*.yang
+ $ sysrepoctl -i ./kea-dhcp4-server*.yang
+ $ sysrepoctl -i ./kea-dhcp6-server*.yang
+ ...
+
+The installation should look similar to the following:
+
+.. code-block:: console
+
+ $ ./src/share/yang/modules/utils/reinstall.sh
+ [INF] Connection 2 created.
+ [INF] Module "keatest-module" was installed.
+ [INF] File "keatest-module@2022-11-30.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 4 created.
+ [ERR] Module "ietf-interfaces@2018-02-20" already installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 7 created.
+ [ERR] Module "ietf-dhcpv6-client" is already in sysrepo.
+ [INF] No datastore changes to apply.
+ [INF] Connection 9 created.
+ [ERR] Module "ietf-dhcpv6-relay" is already in sysrepo.
+ [INF] No datastore changes to apply.
+ [INF] Connection 11 created.
+ [ERR] Module "ietf-dhcpv6-server" is already in sysrepo.
+ [INF] No datastore changes to apply.
+ [INF] Connection 13 created.
+ [ERR] Write permission "ietf-yang-types" check failed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 15 created.
+ [ERR] Module "ietf-dhcpv6-options" is already in sysrepo.
+ [INF] No datastore changes to apply.
+ [INF] Connection 17 created.
+ [ERR] Module "ietf-dhcpv6-types" is already in sysrepo.
+ [INF] No datastore changes to apply.
+ [INF] Connection 21 created.
+ [INF] Module "kea-types" was installed.
+ [INF] File "kea-types@2019-08-12.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 23 created.
+ [INF] Module "kea-dhcp-types" was installed.
+ [INF] File "kea-dhcp-types@2022-11-30.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 25 created.
+ [INF] Module "kea-dhcp-ddns" was installed.
+ [INF] File "kea-dhcp-ddns@2022-07-27.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 27 created.
+ [INF] Module "kea-ctrl-agent" was installed.
+ [INF] File "kea-ctrl-agent@2019-08-12.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 29 created.
+ [INF] Module "kea-dhcp4-server" was installed.
+ [INF] File "kea-dhcp4-server@2022-11-30.yang" was installed.
+ [INF] No datastore changes to apply.
+ [INF] Connection 31 created.
+ [INF] Module "kea-dhcp6-server" was installed.
+ [INF] File "kea-dhcp6-server@2022-11-30.yang" was installed.
+ [INF] No datastore changes to apply.
+
+To confirm whether the modules have been imported correctly, check the list of
+currently installed YANG modules. It should be similar to this:
+
+.. code-block:: console
+
+ $ sysrepoctl -l
+ Sysrepo repository: /etc/sysrepo
+
+ Module Name | Revision | Flags | Owner | Startup Perms | Submodules | Features
+ ---------------------------------------------------------------------------------------------------
+ ietf-datastores | 2018-02-14 | I | user:user | 444 | |
+ ietf-dhcpv6-client | 2018-09-04 | I | user:user | 600 | |
+ ietf-dhcpv6-options | 2018-09-04 | I | user:user | 600 | |
+ ietf-dhcpv6-relay | 2018-09-04 | I | user:user | 600 | |
+ ietf-dhcpv6-server | 2018-09-04 | I | user:user | 600 | |
+ ietf-dhcpv6-types | 2018-09-04 | I | user:user | 600 | |
+ ietf-inet-types | 2013-07-15 | I | user:user | 444 | |
+ ietf-interfaces | 2018-02-20 | I | user:user | 600 | |
+ ietf-netconf | 2013-09-29 | I | user:user | 644 | |
+ ietf-netconf-acm | 2018-02-14 | I | user:user | 600 | |
+ ietf-netconf-notifications | 2012-02-06 | I | user:user | 644 | |
+ ietf-netconf-with-defaults | 2011-06-01 | I | user:user | 444 | |
+ ietf-origin | 2018-02-14 | I | user:user | 444 | |
+ ietf-yang-library | 2019-01-04 | I | user:user | 644 | |
+ ietf-yang-metadata | 2016-08-05 | i | | | |
+ ietf-yang-schema-mount | 2019-01-14 | I | user:user | 644 | |
+ ietf-yang-types | 2013-07-15 | I | user:user | 444 | |
+ kea-ctrl-agent | 2019-08-12 | I | user:user | 600 | |
+ kea-dhcp-ddns | 2022-07-27 | I | user:user | 600 | |
+ kea-dhcp-types | 2022-11-30 | I | user:user | 600 | |
+ kea-dhcp4-server | 2022-11-30 | I | user:user | 600 | |
+ kea-dhcp6-server | 2022-11-30 | I | user:user | 600 | |
+ kea-types | 2019-08-12 | I | user:user | 600 | |
+ keatest-module | 2022-11-30 | I | user:user | 600 | |
+ sysrepo-monitoring | 2022-04-08 | I | user:user | 600 | |
+ sysrepo-plugind | 2022-03-10 | I | user:user | 644 | |
+ yang | 2022-06-16 | I | user:user | 444 | |
+
+ Flags meaning: I - Installed/i - Imported; R - Replay support
+
+To reinstall a module, if the revision YANG entry was bumped, simply installing
+it will update it automatically. Otherwise, it must first be uninstalled:
+
+.. code-block:: console
+
+ $ sysrepoctl -u kea-dhcp4-server
+
+If the module is used (i.e. imported) by other modules, it can be uninstalled
+only after the dependent modules have first been uninstalled.
+Installation and uninstallation must be done in dependency order and
+reverse-dependency order, as appropriate.
+
+.. _netconf-models:
+
+Supported YANG Models
+---------------------
+
+The currently supported models are ``kea-dhcp4-server`` and
+``kea-dhcp6-server``. There is partial support for
+``ietf-dhcpv6-server``, but the primary focus of testing has been on Kea DHCP
+servers. Other models (:iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent`)
+are currently not supported.
+
+.. _using-netconf:
+
+Using the NETCONF Agent
+-----------------------
+
+The NETCONF agent follows this algorithm:
+
+- For each managed server, get the initial configuration from the
+ server through the control socket.
+
+- Open a connection with the Sysrepo environment and establish two
+ sessions with the startup and running datastores.
+
+- Check that the used (not-essential) and required (essential) modules are
+ installed in the Sysrepo repository at the right revision. If an
+ essential module - that is, a module where the configuration schema for a
+ managed server is defined - is not installed, raise a fatal error.
+
+- For each managed server, get the YANG configuration from the startup
+ datastore, translate it to JSON, and load it onto the server being
+ configured.
+
+- For each managed server, subscribe a module change callback using its
+ model name.
+
+- When a running configuration is changed, try to validate or load the
+ updated configuration via the callback to the managed server.
+
+.. _netconf-configuration:
+
+Configuration
+-------------
+
+The behavior described in :ref:`using-netconf`
+is controlled by several configuration flags, which can be set in the
+global scope or in a specific managed-server scope. If the latter,
+the value defined in the managed-server scope takes precedence. These
+flags are:
+
+- ``boot-update`` - controls the initial configuration phase; when
+ ``true`` (the default), the initial configuration retrieved from the
+ classic Kea server JSON configuration file is loaded first, and then
+ the startup YANG model is loaded. This setting lets administrators
+ define a control socket in the local JSON file and then download the
+ configuration from YANG. When set to ``false``, this phase is skipped.
+
+- ``subscribe-changes`` - controls the module change
+ subscription; when ``true`` (the default), a module change callback is
+ subscribed, but when ``false`` the phase is skipped and running
+ configuration updates are disabled. When set to ``true``, the running
+ datastore is used to subscribe for changes.
+
+- ``validate-changes`` - controls how Kea monitors changes in
+ the Sysrepo configuration. Sysrepo offers two stages where Kea can
+ interact: validation and application. At the validation (or
+ ``SR_EV_CHANGE`` event, in the Sysrepo naming convention) stage, Kea
+ retrieves the newly committed configuration and verifies it. If the
+ configuration is incorrect for any reason, the Kea servers reject it
+ and the error is propagated back to the Sysrepo, which then returns
+ an error. This step only takes place if ``validate-changes`` is set to
+ ``true``. In the application (or ``SR_EV_UPDATE`` event in the Sysrepo naming
+ convention) stage, the actual configuration is applied. At this stage
+ Kea can receive the configuration, but it is too late to signal back
+ any errors as the configuration has already been committed.
+
+The idea behind the initial configuration phase is to boot Kea servers
+with a minimal configuration which includes only a control socket,
+making them manageable. For instance, for the DHCPv4 server:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "control-socket": {
+ "socket-name": "/tmp/kea-dhcp4-ctrl.sock",
+ "socket-type": "unix"
+ }
+ }
+ }
+
+With module change subscriptions enabled, the :iscman:`kea-netconf` daemon
+monitors any configuration changes as they appear in the Sysrepo. Such
+changes can be done using the ``sysrepocfg`` tool or remotely using any
+NETCONF client. For details, please see the Sysrepo documentation or
+:ref:`operation-example`.
+Those tools can be used to modify YANG configurations in the running
+datastore. Note that committed configurations are only updated in the
+running datastore; to keep them between server reboots they must be
+copied to the startup datastore.
+
+When module changes are tracked (using ``subscribe-changes`` set to
+``true``) and the running configuration has changed (e.g. using
+``sysrepocfg`` or any NETCONF client), the callback validates the
+modified configuration (if ``validate-changes`` was not set to ``false``)
+and runs a second time to apply the new configuration. If the validation
+fails, the callback is still called again but with an ``SR_EV_ABORT``
+(vs. ``SR_EV_DONE``) event with rollback changes.
+
+The returned code of the callback on an ``SR_EV_DONE`` event is ignored, as it is
+too late to refuse a bad configuration.
+
+There are four ways in which a modified YANG configuration might
+be incorrect:
+
+1. It could be non-compliant with the schema, e.g. an unknown entry, missing a
+ mandatory entry, a value with a bad type, or not matching a constraint.
+
+2. It could fail to be translated from YANG to JSON, e.g. an invalid user
+ context.
+
+3. It could fail Kea server sanity checks, e.g. an out-of-subnet-pool range
+ or an unsupported database type.
+
+4. The syntax may be correct and pass server sanity checks but the
+ configuration could fail to run, e.g. the configuration specifies database
+ credentials but the database refuses the connection.
+
+The first case is handled by Sysrepo. The second and third cases are
+handled by :iscman:`kea-netconf` in the validation phase (if not disabled by
+setting ``validate-changes`` to ``true``). The last case causes the
+application phase to fail without a sensible report to Sysrepo.
+
+The managed Kea servers and agents are described in the
+``managed-servers`` section. Each sub-section begins with the service
+name: ``dhcp4``, ``dhcp6``, ``d2`` (the DHCP-DDNS server does not
+support the control-channel feature yet), and ``ca`` (the control
+agent).
+
+Each managed server entry may contain:
+
+- control flags - ``boot-update``, ``subscribe-changes``, and/or ``validate-changes``.
+
+- ``model`` - specifies the YANG model/module name. For each service,
+ the default is the corresponding Kea YANG model, e.g. for ``"dhcp4"``
+ it is ``"kea-dhcp4-server"``.
+
+- ``control-socket`` - specifies the control socket for managing the
+ service configuration.
+
+A control socket is specified by:
+
+- ``socket-type`` - the socket type is either ``stdout``, ``unix``, or ``http``.
+ ``stdout`` is the default;
+ it is not really a socket, but it allows :iscman:`kea-netconf` to run in
+ debugging mode where everything is printed on stdout, and it can also be
+ used to redirect commands easily. ``unix`` is the standard direct
+ server control channel, which uses UNIX sockets; ``http`` uses
+ a control agent, which accepts HTTP connections.
+
+- ``socket-name`` - the local socket name for the ``unix`` socket type
+ (default empty string).
+
+- ``socket-url`` - the HTTP URL for the ``http`` socket type (default
+ ``http://127.0.0.1:8000/``).
+
+User contexts can store arbitrary data as long as they are in valid JSON
+syntax and their top-level element is a map (i.e. the data must be
+enclosed in curly brackets). They are accepted at the NETCONF entry,
+i.e. below the top-level, managed-service entry, and control-socket
+entry scopes.
+
+Hook libraries can be loaded by the NETCONF agent just as with other
+servers or agents; however, currently no hook points are defined. The
+``hooks-libraries`` list contains the list of hook libraries that
+should be loaded by :iscman:`kea-netconf`, along with their configuration
+information specified with ``parameters``.
+
+Please consult :ref:`logging` for details on how to configure
+logging. The name of the NETCONF agent's main logger is :iscman:`kea-netconf`, as
+given in the example above.
+
+.. _netconf-example:
+
+A :iscman:`kea-netconf` Configuration Example
+---------------------------------------------
+
+The following example demonstrates the basic NETCONF configuration. More
+examples are available in the ``doc/examples/netconf`` directory in the
+Kea sources.
+
+.. code-block:: javascript
+
+ // This is a simple example of a configuration for the NETCONF agent.
+ // This server provides a YANG interface for all Kea servers and the agent.
+ {
+ "Netconf":
+ {
+ // Control flags can be defined in the global scope or
+ // in a managed server scope. Precedences are:
+ // - use the default value (true)
+ // - use the global value
+ // - use the local value.
+ // So this overwrites the default value:
+ "boot-update": false,
+
+ // This map specifies how each server is managed. For each server there
+ // is a name of the YANG model to be used and the control channel.
+ // Currently three control channel types are supported:
+ // "stdout" which outputs the configuration on the standard output,
+ // "unix" which uses the local control channel supported by the
+ // "dhcp4" and "dhcp6" servers ("d2" support is not yet available),
+ // and "http" which uses the Control Agent "ca" to manage itself or
+ // to forward commands to "dhcp4" or "dhcp6".
+ "managed-servers":
+ {
+ // This is how kea-netconf can communicate with the DHCPv4 server.
+ "dhcp4":
+ {
+ "comment": "DHCPv4 server",
+ "model": "kea-dhcp4-server",
+ "control-socket":
+ {
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea4-ctrl-socket"
+ }
+ },
+
+ // DHCPv6 parameters.
+ "dhcp6":
+ {
+ "model": "kea-dhcp6-server",
+ "control-socket":
+ {
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea6-ctrl-socket"
+ }
+ },
+
+ // Currently the DHCP-DDNS (nicknamed D2) server does not support
+ // a command channel.
+ "d2":
+ {
+ "model": "kea-dhcp-ddns",
+ "control-socket":
+ {
+ "socket-type": "stdout",
+ "user-context": { "in-use": false }
+ }
+ },
+
+ // Of course the Control Agent (CA) supports HTTP.
+ "ca":
+ {
+ "model": "kea-ctrl-agent",
+ "control-socket":
+ {
+ "socket-type": "http",
+ "socket-url": "http://127.0.0.1:8000/"
+ }
+ }
+ },
+
+ // kea-netconf is able to load hook libraries that augment its operation.
+ // Currently there are no hook points defined in kea-netconf
+ // processing.
+ "hooks-libraries": [
+ // The hook libraries list may contain more than one library.
+ {
+ // The only necessary parameter is the library filename.
+ "library": "/opt/local/custom_hooks_example.so",
+
+ // Some libraries may support parameters. Make sure you
+ // type this section carefully, as kea-netconf does not
+ // validate it (because the format is library-specific).
+ "parameters": {
+ "param1": "foo"
+ }
+ }
+ ],
+
+ // Similar to other Kea components, NETCONF also uses logging.
+ "loggers": [
+ {
+ "name": "kea-netconf",
+ "output-options": [
+ {
+ "output": "/var/log/kea-netconf.log",
+ // Several additional parameters are possible in
+ // addition to the typical output.
+ // Flush determines whether logger flushes output
+ // to a file.
+ // Maxsize determines maximum filesize before
+ // the file is rotated.
+ // Maxver specifies the maximum number of
+ // rotated files to be kept.
+ "flush": true,
+ "maxsize": 204800,
+ "maxver": 4
+ }
+ ],
+ "severity": "INFO",
+ "debuglevel": 0
+ }
+ ]
+ }
+ }
+
+.. _netconf-start-stop:
+
+Starting and Stopping the NETCONF Agent
+---------------------------------------
+
+:iscman:`kea-netconf` accepts the following command-line switches:
+
+- ``-c file`` - specifies the configuration file.
+
+- ``-d`` - specifies whether the agent logging should be switched to
+ debug/verbose mode. In verbose mode, the logging severity and
+ debuglevel specified in the configuration file are ignored and
+ "debug" severity and the maximum debuglevel (99) are assumed. The
+ flag is convenient for temporarily switching the server into maximum
+ verbosity, e.g. when debugging.
+
+- ``-t file`` - specifies the configuration file to be tested.
+ :iscman:`kea-netconf` attempts to load it and conducts sanity checks;
+ certain checks are possible only while running the actual server. The
+ actual status is reported with exit code (0 = configuration appears valid,
+ 1 = error encountered). Kea prints out log messages to standard
+ output and error to standard error when testing the configuration.
+
+- ``-v`` - displays the version of :iscman:`kea-netconf` and exits.
+
+- ``-V`` - displays the extended version information for :iscman:`kea-netconf`
+ and exits. The listing includes the versions of the libraries
+ dynamically linked to Kea.
+
+- ``-W`` - displays the Kea configuration report and exits. The report
+ is a copy of the ``config.report`` file produced by ``./configure``;
+ it is embedded in the executable binary.
+
+ The contents of the ``config.report`` file may also be accessed by examining
+ certain libraries in the installation tree or in the source tree.
+
+ .. code-block:: shell
+
+ # from installation using libkea-process.so
+ $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.so
+ $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p'
+
+ # from sources using libkea-process.a
+ $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p'
+
+ # from sources using libcfgrpt.a
+ $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p'
+
+.. _operation-example:
+
+A Step-by-Step NETCONF Agent Operation Example
+----------------------------------------------
+
+.. note::
+
+ Copies of example configurations presented within this section can be
+ found in the Kea source code, under
+ ``doc/examples/netconf/kea-dhcp6-operations``.
+
+.. _operation-example-setup:
+
+Setup of NETCONF Agent Operation Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The test box has an Ethernet interface named eth1. On some systems it is
+possible to rename interfaces; for instance, on Linux with an ens38
+interface:
+
+.. code-block:: console
+
+ # ip link set down dev ens38
+ # ip link set name eth1 dev ens38
+ # ip link set up dev eth1
+
+The interface must have an address in the test prefix:
+
+.. code-block:: console
+
+ # ip -6 addr add 2001:db8::1/64 dev eth1
+
+The Kea DHCPv6 server must be launched with the configuration specifying
+a control socket used to receive control commands. The :iscman:`kea-netconf`
+process uses this socket to communicate with the DHCPv6 server, i.e. it
+pushes translated configurations to that server using control commands.
+The following is an example control socket specification for the Kea
+DHCPv6 server:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "control-socket": {
+ "socket-name": "/tmp/kea-dhcp6-ctrl.sock",
+ "socket-type": "unix"
+ }
+ }
+ }
+
+In order to launch the Kea DHCPv6 server using the configuration
+contained within the ``boot.json`` file, run:
+
+.. code-block:: console
+
+ # kea-dhcp6 -d -c boot.json
+
+The current configuration of the server can be fetched via a control
+socket by running:
+
+.. code-block:: console
+
+ # echo '{ "command": "config-get" }' | socat UNIX:/tmp/kea-dhcp6-ctrl.sock '-,ignoreeof'
+
+The following is the example ``netconf.json`` configuration for
+:iscman:`kea-netconf`, to manage the Kea DHCPv6 server:
+
+.. code-block:: json
+
+ {
+ "Netconf": {
+ "loggers": [
+ {
+ "debuglevel": 99,
+ "name": "kea-netconf",
+ "output-options": [
+ {
+ "output": "stderr"
+ }
+ ],
+ "severity": "DEBUG"
+ }
+ ],
+ "managed-servers": {
+ "dhcp6": {
+ "control-socket": {
+ "socket-name": "/tmp/kea-dhcp6-ctrl.sock",
+ "socket-type": "unix"
+ }
+ }
+ }
+ }
+ }
+
+Note that in production there should not be a need to log at the DEBUG level.
+
+The Kea NETCONF agent is launched by:
+
+.. code-block:: console
+
+ # kea-netconf -d -c netconf.json
+
+Now that both :iscman:`kea-netconf` and :iscman:`kea-dhcp6` are running, it is
+possible to populate updates to the configuration to the DHCPv6 server.
+The following is the configuration extracted from ``startup.xml``:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8::1:0</start-address>
+ <end-address>2001:db8::1:ffff</end-address>
+ <prefix>2001:db8::1:0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ </config>
+
+To populate this new configuration:
+
+.. code-block:: console
+
+ $ sysrepocfg -d startup -f xml -m kea-dhcp6-server --import=startup.xml
+
+:iscman:`kea-netconf` pushes the configuration found in the Sysrepo startup
+datastore to all Kea servers during its initialization phase, after it
+subscribes to module changes in the Sysrepo running datastore. This
+action copies the configuration from the startup datastore to the
+running datastore and enables the running datastore, making it
+available.
+
+Changes to the running datastore are applied after validation to the Kea
+servers. Note that they are not by default copied back to the startup
+datastore, i.e. changes are not permanent.
+
+.. note::
+
+ :iscman:`kea-netconf` fetches the entire configuration from any Sysrepo datastore in a
+ single ``get-config`` NETCONF operation. Prior to Kea 2.3.2, a ``get-config`` operation
+ was done for each leaf and leaf-list node. Because of the significant changes,
+ :iscman:`kea-netconf` is considered experimental.
+
+.. _operation-example-errors:
+
+Example of Error Handling in NETCONF Operation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are four classes of issues with configurations applied via
+NETCONF:
+
+1. The configuration does not comply with the YANG schema.
+
+2. The configuration cannot be translated from YANG to the Kea JSON.
+
+3. The configuration is rejected by the Kea server.
+
+4. The configuration was validated by the Kea server but cannot be
+ applied.
+
+In the first case, consider the following ``BAD-schema.xml``
+configuration file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet4>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8::1:0</start-address>
+ <end-address>2001:db8::1:ffff</end-address>
+ <prefix>2001:db8::1:0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ </config>
+
+It is directly rejected by ``sysrepocfg``:
+
+.. code-block:: console
+
+ $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=BAD-schema.xml
+
+In the second case, the configuration is rejected by :iscman:`kea-netconf`.
+For example, consider this ``BAD-translator.xml`` file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8::1:0</start-address>
+ <end-address>2001:db8::1:ffff</end-address>
+ <prefix>2001:db8::1:0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ <user-context>bad</user-context>
+ </config>
+
+In the third case, the configuration is presented to the Kea DHCPv6
+server and fails to validate, as in this ``BAD-config.xml`` file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8:1::0</start-address>
+ <end-address>2001:db8:1::ffff</end-address>
+ <prefix>2001:db8:1::0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ </config>
+
+In the last case, the misconfiguration is detected too late and the
+change must be reverted in Sysrepo, e.g. using the startup datastore as
+a backup.
+
+.. _operation-example-2pools:
+
+NETCONF Operation Example with Two Pools
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example adds a second pool to the initial (i.e. startup)
+configuration in the ``twopools.xml`` file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8::1:0</start-address>
+ <end-address>2001:db8::1:ffff</end-address>
+ <prefix>2001:db8::1:0/112</prefix>
+ </pool>
+ <pool>
+ <start-address>2001:db8::2:0</start-address>
+ <end-address>2001:db8::2:ffff</end-address>
+ <prefix>2001:db8::2:0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ </config>
+
+This configuration is installed by:
+
+.. code-block:: console
+
+ $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=twopools.xml
+
+.. _operation-example-2subnets:
+
+NETCONF Operation Example with Two Subnets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example specifies two subnets in the ``twosubnets.xml`` file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8:1::</start-address>
+ <end-address>2001:db8:1::ffff</end-address>
+ <prefix>2001:db8:1::/112</prefix>
+ </pool>
+ <subnet>2001:db8:1::/64</subnet>
+ </subnet6>
+ <subnet6>
+ <id>2</id>
+ <pool>
+ <start-address>2001:db8:2::</start-address>
+ <end-address>2001:db8:2::ffff</end-address>
+ <prefix>2001:db8:2::/112</prefix>
+ </pool>
+ <subnet>2001:db8:2::/64</subnet>
+ </subnet6>
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ </config>
+
+This configuration is installed by:
+
+.. code-block:: console
+
+ $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=twosubnets.xml
+
+.. _operation-example-logging:
+
+NETCONF Operation Example With Logging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example adds a logger entry to the initial (i.e. startup)
+configuration in the ``logging.xml`` file:
+
+.. code-block:: xml
+
+ <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server">
+ <interfaces-config>
+ <interfaces>eth1</interfaces>
+ </interfaces-config>
+ <subnet6>
+ <id>1</id>
+ <pool>
+ <start-address>2001:db8::1:0</start-address>
+ <end-address>2001:db8::1:ffff</end-address>
+ <prefix>2001:db8::1:0/112</prefix>
+ </pool>
+ <subnet>2001:db8::/64</subnet>
+ </subnet6>
+ <control-socket>
+ <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name>
+ <socket-type>unix</socket-type>
+ </control-socket>
+ <logger>
+ <name>kea-dhcp6</name>
+ <output-option>
+ <output>stderr</output>
+ </output-option>
+ <debuglevel>99</debuglevel>
+ <severity>DEBUG</severity>
+ </logger>
+ </config>
+
+The corresponding Kea configuration in JSON is:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "control-socket": {
+ "socket-name": "/tmp/kea-dhcp6-ctrl.sock",
+ "socket-type": "unix"
+ },
+ "interfaces-config": {
+ "interfaces": [ "eth1" ]
+ },
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "2001:db8::1:0/112"
+ }
+ ],
+ "subnet": "2001:db8::/64"
+ }
+ ],
+ "loggers": [
+ {
+ "name": "kea-dhcp6",
+ "output-options": [
+ {
+ "output": "stderr"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+ }
+
+Finally, any of the previous examples can be replayed by using
+``sysrepocfg`` in edit mode as follows:
+
+.. code-block:: console
+
+ $ sysrepocfg -d running -f xml -m kea-dhcp6-server --edit
+
+or by using a NETCONF client like ``netopeer2-cli`` from the
+`Netopeer2 <https://github.com/CESNET/Netopeer2>`__ NETCONF Toolset.
+
+.. _migrating-yang-data:
+
+Migrating YANG Data From a Prior Sysrepo Version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Shut down :iscman:`kea-netconf`. This ensures that backups for both datastores
+are done at the same configuration state and that no change happens between exporting them.
+
+2. Make data backups for all YANG modules, with one XML for each datastore.
+
+.. code-block:: console
+
+ $ sysrepocfg --datastore running --export=save.xml --format=xml
+ $ sysrepocfg --datastore startup --export=save.xml --format=xml
+
+.. note::
+
+ Sysrepo v0 does not support import/export of all YANG modules; this capability was added in
+ Sysrepo v1. Users that are migrating from Sysrepo v0 will need to do per-module backups. This has
+ the added benefit of isolating potential failures and preventing them from affecting all
+ modules. The command is the same, except it has the module name added to it at the end.
+
+ .. code-block:: console
+
+ $ sysrepocfg --datastore running --export=save.xml --format=xml kea-dhcp6-server
+ $ sysrepocfg --datastore startup --export=save.xml --format=xml kea-dhcp6-server
+
+3. Upgrade Sysrepo to the newer version and then run:
+
+.. code-block:: console
+
+ $ sysrepocfg --datastore running --import=save.xml
+ $ sysrepocfg --datastore startup --import=save.xml
diff --git a/doc/sphinx/arm/ext-radius.rst b/doc/sphinx/arm/ext-radius.rst
new file mode 100644
index 0000000..08ca631
--- /dev/null
+++ b/doc/sphinx/arm/ext-radius.rst
@@ -0,0 +1,559 @@
+.. _radius:
+
+RADIUS
+======
+
+.. _radius-overview:
+
+RADIUS Overview
+---------------
+
+This hook library allows Kea to interact with two types of RADIUS
+services: access and accounting. Although the most common DHCP and RADIUS
+integration is done on the DHCP relay-agent level (DHCP clients send
+DHCP packets to DHCP relays; those relays contact the RADIUS server and
+depending on the response either send the packet to the DHCP server or
+drop it), it does require DHCP relay hardware to support RADIUS
+communication. Also, even if the relay has the necessary support, it is
+often not flexible enough to send and receive additional RADIUS
+attributes. As such, the alternative looks more appealing: to extend the
+DHCP server to talk to RADIUS directly. That is the goal of this library.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or the
+ :iscman:`kea-dhcp6` process.
+
+The major feature of this hook library is the ability to use RADIUS
+authorization. When a DHCP packet is received, the Kea server sends an
+Access-Request to the RADIUS server and waits for a response. The server
+then sends back either an Access-Accept with specific client attributes,
+or an Access-Reject. There are two cases supported here: first, the
+Access-Accept includes a Framed-IP-Address attribute (for DHCPv4) or a
+Framed-IPv6-Address attribute (for DHCPv6), which are interpreted by Kea as
+instructions to assign the specified IPv4 or IPv6 address. This
+effectively means RADIUS can act as an address-reservation database.
+
+The second supported case is the ability to assign clients to specific
+pools based on a RADIUS response. In this case, the RADIUS server sends
+back an Access-Accept with a Framed-Pool attribute.
+For both DHCPv4 and DHCPv6, Kea interprets this attribute as a client class.
+With the addition of the ability to limit access to pools to
+specific classes (see :ref:`classification-pools`), RADIUS can be
+used to force the client to be assigned a dynamic address from a
+specific pool. Furthermore, the same mechanism can be used to control
+what kind of options the client gets if there are DHCP options
+specified for a particular class.
+
+.. _radius-config:
+
+RADIUS Hook Library Configuration
+---------------------------------
+
+The RADIUS hook is a library that must be loaded by either :iscman:`kea-dhcp4` or
+:iscman:`kea-dhcp6` servers. Unlike some other available hook libraries, this one
+takes many parameters. For example, this configuration can be used:
+
+.. parsed-literal::
+
+ {
+ "Dhcp4": {
+
+ // Your regular DHCPv4 configuration parameters goes here.
+
+ "hooks-libraries": [
+ {
+ // Note that RADIUS requires host-cache for proper operation,
+ // so that library is loaded as well.
+ "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so"
+ },
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_radius.so",
+ "parameters": {
+
+ // Specify where the dictionary is located.
+ "dictionary": "/etc/kea/radius/dictionary",
+
+ // Specify which address to use to communicate with RADIUS servers
+ "bindaddr": "*"
+
+ // More RADIUS parameters go here.
+ }
+ }
+ ]
+ }
+ }
+
+RADIUS is a complicated environment. As such, it is not feasible
+to provide a default configuration that works for everyone.
+However, we do have an example that showcases some of the more common
+features. Please see ``doc/examples/kea4/hooks-radius.json`` in the Kea
+sources.
+
+The RADIUS hook library supports the following global configuration
+flags:
+
+- ``bindaddr`` (default ``"*"``) - specifies the address to be used by the
+ hook library in communication with RADIUS servers. The ``"*"`` special
+ value tells the kernel to choose the address at hook library load time.
+
+- ``canonical-mac-address`` (default ``false``) - specifies whether MAC
+ addresses in attributes follow the canonical RADIUS format (lowercase
+ pairs of hexadecimal digits separated by ``-``).
+
+- ``client-id-pop0`` (default ``false``) - is used with
+ :ischooklib:`libdhcp_flex_id.so`. Removes the leading zero (or pair of zeroes
+ in DHCPv6) type in the client id (duid in DHCPv6). See
+ ``client-id-printable`` for any value implications when used in conjunction
+ with it.
+
+- ``client-id-printable`` (default ``false``) - checks whether the
+ ``client-id``/``duid`` content is printable and uses it as is instead of in
+ hexadecimal. Implies ``client-id-pop0`` and ``extract-duid`` as 0 and 255 are
+ not printable.
+
+- ``deadtime`` (default ``0``) - is a mechanism that helps in sorting the
+ servers such that the servers that have proved responsive so far are inquired
+ first, and the servers that have proved unresponsive are left at the end. The
+ deadtime value specifies the number of seconds after which a server is
+ considered unresponsive. 0 disables the mechanism.
+
+- ``dictionary`` (default ``"/etc/kea/radius/dictionary"``) - is the
+ attribute and value dictionary. Note that it is a critical parameter.
+ A dictionary is provided by Kea and is set by default.
+
+- ``extract-duid`` (default ``true``) - extracts the embedded duid from an
+ RFC-4361-compliant DHCPv4 client id. See ``client-id-printable`` for any
+ value implications when used in conjunction with it.
+
+- ``identifier-type4`` (default ``"client-id"``) - specifies the identifier
+ type to build the User-Name attribute. It should be the same as the
+ host identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then
+ ``replace-client-id`` must be set to ``true`` and ``client-id`` must be used
+ with ``client-id-pop0`` enabled.
+
+- ``identifier-type6`` (default ``"duid"``) - specifies the identifier type to
+ build the User-Name attribute. It should be the same as the host
+ identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then
+ ``replace-client-id`` must be set to ``true`` and ``duid`` must be used with
+ ``client-id-pop0`` enabled.
+
+- ``nas-ports`` (default ``[]``), specifies the NAS port to use in place of
+ a subnet ID (default behavior). It is an array of maps, each map having two
+ elements at most: the mandatory NAS port value, and, optionally, a selector
+ consisting of either a subnet id, a subnet prefix, or a shared-network name.
+ If the selector is applied to the packet, the NAS port is used instead of the
+ subnet id. When the subnet id is 0 or missing, the specified NAS port acts as
+ a default. Its substition happens for all packets that did not match a
+ selector.
+
+- ``realm`` (default ``""``) - is the default realm.
+
+- ``reselect-subnet-address`` (default ``false``) - enables subnet reselection
+ according to the value of the Framed-IP-Address or, respectively,
+ the Framed-IPv6-Address attribute from the RADIUS access response. With this
+ flag enabled, if the IP address is not in range of the currently selected
+ subnet, but is in range of another subnet that is selectable with regards to
+ other criteria, the latter subnet is selected and used further in the lease
+ assignment process.
+
+- ``reselect-subnet-pool`` (default ``false``) - enables subnet reselection
+ according to the value of the Framed-Pool attribute from the RADIUS access
+ response. With this flag enabled, if the currently selected subnet is not
+ guarded by the client class represented by the attribute value, but there is
+ another selectable subnet that is guarded by it, the latter subnet is
+ selected and used further in the lease assignment process.
+ This reselection is attempted first, and if successful, it prevents the
+ function of reselect-subnet-address from coming into effect.
+
+- ``retries`` (default ``3``) - is the number of retries before trying the
+ next server.
+
+- ``session-history`` (default ``""``) - is the name of the file providing
+ persistent storage for accounting session history.
+
+ - ``thread-pool-size`` (default ``0``) indicates the number of threads that
+ is used for sending RADIUS requests and processing RADIUS responses for both
+ access and accounting services before passing it to the core thread pool. A
+ value of ``0`` instructs the RADIUS hook library to use the same number of
+ threads used for core DHCP processing. This value is only relevant if Kea
+ core is configured as multi-threaded. Single-threaded Kea core results in
+ single-threaded RADIUS processing.
+
+- ``timeout`` (default ``10``) - is the number of seconds during which a
+ response is awaited.
+
+Two services are supported:
+
+- ``access`` - the authorization service.
+
+- ``accounting`` - the accounting service.
+
+At the service level, three sections can be configured:
+
+- Servers that define RADIUS services that the library is expected to
+ contact. Each server may have the following items specified:
+
+ - ``name`` - specifies the IP address of the server. A domain name may be
+ used and will be resolved at hook library load time.
+
+ - ``port`` - specifies the UDP port of the server. By default, it is 1812
+ for access and 1813 for accounting.
+
+ - ``secret`` - authenticates messages.
+
+ When no server is specified, the service is disabled.
+
+- Attributes which define additional information that the Kea server
+ sends to a RADIUS server. The parameter must be identified either
+ by a name or type. Its value can be specified in one of three
+ possible ways: ``data`` (which defines a plain text value), ``raw`` (which
+ defines the value in hex), or ``expr`` (which defines an expression
+ that is evaluated for each incoming packet independently).
+
+ - ``name`` - the name of the attribute.
+
+ - ``type`` - the type of the attribute. Either the type or the name must be
+ provided, and the attribute must be defined in the dictionary.
+
+ - ``data`` - the first of three ways to specify the attribute content.
+ It specifies the textual representation of the attribute content.
+
+ - ``raw`` - the second of three ways to specify the attribute content.
+ It specifies the content in hexadecimal.
+
+ - ``expr`` - the last of the three ways to specify the attribute content.
+ It specifies an evaluation expression on the DHCP query packet.
+ Currently this is restricted to the access service.
+
+ Attributes are supported only for the access service.
+
+- The ``peer-updates`` boolean flag (default ``true``) controls whether lease
+ updates coming from an active High-Availability (HA) partner should result in
+ an accounting request. This may be desirable to remove duplicates if HA
+ partners are configured to send request to the same RADIUS server. The flag is
+ only supported by the accounting service. The lease synchronization process at
+ the startup of an HA node does not trigger a RADIUS accounting request,
+ regardless of the value of this flag.
+
+- The ``max-pending-requests`` positive integer (default ``0``) limits the
+ number of pending RADIUS requests. The value ``0`` means no limit. It is
+ supported only by the access service. ``64`` can be a good value to set it to.
+
+For example, to specify a single access server available on localhost
+that uses ``"xyz123"`` as a secret, and tell Kea to send three additional
+attributes (``User-Password``, ``Connect-Info``, and ``Configuration-Token``),
+the following snippet could be used:
+
+.. parsed-literal::
+
+ {
+ "parameters": {
+
+ // Other RADIUS parameters here
+
+ "access": {
+
+ // This starts the list of access servers.
+ "servers": [
+ {
+ // These are parameters for the first (and only) access server
+ "name": "127.0.0.1",
+ "port": 1812,
+ "secret": "xyz123"
+ }
+ // Additional access servers could be specified here.
+ ],
+
+ // This defines a list of additional attributes Kea will send to each
+ // access server in Access-Request.
+ "attributes": [
+ {
+ // This attribute is identified by name (must be present in the
+ // dictionary) and has static value (i.e. the same value will be
+ // sent to every server for every packet).
+ "name": "User-Password",
+ "data": "mysecretpassword"
+ },
+ {
+ // It is also possible to specify an attribute using its type,
+ // rather than a name. 77 is Connect-Info. The value is specified
+ // using hex. Again, this is a static value. It will be sent the
+ // same for every packet and to every server.
+ "type": 77,
+ "raw": "65666a6a71"
+ },
+ {
+ // This example shows how an expression can be used to send dynamic value.
+ // The expression (see :ref:`classification-using-expressions`) may take any
+ // value from the incoming packet or even its metadata e.g. the
+ // interface it was received over from.
+ "name": "Configuration-Token",
+ "expr": "hexstring(pkt4.mac,':')"
+ }
+ ] // End of attributes
+ }, // End of access
+
+ // Accounting parameters.
+ "accounting": {
+ // This starts the list of accounting servers.
+ "servers": [
+ {
+ // These are parameters for the first (and only) accounting server
+ "name": "127.0.0.1",
+ "port": 1813,
+ "secret": "sekret"
+ }
+ // Additional accounting servers could be specified here.
+ ]
+ }
+ }
+ }
+
+Customization is sometimes required for certain attributes by devices belonging
+to various vendors. This is a great way to leverage the expression evaluation
+mechanism. For example, MAC addresses which might be used as a convenience
+value for the ``User-Password`` attribute are most likely to appear in colon-hexadecimal
+notation (``de:ad:be:ef:ca:fe``), but they might need to be expressed in
+hyphen-hexadecimal notation (``de-ad-be-ef-ca-fe``). Here's how to specify that:
+
+.. code-block:: json
+
+ {
+ "parameters": {
+ "access": {
+ "attributes": [
+ {
+ "name": "User-Password",
+ "expr": "hexstring(pkt4.mac, '-')"
+ }
+ ]
+ }
+ }
+ }
+
+And here's how to specify period-separated hexadecimal notation (``dead.beef.cafe``), preferred by Cisco devices:
+
+.. code-block:: json
+
+ {
+ "parameters": {
+ "access": {
+ "attributes": [
+ {
+ "name": "User-Password",
+ "expr": "substring(hexstring(pkt4.mac, ''), 0, 4) + '.' + substring(hexstring(pkt4.mac, ''), 4, 4) + '.' + substring(hexstring(pkt4.mac, ''), 8, 4)"
+ }
+ ]
+ }
+ }
+ }
+
+
+For :ischooklib:`libdhcp_radius.so` to operate properly in DHCPv4,
+:ischooklib:`libdhcp_host_cache.so` must also be loaded. The reason for this
+is somewhat complex. In a typical deployment, the DHCP clients send
+their packets via DHCP relay, which inserts certain Relay Agent
+Information options, such as ``circuit-id`` or ``remote-id``. The values of
+those options are then used by the Kea DHCP server to formulate the
+necessary attributes in the Access-Request message sent to the RADIUS
+server. However, once the DHCP client gets its address, it then renews
+by sending packets directly to the DHCP server. As a result, the relays
+are not able to insert their RAI options, and the DHCP server cannot send
+the Access-Request queries to the RADIUS server by using just the
+information from incoming packets. Kea needs to keep the information
+received during the initial Discover/Offer exchanges and use it again
+later when sending accounting messages.
+
+This mechanism is implemented based on user context in host
+reservations. (See :ref:`user-context` and :ref:`user-context-hooks` for
+details.) The host-cache mechanism allows the information retrieved by
+RADIUS to be stored and later used for sending access and accounting
+queries to the RADIUS server. In other words, the host-cache mechanism
+is mandatory, unless administrators do not want RADIUS communication for messages
+other than Discover and the first Request from each client.
+
+.. note::
+
+ Currently the RADIUS hook library is incompatible with the
+ ``early-global-reservations-lookup`` global parameter i.e.
+ setting the parameter to ``true`` raises an error when the
+ hook library is loaded.
+
+.. note::
+
+ Currently the RADIUS hook library is incompatible with the
+ multi-subnet shared networks that have host reservations other
+ than global. Loading the RADIUS hook library in a Kea DHCP server
+ that has this configuration raises an error.
+
+.. _radius-server-example:
+
+RADIUS Server Setup Example
+---------------------------
+
+The RADIUS hook library requires at least one RADIUS server to function. One
+popular open-source implementation is FreeRADIUS. This is how it can be
+set up to enable basic functionality in Kea.
+
+1. Install FreeRADIUS through the package manager or from the tarballs available
+ on [the freeradius.org download page](https://freeradius.org/releases/).
+
+2. Establish the FreeRADIUS configuration directory. It's commonly
+ ``/etc/freeradius``, but it may be ``/etc/raddb``.
+
+3. Generate certificates. Go to ``/etc/freeradius/certs``.
+ Run ``./bootstrap`` or ``make``.
+ Wait until finished. It should take a few seconds.
+
+4. Check that the server is able to start.
+ Running with the ``-X`` flag is a good way to display potential errors.
+ Run ``radiusd -X`` or ``freeradius -X``, whichever is available.
+ It should display ``Ready to process requests`` on the final line.
+
+5. If the Kea DHCP server and the RADIUS server are on different machines,
+ edit ``/etc/freeradius/clients.conf`` with the proper address under
+ ``ipadddr``. This file is also where the secret is set, which needs to match
+ the one set in the hook library's configuration.
+
+6. If RADIUS is used for the purpose of authorizing DHCP clients, each DHCP
+ client needs to have an entry in the authorize file, which can be commonly
+ found at:
+
+ - ``/etc/raddb/mods-config/files/authorize``
+ - ``/etc/freeradius/3.0/mods-config/files/authorize``
+ - ``/etc/freeradius/users`` (for RADIUS 2.x series)
+
+ Entries need to have the password set which needs to match the password
+ configured in the configuration of the RADIUS hook library under the
+ ``User-Password`` attribute. Each entry can have zero, one or multiple
+ attributes.
+
+ In the following example, there are 6 entries with the password set to the
+ client ID, which would need to be dynamically set in the hook library's
+ configuration. Here's how the entries can look like:
+
+ ::
+
+ 01:00:0c:01:02:03:04 Cleartext-password := "00:0c:01:02:03:04"
+
+ 01:00:0c:01:02:03:05 Cleartext-password := "00:0c:01:02:03:05"
+ Framed-IP-Address = "192.0.2.5"
+
+ 01:00:0c:01:02:03:06 Cleartext-password := "00:0c:01:02:03:06"
+ Framed-IP-Address = "192.0.2.6",
+ Framed-Pool = "classical"
+
+ 00:03:00:01:00:0c:01:02:03:07 Cleartext-password := "00:0c:01:02:03:07"
+
+ 00:03:00:01:00:0c:01:02:03:08 Cleartext-password := "00:0c:01:02:03:08"
+ Framed-IPv6-Address = "2001:db8::8"
+
+ 00:03:00:01:00:0c:01:02:03:09 Cleartext-password := "00:0c:01:02:03:09"
+ Framed-IPv6-Address = "2001:db8::9",
+ Framed-Pool = "classroom"
+
+7. Accounting should work out of the box with Kea, but customizations are
+ possible in the accounting file, which can be commonly found at:
+
+ - ``/etc/radius-config/mods-config/files/accounting``
+ - ``/etc/freeradius/3.0/mods-config/files/accounting``
+
+.. _radius-lease-allocation:
+
+RADIUS Workflows for Lease Allocation
+-------------------------------------
+
+The following diagrams show a high level view of how RADIUS assists with the
+lease allocation process in :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`.
+
+.. figure:: ../uml/radius.*
+
+Somewhat tangential to lease allocation, and not shown in the diagrams above,
+is the ``command_processed`` callout, which sends Accounting-Request messages
+when a lease command is received.
+
+.. _radius-differences:
+
+Differences Between RADIUS Hook Libraries Prior To 2.4.0 and As Of 2.6.0
+------------------------------------------------------------------------
+
+The RADIUS hook library in 2.4.0 and prior versions relied on the FreeRADIUS
+client library to function. Starting with 2.6.0 and onwards, the RADIUS hook
+library is standalone with its own RADIUS client implementation and its own
+RADIUS dictionary. There are differences:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Feature
+
+ - Old
+
+ - New
+
+ * - Support for Attribute Data Types
+
+ - string, ipaddr, ipv4prefix, integer, integer64, date, ifid, ipv6addr, ipv6prefix, tlv, abinary, byte, ether, short, signed, octets
+
+ - string (can simulate any other unsupported data type too), ipaddr, integer, date (interpreted as integer), ipv6addr, ipv6prefix
+
+ * - Names of Standard Attributes
+
+ - Taken from the FreeRADIUS dictionary.
+
+ - Taken from the Kea RADIUS dictionary and the IANA registry. There is an aliasing mechanism built into the library that ensures backward compatibility e.g. ``Password`` translates to the standard name of the attribute ``User-Password``.
+
+ * - Resolution of RADIUS Server Domain Names
+
+ - At run time.
+
+ - At hook library load time.
+
+ * - Automatic Deduction of Source Address for Reaching RADIUS Servers (configured with ``bindaddr: "*"``)
+
+ - At run time.
+
+ - At hook library load time.
+
+ * - RADIUS Server Limit per Service
+
+ - 8
+
+ - Unlimited
+
+ * - Support for Including Dictionaries Inside Dictionaries
+
+ - Yes
+
+ - No
+
+ * - Support for Vendor Attributes
+
+ - Yes
+
+ - No
+
+ * - Attribute Names and Attribute Values
+
+ - Case-insensitive
+
+ - Case-sensitive
+
+ * - Integer Values
+
+ - Do not require an attribute definition.
+
+ - Must have an associated attribute definition in the dictionary.
+
+ * - Reply-Message Presence in the Kea Logs
+
+ - Only as part of the aggregated list of attributes in ``RADIUS_AUTHENTICATION_ACCEPTED``, ``RADIUS_ACCESS_CACHE_INSERT``, ``RADIUS_ACCESS_CACHE_GET`` log messages.
+
+ - Also has a dedicated ``RADIUS_REPLY_MESSAGE_ATTRIBUTE`` message per each Reply-Message attribute logged after a valid RADIUS reply is received.
+
+ * - Behavior of Multiple Attributes of the Same Type (except Reply-Message)
+
+ - Experimentally, only the **first** attribute on the wire from an Access-Accept message is considered.
+
+ - Experimentally, only the **last** attribute on the wire from an Access-Accept message is considered.
diff --git a/doc/sphinx/arm/hammer.rst b/doc/sphinx/arm/hammer.rst
new file mode 100644
index 0000000..2d25a52
--- /dev/null
+++ b/doc/sphinx/arm/hammer.rst
@@ -0,0 +1,137 @@
+.. _hammer:
+
+Hammer Building Tool
+====================
+
+Hammer is a Python 3 script that lets users automate tasks related to building
+Kea, such as setting up virtual machines, installing Kea dependencies,
+compiling Kea with various options, running unit-tests and more. This
+tool was created primarily for internal QA purposes at ISC and it is not
+included in the Kea distribution; however, it is available in the Kea
+git repository. This tool was developed primarily for internal purposes
+and ISC cannot guarantee its proper operation. Administrators who decide to use it
+should do so with care.
+
+.. note::
+
+ Use of this tool is completely optional. Everything it does can be
+ done manually.
+
+The first-time user is strongly encouraged to look at Hammer's built-in
+help:
+
+.. code-block:: console
+
+ $ ./hammer.py --help
+
+It will list available parameters.
+
+Hammer is able to set up various operating systems running either in LXC
+or in VirtualBox. For a list of supported systems, use the
+``supported-systems`` command:
+
+.. code-block:: console
+
+ $ ./hammer.py supported-systems
+ fedora:
+ - 37: lxc
+ - 38:
+ centos:
+ - 8: lxc, virtualbox
+ - 9:
+ rhel:
+ - 8: virtualbox
+ - 9:
+ ubuntu:
+ - 18.04: lxc, virtualbox
+ - 20.04: lxc
+ - 22.04: lxc
+ debian:
+ - 10: lxc, virtualbox
+ - 11: lxc
+ - 12: lxc
+ freebsd:
+ - 12.0: virtualbox
+ - 12.1:
+ - 13.0: virtualbox
+ alpine:
+ - 3.15: lxc
+ - 3.16: lxc
+ - 3.17: lxc
+
+It is also possible to run the build locally, in the current system (if the OS
+is supported).
+
+First, the Hammer dependencies must be installed: Vagrant
+and either VirtualBox or LXC. Hammer can install
+Vagrant and the required Vagrant plugins using the command:
+
+.. code-block:: console
+
+ $ ./hammer.py ensure-hammer-deps
+
+VirtualBox and LXC must be installed manually.
+
+The basic functions provided by Hammer are to prepare the build environment
+and perform the actual build, and to run the unit tests locally in the current
+system. This can be achieved by running the command:
+
+.. code-block:: console
+
+ $ ./hammer.py build -p local
+
+The scope of the process can be defined using the ``--with`` (``-w``) and ``--without``
+(``-x``) options. By default, the ``build`` command builds Kea with
+documentation, installs it locally, and runs unit tests.
+
+To exclude the installation and generation of docs, type:
+
+.. code-block:: console
+
+ $ ./hammer.py build -p local -x install docs
+
+The basic scope can be extended by mysql, pgsql, native-pkg, shell, and forge.
+Please check ``./hammer.py build --help`` for more details.
+
+.. note::
+
+ If building Kea locally, Hammer dependencies like Vagrant are
+ not needed.
+
+Hammer can be told to set up a new virtual machine with a specified
+operating system, without the build:
+
+.. code-block:: console
+
+ $ ./hammer.py prepare-system -p virtualbox -s freebsd -r 12.0
+
+This way, a system can be prepared for our own use. To get to such a system
+using SSH, invoke:
+
+.. code-block:: console
+
+ $ ./hammer.py ssh -p virtualbox -s freebsd -r 12.0
+
+It is possible to speed up subsequent Hammer builds via
+`ccache <https://ccache.samba.org/>`__. During
+compilation, ccache stores objects in a shared folder. In subsequent runs,
+instead of doing an actual compilation, ccache returns the stored earlier
+objects. The cache with these objects for reuse must be stored outside of VM
+or LXC. To indicate the folder, the ``--ccache-dir``
+parameter for Hammer must be included. In the indicated folder, there are separate stored objects for each target
+operating system.
+
+.. code-block:: console
+
+ $ ./hammer.py build -p lxc -s ubuntu -r 18.04 --ccache-dir ~/kea-ccache
+
+.. note::
+
+ ccache is currently only supported for LXC in Hammer; support
+ for VirtualBox may be added later.
+
+For more information check:
+
+.. code-block:: console
+
+ $ ./hammer.py --help
diff --git a/doc/sphinx/arm/hooks-bootp.rst b/doc/sphinx/arm/hooks-bootp.rst
new file mode 100644
index 0000000..7f8a749
--- /dev/null
+++ b/doc/sphinx/arm/hooks-bootp.rst
@@ -0,0 +1,91 @@
+.. ischooklib:: libdhcp_bootp.so
+.. _hooks-bootp:
+
+``libdhcp_bootp.so``: Support for BOOTP Clients
+===============================================
+
+This hook library adds support for BOOTP with vendor-information extensions
+(`RFC 1497 <https://tools.ietf.org/html/rfc1497>`__). Received BOOTP
+requests are recognized, translated into DHCPREQUEST packets by adding
+a ``dhcp-message-type`` option, and put into the "BOOTP" client class.
+Members of this class get infinite lifetime leases but the class can
+also be used to guard a pool of addresses.
+
+The DHCP-specific options, such as ``dhcp-message-type``, are removed from
+the server's responses; responses shorter than the BOOTP minimum
+size of 300 octets are padded to this size.
+
+.. note::
+
+ :ischooklib:`libdhcp_bootp.so` is part of the open source code and is
+ available to every Kea user.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` process,
+ as there is no BOOTP protocol for IPv6.
+
+This library is loaded similarly to other hook libraries, and
+it takes no parameters.
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ { "library": "/usr/local/lib/libdhcp_bootp.so" },
+ ...
+ ]
+ }
+
+.. note::
+
+ A host reservation for a BOOTP client should use the hardware address
+ as the identifier (the ``client-id`` option is a DHCP-specific option).
+
+.. _hooks-bootp-config:
+
+Incoming BOOTP packets are added to the BOOTP class, allowing administrators
+to segregate BOOTP clients into separate pools. For example:
+
+::
+
+ "Dhcp4": {
+ "client-classes": [
+ {
+ // The DHCP class is the complement of the BOOTP class
+ "name": "DHCP",
+ "test": "not member('BOOTP')"
+ }
+ ],
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ // BOOTP clients will be handled here
+ "pool": "192.0.2.200 - 192.0.2.254",
+ "client-class": "BOOTP"
+ },
+ {
+ // Regular DHCP clients will be handled here
+ "pool": "192.0.2.1 - 192.0.2.199",
+ "client-class": "DHCP"
+ }],
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+
+
+.. _hooks-bootp-limitations:
+
+BOOTP Hooks Limitations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently the BOOTP library has the following limitation:
+
+- Basic BOOTP, as defined in `RFC 951
+ <https://tools.ietf.org/html/rfc951>`__, is not supported. Kea only
+ supports BOOTP with vendor-information extensions.
diff --git a/doc/sphinx/arm/hooks-cb-cmds.rst b/doc/sphinx/arm/hooks-cb-cmds.rst
new file mode 100644
index 0000000..237f911
--- /dev/null
+++ b/doc/sphinx/arm/hooks-cb-cmds.rst
@@ -0,0 +1,2248 @@
+.. ischooklib:: libdhcp_cb_cmds.so
+.. _hooks-cb-cmds:
+
+``libdhcp_cb_cmds.so``: Configuration Backend Commands
+======================================================
+
+This hook library is used to manage Kea
+servers' configurations in a configuration backend database. This library must
+be used in conjunction with the available CB hook libraries implementing
+the common APIs to create, read, update, and delete (CRUD) the
+configuration information in the respective databases. For example:
+:ischooklib:`libdhcp_mysql_cb.so` implements this API for MySQL while
+:ischooklib:`libdhcp_pgsql_cb.so` implements this API for PostgreSQL.
+To manage the configuration information in a MySQL database, both
+:ischooklib:`libdhcp_mysql_cb.so` and :ischooklib:`libdhcp_cb_cmds.so`
+must be loaded by the server used for the configuration management.
+To manage the configuration information in a PostgreSQL database, both
+:ischooklib:`libdhcp_pgsql_cb.so` and :ischooklib:`libdhcp_cb_cmds.so`
+must be loaded by the server used for the configuration management.
+
+More information on how to configure the Configuration Backend hook library for
+use with a MySQL or PostgreSQL database can be found in the :ref:`dhcp4-cb`
+and :ref:`dhcp6-cb` sections.
+
+.. note::
+
+ :ischooklib:`libdhcp_cb_cmds.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or
+ :iscman:`kea-dhcp6` process.
+
+.. note::
+
+ Please read about :ref:`cb-limitations` before using the commands
+ described in this section.
+
+Command Structure
+~~~~~~~~~~~~~~~~~
+
+There are 5 types of commands supported by this library:
+
+- ``del`` - delete the selected object from the database, e.g.
+ :isccmd:`remote-global-parameter4-del`.
+
+- ``get`` - fetch the selected object from the database, e.g.
+ :isccmd:`remote-subnet4-get-by-id`.
+
+- ``get-all`` - fetch all objects of the particular type from the
+ database, e.g. :isccmd:`remote-option-def4-get-all`.
+
+- ``list`` - list all objects of the particular type in the database,
+ e.g. :isccmd:`remote-network4-list`; this class of commands returns brief
+ information about each object compared to the output of ``get-all``.
+
+- ``set`` - creates or replaces an object of the given type in the
+ database, e.g. :isccmd:`remote-option4-global-set`.
+
+All types of commands accept an optional ``remote`` map which selects the
+database instance to which the command refers. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-list",
+ "arguments": {
+ "remote": {
+ "type": "mysql",
+ "host": "192.0.2.33",
+ "port": 3302
+ }
+ }
+ }
+
+selects the MySQL database, running on host 192.0.2.33 and port 3302, to
+fetch the list of subnets from. All parameters in the ``remote`` argument are
+optional. The ``port`` parameter can be only specified in conjunction
+with the ``host``. If no options in the ``remote`` parameter are to
+be specified, the parameter should be omitted. In this case, the server
+will use the first backend listed in the ``config-control`` map within
+the configuration of the server receiving the command.
+
+.. note::
+
+ In the current Kea release, it is only possible to configure the Kea server
+ to use a single configuration backend. Strictly speaking, it is
+ possible to point the Kea server to at most one database (either MySQL or
+ PostgreSQL) using the ``config-control`` parameter. Therefore, the ``remote``
+ parameter may be omitted in the commands and :ischooklib:`libdhcp_cb_cmds.so`
+ uses the sole backend by default. The example commands below most often show a
+ value of "mysql" for the ``type`` parameter; it should be assumed that the
+ value is "postgresql" for installations using a PostgreSQL database.
+
+.. _cb-cmds-dhcp:
+
+Control Commands for DHCP Servers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section describes and gives some examples of the control commands
+implemented by :ischooklib:`libdhcp_cb_cmds.so`, to manage the
+configuration information of the DHCPv4 and DHCPv6 servers. Many of the
+commands are almost identical between DHCPv4 and DHCPv6; they only
+differ by the command name. Other commands differ slightly by the
+structure of the inserted data; for example, the structure of the IPv4 subnet
+information is different than that of the IPv6 subnet.
+Nevertheless, they still share the structure of their command arguments
+and thus it makes sense to describe them together.
+
+In addition, whenever the text in the subsequent sections refers to a
+DHCP command or DHCP parameter, it refers to both DHCPv4 and DHCPv6
+variants. The text specific to the particular server type refers to them
+as: DHCPv4 command, DHCPv4 parameter, DHCPv6 command, DHCPv6 parameter,
+etc.
+
+.. _cb-cmds-metadata:
+
+Metadata
+~~~~~~~~
+
+The typical response to the ``get`` or ``list`` command includes a list
+of returned objects (e.g. subnets), and each such object contains the
+``metadata`` map with some database-specific information describing this
+object. In other words, the metadata contains any information about the
+fetched object which may be useful for an administrator but which is not
+part of the object specification from the DHCP server standpoint. In the
+present Kea release, the metadata is limited to the ``server-tag``. It
+describes the association of the object with a particular server or
+all servers.
+
+The following is the example response to the :isccmd:`remote-network4-list`
+command, which includes the metadata:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 IPv4 shared network(s) found.",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "level3",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+
+Client implementations must not assume that the metadata contains only
+the ``server-tags`` parameter. In future releases, it is expected that this
+map will be extended with additional information, e.g. object modification
+time, log message created during the last modification, etc.
+
+.. isccmd:: remote-server4-del
+.. _command-remote-server4-del:
+.. isccmd:: remote-server6-del
+.. _command-remote-server6-del:
+
+The ``remote-server4-del``, ``remote-server6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to delete the information about a selected DHCP server from
+the configuration database. The server is identified by a unique case
+insensitive server tag. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-server4-del",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1"
+ }
+ ],
+ "remote": {
+ "type": "postgresql"
+ }
+ }
+ }
+
+As a result of this command, all associations of the configuration for the
+user-defined server called "server1" are removed from the database, including
+non-shareable configuration information, such as global parameters, option
+definitions, and global options. Any shareable configuration information,
+i.e. the configuration elements which may
+be associated with more than one server, is preserved. In particular, the
+subnets and shared networks associated with the deleted servers are
+preserved. If any of the shareable configuration elements was associated only
+with the deleted server, this object becomes unassigned (orphaned). For
+example: if a subnet has been created and associated with "server1" using
+the :isccmd:`remote-subnet4-set` command and "server1" is subsequently deleted, the
+subnet remains in the database but no servers can use this subnet. The
+subnet can be updated using the :isccmd:`remote-subnet4-set` command, and can be
+associated with either another server or with all servers, using the special
+server tag "all". Such a subnet can be also deleted from the database
+using the :isccmd:`remote-subnet4-del-by-id` or
+:isccmd:`remote-subnet4-del-by-prefix` command, if it is no longer needed.
+
+The following is the successful response to the :isccmd:`remote-server4-del` command:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv4 server(s) deleted.",
+ "arguments": {
+ "count": 1
+ }
+ }
+
+
+.. warning::
+
+ The :isccmd:`remote-server4-del` and
+ :isccmd:`remote-server6-del` commands must be used with
+ care, because an accidental deletion of the server can cause some parts of the
+ existing configurations to be lost permanently from the database. This
+ operation is not reversible. Re-creation of the accidentally deleted server
+ does not revert the lost configuration for that server and such configuration
+ must be re-created manually by the user.
+
+.. isccmd:: remote-server4-get
+.. _command-remote-server4-get:
+.. isccmd:: remote-server6-get
+.. _command-remote-server6-get:
+
+The ``remote-server4-get``, ``remote-server6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to fetch the information about the selected DHCP server
+from the configuration database. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-server6-get",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+
+This command fetches the information about the DHCPv6 server identified by the
+server tag "server1". The server tag is case-insensitive. A successful response
+returns basic information about the server, such as the server tag and the user's
+description of the server:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCP server server1 found.",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1",
+ "description": "A DHCPv6 server located on the first floor."
+ }
+ ],
+ "count": 1
+ }
+ }
+
+.. isccmd:: remote-server4-get-all
+.. _command-remote-server4-get-all:
+.. isccmd:: remote-server6-get-all
+.. _command-remote-server6-get-all:
+
+The ``remote-server4-get-all``, ``remote-server6-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to fetch all user-defined DHCPv4 or DHCPv6 servers from the
+database. The command structure is very simple:
+
+.. code-block:: json
+
+ {
+ "command": "remote-server4-get-all",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The response includes basic information about each server, such as its server
+tag and description:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCPv4 servers found.",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1",
+ "description": "A DHCP server located on the first floor."
+ },
+ {
+ "server-tag": "server2",
+ "description": "An old DHCP server to be soon replaced."
+ }
+ ],
+ "count": 2
+ }
+ }
+
+.. isccmd:: remote-server4-set
+.. _command-remote-server4-set:
+.. isccmd:: remote-server6-set
+.. _command-remote-server6-set:
+
+The ``remote-server4-set``, ``remote-server6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to create or replace an information about a DHCP server in
+the database. The information about the server must be created when there is a
+need to differentiate the configurations used by various Kea instances
+connecting to the same database. Various configuration elements, e.g. global
+parameters, subnets, etc. may be explicitly associated with the selected servers
+(using server tags as identifiers), allowing only these servers to use the
+respective configuration elements. Using the particular server tag to make such
+associations is only possible when the server information has been stored in the
+database via the :isccmd:`remote-server4-set` or
+:isccmd:`remote-server6-set` commands. The
+following command creates a new (or updates an existing) DHCPv6 server in the
+database:
+
+.. code-block:: json
+
+ {
+ "command": "remote-server6-set",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1",
+ "description": "A DHCP server on the ground floor."
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The server tag must be unique across all servers in the database. When the
+server information under the given server tag already exists, it is replaced
+with the new information. The specified server tag is case-insensitive, and the
+maximum length of the server tag is 256 characters. The following keywords are
+reserved and cannot be used as server tags: "all" and "any".
+
+The following is the example response to the above command:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCPv6 server successfully set.",
+ "arguments": {
+ "servers": [
+ {
+ "server-tag": "server1",
+ "description": "A DHCP server on the ground floor."
+ }
+ ]
+ }
+ }
+
+
+.. isccmd:: remote-global-parameter4-del
+.. _command-remote-global-parameter4-del:
+
+.. isccmd:: remote-global-parameter6-del
+.. _command-remote-global-parameter6-del:
+
+The ``remote-global-parameter4-del``, ``remote-global-parameter6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete a global DHCP parameter from the
+configuration database. When the parameter is deleted from the database,
+the server uses the value specified in the configuration file for
+this parameter, or a default value if the parameter is not specified in
+the configuration file.
+
+The following command attempts to delete the DHCPv4 ``renew-timer``
+parameter common for all servers from the database:
+
+.. code-block:: json
+
+ {
+ "command": "remote-global-parameter4-del",
+ "arguments": {
+ "parameters": [ "renew-timer" ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+If a server-specific parameter is to be deleted, the
+``server-tags`` list must contain the tag of the appropriate
+server. There must be exactly one server tag specified in this list.
+
+.. isccmd:: remote-global-parameter4-get
+.. _command-remote-global-parameter4-get:
+
+.. isccmd:: remote-global-parameter6-get
+.. _command-remote-global-parameter6-get:
+
+The ``remote-global-parameter4-get``, ``remote-global-parameter6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch a scalar global DHCP parameter from the
+configuration database.
+
+The following command attempts to fetch the ``boot-file-name``
+parameter for "server1":
+
+.. code-block:: json
+
+ {
+ "command": "remote-global-parameter4-get",
+ "arguments": {
+ "parameters": [ "boot-file-name" ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+
+The returned value has one of the four scalar types: string, integer,
+real, or boolean. Non-scalar global configuration parameters, such as map
+or list, are not returned by this command.
+
+In the case of the example above, the string value is returned, e.g.:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv4 global parameter found.",
+ "arguments": {
+ "parameters": {
+ "boot-file-name": "/dev/null",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ },
+ "count": 1
+ }
+ }
+
+
+Note that the response above indicates that the returned parameter is associated
+with "all" servers rather than "server1", used in the command. This indicates
+that there is no "server1"-specific value in the database and therefore, the value
+shared by all servers is returned. If there were a "server1"-specific value
+in the database, that value would be returned instead.
+
+The example response for the integer value is:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv4 global parameter found.",
+ "arguments": {
+ "parameters": {
+ "renew-timer": 2000,
+ "metadata": {
+ "server-tags": [ "server1" ]
+ }
+ },
+ "count": 1
+ }
+ }
+
+
+The real value:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv4 global parameter found.",
+ "arguments": {
+ "parameters": {
+ "t1-percent": 0.85,
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ },
+ "count": 1
+ }
+ }
+
+
+Finally, the boolean value:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv4 global parameter found.",
+ "arguments": {
+ "parameters": {
+ "match-client-id": true,
+ "metadata": {
+ "server-tags": [ "server2" ]
+ }
+ },
+ "count": 1
+ }
+ }
+
+
+.. isccmd:: remote-global-parameter4-get-all
+.. _command-remote-global-parameter4-get-all:
+
+.. isccmd:: remote-global-parameter6-get-all
+.. _command-remote-global-parameter6-get-all:
+
+The ``remote-global-parameter4-get-all``, ``remote-global-parameter6-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch all global DHCP parameters from the database
+for the specified server. The following example demonstrates how to fetch all
+global parameters to be used by the server "server1":
+
+.. code-block:: json
+
+ {
+ "command": "remote-global-parameter4-get-all",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The example response may look as follows:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCPv4 global parameters found.",
+ "arguments": {
+ "parameters": [
+ {
+ "boot-file-name": "/dev/null",
+ "metadata": {
+ "server-tags": [ "server1" ]
+ }
+ },
+ {
+ "match-client-id": true,
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 2
+ }
+ }
+
+
+The example response contains two parameters: one string parameter and one
+boolean parameter. The metadata returned for each parameter indicates
+whether this parameter is specific to "server1" or applies to all servers. Since the
+``match-client-id`` value is associated with "all" servers,
+it indicates that there is no "server1"-specific setting for this parameter.
+Each parameter always has exactly one server tag associated with it, because
+global parameters are non-shareable configuration elements.
+
+.. note::
+
+ If the server tag is set to "all" in the command, the response will
+ contain only the global parameters associated with the logical server
+ "all". When the server tag points to the specific server (as in the
+ example above), the returned list combines parameters associated with
+ this server and all servers, but the former take precedence.
+
+.. isccmd:: remote-global-parameter4-set
+.. _command-remote-global-parameter4-set:
+
+.. isccmd:: remote-global-parameter6-set
+.. _command-remote-global-parameter6-set:
+
+The ``remote-global-parameter4-set``, ``remote-global-parameter6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to create scalar global DHCP parameters in the
+database. If any of the parameters already exists, its value is replaced
+as a result of this command. It is possible to set multiple parameters
+within a single command, each having one of the four types: string,
+integer, real, or boolean. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-global-parameter4-set",
+ "arguments": {
+ "parameters": {
+ "boot-file-name": "/dev/null",
+ "renew-timer": 2000,
+ "t1-percent": 0.85,
+ "match-client-id": true
+ },
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+An error is returned if any of the parameters is not supported by the DHCP
+server or its type does not match. Care should be taken when multiple parameters
+are specified in a single command, because it is possible that only some of the
+parameters will be stored successfully and some will fail. If an error occurs when
+processing this command, it is recommended to use
+:isccmd:`remote-global-parameter4-get-all` or
+:isccmd:`remote-global-parameter6-get-all`
+to check which of the parameters have
+been stored/updated successfully and which have failed.
+
+The ``server-tags`` list is mandatory and must contain a single server tag or
+the keyword "all". In the example above, all specified parameters are associated
+with the "server1" server.
+
+.. isccmd:: remote-network4-del
+.. _command-remote-network4-del:
+
+.. isccmd:: remote-network6-del
+.. _command-remote-network6-del:
+
+The ``remote-network4-del``, ``remote-network6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete an IPv4 or IPv6 shared network from
+the database. The optional parameter ``subnets-action`` determines
+whether the subnets belonging to the deleted shared network should also
+be deleted or preserved. The ``subnets-action`` parameter defaults to ``keep``,
+which preserves the subnets. If it is set to ``delete``, the subnets are
+deleted along with the shared network.
+
+The following command:
+
+.. code-block:: json
+
+ {
+ "command": "remote-network6-del",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "level3"
+ }
+ ],
+ "subnets-action": "keep",
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+
+deletes the "level3" IPv6 shared network. The subnets are preserved, but
+they are disassociated from the deleted shared network and become
+global. This behavior corresponds to the behavior of the
+:isccmd:`network4-del`, :isccmd:`network6-del` commands with respect to the
+``subnets-action`` parameter.
+
+Note that the ``server-tags`` parameter cannot be used for this command.
+
+.. isccmd:: remote-network4-get
+.. _command-remote-network4-get:
+
+.. isccmd:: remote-network6-get
+.. _command-remote-network6-get:
+
+The ``remote-network4-get``, ``remote-network6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to retrieve information about an IPv4 or
+IPv6 shared network. The optional parameter ``subnets-include`` denotes
+whether the subnets belonging to the shared network should also be
+returned. This parameter defaults to ``no``, in which case the subnets
+are not returned. If this parameter is set to ``full``, the subnets are
+returned together with the shared network.
+
+The following command fetches the "level3" IPv6 shared network along
+with the full information about the subnets belonging to it:
+
+.. code-block:: json
+
+ {
+ "command": "remote-network6-get",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "level3"
+ }
+ ],
+ "subnets-include": "full",
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+Note that the ``server-tags`` parameter cannot be used for this command.
+
+.. isccmd:: remote-network4-list
+.. _command-remote-network4-list:
+
+.. isccmd:: remote-network6-list
+.. _command-remote-network6-list:
+
+The ``remote-network4-list``, ``remote-network6-list`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to list all IPv4 or IPv6 shared networks for a server.
+
+The following command retrieves all shared networks to be used by
+"server1" and "server2":
+
+.. code-block:: json
+
+ {
+ "command": "remote-network4-list",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1", "server2" ]
+ }
+ }
+
+The ``server-tags`` parameter is mandatory and contains one or more server
+tags. It may contain the keyword "all" to fetch the shared networks associated
+with all servers. When the ``server-tags`` list contains the
+``null`` value, the returned response contains a list of unassigned shared
+networks, i.e. the networks which are associated with no servers. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-network4-list",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ null ]
+ }
+ }
+
+The example response to this command when non-null server tags are specified
+looks similar to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "3 IPv4 shared network(s) found.",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "ground floor",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ },
+ {
+ "name": "floor2",
+ "metadata": {
+ "server-tags": [ "server1" ]
+ }
+ },
+ {
+ "name": "floor3",
+ "metadata": {
+ "server-tags": [ "server2" ]
+ }
+ }
+ ],
+ "count": 3
+ }
+ }
+
+The returned information about each shared network merely contains the shared
+network name and the metadata. To fetch detailed information about
+the selected shared network, use the :isccmd:`remote-network4-get` or
+:isccmd:`remote-network6-get` command.
+
+The example response above contains three shared networks. One of the
+shared networks is associated with all servers, so it is included in
+the list of shared networks to be used by "server1" and "server2".
+The remaining two shared networks are returned because one of them
+is associated with "server1" and another one is associated with
+"server2".
+
+When listing unassigned shared networks, the response looks similar
+to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 IPv4 shared network(s) found.",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "fancy",
+ "metadata": {
+ "server-tags": [ null ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+The ``null`` value in the metadata indicates that the
+returned shared network is unassigned.
+
+.. isccmd:: remote-network4-set
+.. _command-remote-network4-set:
+
+.. isccmd:: remote-network6-set
+.. _command-remote-network6-set:
+
+The ``remote-network4-set``, ``remote-network6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new or replace an existing IPv4 or IPv6 shared
+network in the database. The structure of the shared network information
+is the same as in the Kea configuration file (see
+:ref:`shared-network4` and :ref:`shared-network6` for details),
+except that specifying subnets along with the shared
+network information is not allowed. Including the ``subnet4`` or ``subnet6`` parameter
+within the shared network information results in an error.
+
+These commands are intended to be used for managing the shared
+network-specific information and DHCP options. To associate and
+disassociate the subnets with the shared networks, the
+:isccmd:`remote-subnet4-set`, :isccmd:`remote-subnet6-set`
+commands should be used.
+
+The following command adds the IPv6 shared network "level3" to the
+database:
+
+.. code-block:: json
+
+ {
+ "command": "remote-network6-set",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "level3",
+ "interface": "eth0",
+ "option-data": [ {
+ "name": "sntp-servers",
+ "data": "2001:db8:1::1"
+ } ]
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+
+This command includes the ``interface`` parameter, which sets the shared
+network-level interface name. Any remaining shared-network level parameters,
+which are not specified with the command, will be marked as
+"unspecified" in the database. The DHCP server uses the global
+values for unspecified parameters or, if the global values are not
+specified, the default values are used.
+
+The ``server-tags`` list is mandatory for this command and must include one or
+more server tags. As a result, the shared network is associated with all listed
+servers. The shared network may be associated with all servers connecting to the
+database when the keyword "all" is included.
+
+.. note::
+
+ As with other "set" commands, this command replaces all the
+ information about the given shared network in the database, if the
+ shared network already exists. Therefore, when sending this command,
+ make sure to always include all parameters that must be specified for
+ the updated shared-network instance. Any unspecified parameter will
+ be marked unspecified in the database, even if its value was present
+ prior to sending the command.
+
+.. isccmd:: remote-option-def4-del
+.. _command-remote-option-def4-del:
+
+.. isccmd:: remote-option-def6-del
+.. _command-remote-option-def6-del:
+
+The ``remote-option-def4-del``, ``remote-option-def6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete a DHCP option definition from the
+database. The option definition is identified by an option code and
+option space. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option-def6-del",
+ "arguments": {
+ "option-defs": [
+ {
+ "code": 1,
+ "space": "isc"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+
+deletes the definition of the option associated with "server1", having the
+code of 1 and belonging to the option space "isc". The default option spaces are
+"dhcp4" and "dhcp6" for the DHCPv4 and DHCPv6 top-level options, respectively. If
+there is no such option explicitly associated with "server1", no option is
+deleted. To delete an option belonging to "all" servers, the keyword
+"all" must be used as the server tag. The ``server-tags`` list must contain exactly
+one tag and cannot include the ``null`` value.
+
+.. isccmd:: remote-option-def4-get
+.. _command-remote-option-def4-get:
+
+.. isccmd:: remote-option-def6-get
+.. _command-remote-option-def6-get:
+
+The ``remote-option-def4-get``, ``remote-option-def6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch a specified DHCP option definition from
+the database. The option definition is identified by the option code and
+option space. The default option spaces are "dhcp4" and "dhcp6" for the
+DHCPv4 and DHCPv6 top-level options, respectively.
+
+The following command retrieves a DHCPv4 option definition associated with all
+servers, having the code of 1 and belonging to the option space "isc":
+
+.. code-block:: json
+
+ {
+ "command": "remote-option-def4-get",
+ "arguments": {
+ "option-defs": [
+ {
+ "code": 1,
+ "space": "isc"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+The ``server-tags`` list must include exactly one server tag or the keyword
+"all", and cannot contain the `null` value.
+
+.. isccmd:: remote-option-def4-get-all
+.. _command-remote-option-def4-get-all:
+
+.. isccmd:: remote-option-def6-get-all
+.. _command-remote-option-def6-get-all:
+
+The ``remote-option-def4-get-all``, ``remote-option-def6-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch all DHCP option definitions from the database
+for the given server or all servers. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option-def6-get-all",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+This command attempts to fetch all DHCPv6 option definitions associated
+with "all" servers. The ``server-tags`` list is mandatory for
+this command and must include exactly one server tag or the keyword "all".
+It cannot include the ``null`` value.
+
+The following is the example response to this command:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 DHCPv6 option definition(s) found.",
+ "arguments": {
+ "option-defs": [
+ {
+ "name": "bar",
+ "code": 1012,
+ "space": "dhcp6",
+ "type": "record",
+ "array": true,
+ "record-types": "ipv6-address, uint16",
+ "encapsulate": "",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+The response contains an option definition associated with all servers, as
+indicated by the metadata.
+
+.. isccmd:: remote-option-def4-set
+.. _command-remote-option-def4-set:
+
+.. isccmd:: remote-option-def6-set
+.. _command-remote-option-def6-set:
+
+The ``remote-option-def4-set``, ``remote-option-def6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new DHCP option definition or replace an
+existing option definition in the database. The structure of the option
+definition information is the same as in the Kea configuration file (see
+:ref:`dhcp4-custom-options` and :ref:`dhcp6-custom-options`).
+The following command creates the DHCPv4 option definition at the
+top-level "dhcp4" option space and associates it with "server1":
+
+.. code-block:: json
+
+ {
+ "command": "remote-option-def4-set",
+ "arguments": {
+ "option-defs": [
+ {
+ "name": "foo",
+ "code": 222,
+ "type": "uint32",
+ "array": false,
+ "record-types": "",
+ "space": "dhcp4",
+ "encapsulate": ""
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The ``server-tags`` list must include exactly one
+server tag or the keyword "all", and cannot contain the
+``null`` value.
+
+.. isccmd:: remote-option4-global-del
+.. _command-remote-option4-global-del:
+
+.. isccmd:: remote-option6-global-del
+.. _command-remote-option6-global-del:
+
+The ``remote-option4-global-del``, ``remote-option6-global-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete a global DHCP option from the
+database. The option is identified by an option code and option space.
+For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option4-global-del",
+ "arguments": {
+ "options": [
+ {
+ "code": 5,
+ "space": "dhcp4"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The "dhcp4" value represents the top-level option space where the standard DHCPv4
+options belong. The ``server-tags`` parameter is mandatory and must include a
+single option tag or the keyword "all". If the explicit server tag is specified,
+this command attempts to delete a global option associated with this
+server. If there is no such option associated with the given server, no option
+is deleted. To delete an option associated with all servers, the
+keyword "all" must be specified.
+
+.. isccmd:: remote-option4-global-get
+.. _command-remote-option4-global-get:
+
+.. isccmd:: remote-option6-global-get
+.. _command-remote-option6-global-get:
+
+The ``remote-option4-global-get``, ``remote-option6-global-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch a global DHCP option from the database.
+The option is identified by the code and option space. The top-level
+option spaces where DHCP standard options belong are called "dhcp4" and
+"dhcp6" for the DHCPv4 and DHCPv6 servers, respectively.
+
+The following command retrieves the IPv6 "DNS Servers" (code 23) option
+associated with all servers:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-global-get",
+ "arguments": {
+ "options": [
+ {
+ "code": 23,
+ "space": "dhcp6"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+The ``server-tags`` parameter is mandatory and must include exactly one
+server tag or the keyword "all". It cannot contain the ``null``
+value.
+
+.. isccmd:: remote-option4-global-get-all
+.. _command-remote-option4-global-get-all:
+
+.. isccmd:: remote-option6-global-get-all
+.. _command-remote-option6-global-get-all:
+
+The ``remote-option4-global-get-all``, ``remote-option6-global-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to fetch all global DHCP options from the configuration
+database for the given server or for all servers. The following command
+fetches all global DHCPv4 options for "server1":
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-global-get-all",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The ``server-tags`` list is mandatory for this command and
+must contain exactly one server tag or a keyword "all"; it cannot contain
+the ``null`` value.
+
+The following is a example response to this
+command with a single option being associated with "server1" returned:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCPv4 options found.",
+ "arguments": {
+ "options": [
+ {
+ "name": "domain-name-servers",
+ "code": 6,
+ "space": "dhcp4",
+ "csv-format": false,
+ "data": "192.0.2.3",
+ "metadata": {
+ "server-tags": [ "server1" ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+.. isccmd:: remote-option4-global-set
+.. _command-remote-option4-global-set:
+
+.. isccmd:: remote-option6-global-set
+.. _command-remote-option6-global-set:
+
+The ``remote-option4-global-set``, ``remote-option6-global-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new global DHCP option or replace an existing
+option in the database. The structure of the option information is the
+same as in the Kea configuration file (see :ref:`dhcp4-std-options`
+and :ref:`dhcp6-std-options`). For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-global-set",
+ "arguments": {
+ "options": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The ``server-tags`` list is mandatory for this command
+and must include exactly one server tag or the keyword "all"; it cannot
+include the ``null`` value. The command above associates
+the option with the "server1" server.
+
+Note that specifying an option name instead of the option code only
+works reliably for standard DHCP options. When specifying a value
+for a user-defined DHCP option, the option code should be indicated
+instead of the name. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-global-set",
+ "arguments": {
+ "options": [
+ {
+ "code": 1,
+ "space": "isc",
+ "data": "2001:db8:1::1"
+ }
+ ],
+ "server-tags": [ "server1" ]
+ }
+ }
+
+.. isccmd:: remote-option4-network-del
+.. _command-remote-option4-network-del:
+
+.. isccmd:: remote-option6-network-del
+.. _command-remote-option6-network-del:
+
+The ``remote-option4-network-del``, ``remote-option6-network-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete a shared-network-specific DHCP
+option from the database. The option is identified by an option code
+and option space and these two parameters are passed within the
+``options`` list. Another list, ``shared-networks``, contains a map
+with the name of the shared network from which the option is to
+be deleted. If the option is not explicitly specified for this
+shared network, no option is deleted. In particular, the given
+option may be present for a subnet belonging to the shared network.
+Such an option instance is not affected by this command as this
+command merely deletes the shared-network level option. To
+delete a subnet-level option, the :isccmd:`remote-option4-subnet-del`,
+:isccmd:`remote-option6-subnet-del` commands must be used instead.
+
+The following command attempts to delete an option having the
+option code 5 in the top-level option space from the shared
+network "fancy".
+
+.. code-block:: json
+
+ {
+ "command": "remote-option4-network-del",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "fancy"
+ }
+ ],
+ "options": [
+ {
+ "code": 5,
+ "space": "dhcp4"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The "dhcp4" value represents the top-level option space where the standard DHCPv4
+options belong. The ``server-tags`` parameter cannot be specified for this command.
+
+.. isccmd:: remote-option4-network-set
+.. _command-remote-option4-network-set:
+
+.. isccmd:: remote-option6-network-set
+.. _command-remote-option6-network-set:
+
+The ``remote-option4-network-set``, ``remote-option6-network-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new shared-network-specific DHCP option or replace
+an existing option in the database. The structure of the option information
+is the same as in the Kea configuration file (see :ref:`dhcp4-std-options`
+and :ref:`dhcp6-std-options`). The option information is carried in the
+``options`` list. Another list, ``shared-networks``, contains a map with the
+name of the shared network for which the option is to be set. If such an option
+already exists for the shared network, it is replaced with the new instance.
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-network-set",
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "fancy"
+ }
+ ],
+ "options": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be specified for this command.
+
+Specifying an option name instead of the option code only works reliably
+for standard DHCP options. When specifying a value for a user-defined
+DHCP option, the option code should be indicated instead of the name.
+
+.. isccmd:: remote-option6-pd-pool-del
+.. _command-remote-option6-pd-pool-del:
+
+The ``remote-option6-pd-pool-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to delete a prefix delegation pool-specific DHCPv6
+option from the database. The option is identified by an option code
+and option space, and these two parameters are passed within the
+``options`` list. Another list, ``pd-pools``, contains a map with the
+prefix-delegation-pool prefix and length identifying the pool. If the
+option is not explicitly specified for this pool, no option is deleted.
+In particular, the given option may exist for a subnet containing
+the specified pool. Such an option instance is not affected by this
+command, as this command merely deletes a prefix delegation pool-level
+option. To delete a subnet level option, the
+:isccmd:`remote-option6-subnet-del` command must be used instead.
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-pd-pool-del",
+ "arguments": {
+ "pd-pools": [
+ {
+ "prefix": "3000::",
+ "prefix-len": 64
+ }
+ ],
+ "options": [
+ {
+ "code": 23,
+ "space": "dhcp6"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The "dhcp6" value represents the top-level option space where the standard DHCPv6
+options belong. The ``server-tags`` parameter cannot be specified for this command.
+
+.. isccmd:: remote-option6-pd-pool-set
+.. _command-remote-option6-pd-pool-set:
+
+The ``remote-option6-pd-pool-set`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command creates a new prefix delegation pool-specific DHCPv6 option or
+replaces an existing option in the database. The structure of the option
+information is the same as in the Kea configuration file (see :ref:`dhcp4-std-options`
+and :ref:`dhcp6-std-options`). The option information is carried in the
+``options`` list. Another list, ``pd-pools``, contains a map with the
+prefix-delegation-pool prefix and the prefix length identifying the pool. If such an
+option already exists for the prefix delegation pool, it is replaced with
+the new instance.
+
+For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-pd-pool-set",
+ "arguments": {
+ "pd-pools": [
+ {
+ "prefix": "3001:1::",
+ "length": 64
+ }
+ ],
+ "options": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be specified for this command.
+
+Specifying an option name instead of the option code only works reliably
+for standard DHCP options. When specifying a value for a user-defined
+DHCP option, the option code should be indicated instead of the name.
+
+.. isccmd:: remote-option4-pool-del
+.. _command-remote-option4-pool-del:
+
+.. isccmd:: remote-option6-pool-del
+.. _command-remote-option6-pool-del:
+
+The ``remote-option4-pool-del``, ``remote-option6-pool-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete an address-pool-specific DHCP
+option from the database. The option is identified by an option code
+and option space, and these two parameters are passed within the
+``options`` list. Another list, ``pools``, contains a map with the
+IP address range or prefix identifying the pool. If the option
+is not explicitly specified for this pool, no option is deleted.
+In particular, the given option may exist for a subnet containing
+the specified pool. Such an option instance is not affected by this
+command, as this command merely deletes a pool-level option. To
+delete a subnet-level option, the :isccmd:`remote-option4-subnet-del`,
+:isccmd:`remote-option6-subnet-del` commands must be used instead.
+
+The following command attempts to delete an option having the
+option code 5 in the top-level option space from an IPv4 address
+pool:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option4-pool-del",
+ "arguments": {
+ "pools": [
+ {
+ "pool": "192.0.2.10 - 192.0.2.100"
+ }
+ ],
+ "options": [
+ {
+ "code": 5,
+ "space": "dhcp4"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The "dhcp4" value represents the top-level option space where the standard DHCPv4
+options belong. The ``server-tags`` parameter cannot be specified for this command.
+
+.. isccmd:: remote-option4-pool-set
+.. _command-remote-option4-pool-set:
+
+.. isccmd:: remote-option6-pool-set
+.. _command-remote-option6-pool-set:
+
+The ``remote-option4-pool-set``, ``remote-option6-pool-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new address-pool-specific DHCP option or replace
+an existing option in the database. The structure of the option information
+is the same as in the Kea configuration file (see :ref:`dhcp4-std-options`
+and :ref:`dhcp6-std-options`). The option information is carried in the
+``options`` list. Another list, ``pools``, contains a map with the IP address
+range or prefix identifying the pool. If such an option already exists for
+the pool, it is replaced with the new instance.
+
+For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-option4-pool-set",
+ "arguments": {
+ "pools": [
+ {
+ "pool": "192.0.2.10 - 192.0.2.100"
+ }
+ ],
+ "options": [
+ {
+ "name": "domain-name-servers",
+ "data": "10.0.0.1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be specified for this command.
+
+Specifying an option name instead of the option code only works reliably
+for standard DHCP options. When specifying a value for a user-defined
+DHCP option, the option code should be indicated instead of the name.
+
+.. isccmd:: remote-option4-subnet-del
+.. _command-remote-option4-subnet-del:
+
+.. isccmd:: remote-option6-subnet-del
+.. _command-remote-option6-subnet-del:
+
+The ``remote-option4-subnet-del``, ``remote-option6-subnet-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete a subnet-specific DHCP option
+from the database. The option is identified by an option code
+and option space, and these two parameters are passed within the
+``options`` list. Another list, ``subnets``, contains a map with the
+identifier of the subnet from which the option is to be deleted.
+If the option is not explicitly specified for this subnet, no
+option is deleted.
+
+The following command attempts to delete an option having the
+option code 5 in the top-level option space from the subnet
+having an identifier of 123.
+
+.. code-block:: json
+
+ {
+ "command": "remote-option4-subnet-del",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 123
+ }
+ ],
+ "options": [
+ {
+ "code": 5,
+ "space": "dhcp4"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The "dhcp4" value represents the top-level option space where the standard DHCPv4
+options belong. The ``server-tags`` parameter cannot be specified for this command.
+
+.. isccmd:: remote-option4-subnet-set
+.. _command-remote-option4-subnet-set:
+
+.. isccmd:: remote-option6-subnet-set
+.. _command-remote-option6-subnet-set:
+
+The ``remote-option4-subnet-set``, ``remote-option6-subnet-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands create a new subnet-specific DHCP option or replace an existing
+option in the database. The structure of the option information is the same as
+in the Kea configuration file (see :ref:`dhcp4-std-options`
+and :ref:`dhcp6-std-options`). The option information is carried in the
+``options`` list. Another list, ``subnets``, contains a map with the identifier of
+the subnet for which the option is to be set. If such an option already exists
+for the subnet, it is replaced with the new instance.
+
+.. code-block:: json
+
+ {
+ "command": "remote-option6-subnet-set",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 123
+ }
+ ],
+ "options": [
+ {
+ "name": "dns-servers",
+ "data": "2001:db8:1::1"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be specified for this command.
+
+Specifying an option name instead of the option code only works reliably
+for the standard DHCP options. When specifying a value for the user-defined
+DHCP option, the option code should be indicated instead of the name.
+
+.. isccmd:: remote-subnet4-del-by-id
+.. _command-remote-subnet4-del-by-id:
+
+.. isccmd:: remote-subnet6-del-by-id
+.. _command-remote-subnet6-del-by-id:
+
+The ``remote-subnet4-del-by-id``, ``remote-subnet6-del-by-id`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the first variant of the commands used to delete an IPv4 or IPv6
+subnet from the database. It uses the subnet ID to identify the subnet. For
+example, to delete the IPv4 subnet with an ID of 5:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-del-by-id",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 5
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used with this command.
+
+.. isccmd:: remote-subnet4-del-by-prefix
+.. _command-remote-subnet4-del-by-prefix:
+
+.. isccmd:: remote-subnet6-del-by-prefix
+.. _command-remote-subnet6-del-by-prefix:
+
+The ``remote-subnet4-del-by-prefix``, ``remote-subnet6-del-by-prefix`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the second variant of the commands used to delete an IPv4 or
+IPv6 subnet from the database. It uses the subnet prefix to identify the
+subnet. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet6-del-by-prefix",
+ "arguments": {
+ "subnets": [
+ {
+ "subnet": "2001:db8:1::/64"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used with this command.
+
+.. isccmd:: remote-subnet4-get-by-id
+.. _command-remote-subnet4-get-by-id:
+
+.. isccmd:: remote-subnet6-get-by-id
+.. _command-remote-subnet6-get-by-id:
+
+The ``remote-subnet4-get-by-id``, ``remote-subnet6-get-by-id`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the first variant of the commands used to fetch an IPv4 or IPv6
+subnet from the database. It uses a subnet ID to identify the subnet.
+For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-get-by-id",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 5
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used with this command.
+
+.. isccmd:: remote-subnet4-get-by-prefix
+.. _command-remote-subnet4-get-by-prefix:
+
+.. isccmd:: remote-subnet6-get-by-prefix
+.. _command-remote-subnet6-get-by-prefix:
+
+The ``remote-subnet4-get-by-prefix``, ``remote-subnet6-get-by-prefix`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the second variant of the commands used to fetch an IPv4 or IPv6
+subnet from the database. It uses a subnet prefix to identify the
+subnet. For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet6-get-by-prefix",
+ "arguments": {
+ "subnets": [
+ {
+ "subnet": "2001:db8:1::/64"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used with this command.
+
+.. isccmd:: remote-subnet4-list
+.. _command-remote-subnet4-list:
+
+.. isccmd:: remote-subnet6-list
+.. _command-remote-subnet6-list:
+
+The ``remote-subnet4-list``, ``remote-subnet6-list`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to list all IPv4 or IPv6 subnets from the database for
+selected servers or all servers. The following command retrieves all servers to
+be used by "server1" and "server2":
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-list",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1", "server2" ]
+ }
+ }
+
+The ``server-tags`` parameter is mandatory and contains one or
+more server tags. It may contain the keyword "all", to fetch the subnets
+associated with all servers. When the ``server-tags`` list
+contains the ``null`` value, the returned response contains a list
+of unassigned subnets, i.e. the subnets which are associated with no servers.
+For example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-list",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ null ]
+ }
+ }
+
+The example response to this command when non-null server tags are specified
+looks similar to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "2 IPv4 subnet(s) found.",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "shared-network-name": null,
+ "metadata": {
+ "server-tags": [ "server1", "server2" ]
+ }
+ },
+ {
+ "id": 2,
+ "subnet": "192.0.3.0/24",
+ "shared-network-name": null,
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 2
+ }
+ }
+
+The returned information about each subnet is limited to the subnet identifier,
+prefix, and associated shared network name. To retrieve full
+information about the selected subnet, use
+the :isccmd:`remote-subnet4-get-by-id`, :isccmd:`remote-subnet6-get-by-id` commands
+or the :isccmd:`remote-subnet4-get-by-prefix`, :isccmd:`remote-subnet6-get-by-prefix` commands.
+
+The example response above contains two subnets. One of the subnets is
+associated with both servers: "server1" and "server2". The second subnet is
+associated with all servers, so it is also present in the configurations for
+"server1" and "server2".
+
+When listing unassigned subnets, the response will look similar to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "1 IPv4 subnet(s) found.",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 3,
+ "subnet": "192.0.4.0/24",
+ "shared-network-name": null,
+ "metadata": {
+ "server-tags": [ null ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+The ``null`` value in the metadata indicates that the
+returned subnet is unassigned.
+
+.. isccmd:: remote-subnet4-set
+.. _command-remote-subnet4-set:
+
+.. isccmd:: remote-subnet6-set
+.. _command-remote-subnet6-set:
+
+The ``remote-subnet4-set``, ``remote-subnet6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to create a new IPv4 or IPv6 subnet or replace
+an existing subnet in the database. Setting the subnet also associates
+or disassociates the subnet with a shared network.
+
+The structure of the subnet information is similar to the structure used
+in the configuration file (see :ref:`dhcp4-configuration` and
+:ref:`dhcp6-configuration`). The subnet information conveyed in the
+:isccmd:`remote-subnet4-set`, :isccmd:`remote-subnet6-set` commands
+must include the additional parameter
+``shared-network-name``, which denotes whether the subnet belongs to a
+shared network.
+
+Consider the following example:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-set",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 5,
+ "subnet": "192.0.2.0/24",
+ "shared-network-name": "level3",
+ "pools": [ { "pool": "192.0.2.100-192.0.2.200" } ],
+ "option-data": [ {
+ "name": "routers",
+ "data": "192.0.2.1"
+ } ]
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+It creates the subnet and associates it with the "level3" shared
+network. The "level3" shared network must be created with the :isccmd:`remote-network4-set`
+command prior to creating the subnet.
+
+If the created subnet must be global - that is, not associated with any shared
+network - the ``shared-network-name`` must be explicitly set to
+``null``:
+
+.. code-block:: json
+
+ {
+ "command": "remote-subnet4-set",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 5,
+ "subnet": "192.0.2.0/24",
+ "shared-network-name": null,
+ "pools": [ { "pool": "192.0.2.100-192.0.2.200" } ],
+ "option-data": [ {
+ "name": "routers",
+ "data": "192.0.2.1"
+ } ]
+ }
+ ],
+ "server-tags": [ "all" ]
+ }
+ }
+
+The subnet created in the previous example is replaced with the new
+subnet having the same parameters, but it becomes global.
+
+The ``shared-network-name`` parameter is mandatory for the
+:isccmd:`remote-subnet4-set` command. The ``server-tags`` list is mandatory and must
+include one or more server tags. As a result, the subnet is associated with all
+of the listed servers. It may also be associated with all servers connecting
+to the database when the keyword "all" is used as the server tag.
+
+.. note::
+
+ As with other "set" commands, this command replaces all the
+ information about the particular subnet in the database, if the
+ subnet information is already present. Therefore, when sending this
+ command, make sure to always include all parameters that must be
+ specified for the updated subnet instance. Any unspecified parameter
+ will be marked as unspecified in the database, even if its value was
+ present prior to sending the command.
+
+.. isccmd:: remote-class4-del
+.. _command-remote-class4-del:
+
+.. isccmd:: remote-class6-del
+.. _command-remote-class6-del:
+
+The ``remote-class4-del``, ``remote-class6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands delete a DHCPv4 or DHCPv6 client class by name. If any client
+classes in the database depend on the deleted class, an error is returned in
+response to this command. In this case, to successfully delete the class,
+the dependent client classes must be deleted first. Use the
+:isccmd:`remote-class4-get-all` command to fetch all client classes and find
+the dependent ones.
+
+.. code-block:: json
+
+ {
+ "command": "remote-class4-del",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "foo"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used for this command because client
+classes are uniquely identified by name.
+
+.. isccmd:: remote-class4-get
+.. _command-remote-class4-get:
+
+.. isccmd:: remote-class6-get
+.. _command-remote-class6-get:
+
+The ``remote-class4-get``, ``remote-class6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands retrieve DHCPv4 or DHCPv6 client class information by a
+client-class name.
+
+.. code-block:: json
+
+ {
+ "command": "remote-class4-get",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "foo"
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ }
+ }
+ }
+
+The ``server-tags`` parameter cannot be used for this command because client
+classes are uniquely identified by name.
+
+A response to the command looks similar to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "DHCPv4 client class 'foo' found.",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "foo",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 1
+ }
+ }
+
+.. isccmd:: remote-class4-get-all
+.. _command-remote-class4-get-all:
+
+.. isccmd:: remote-class6-get-all
+.. _command-remote-class6-get-all:
+
+The ``remote-class4-get-all``, ``remote-class6-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands retrieve all DHCPv4 or DHCPv6 client classes for a particular server,
+multiple explicitly listed servers, and/or all servers. A given server has its own
+server-specific tag and also has the "all" server tag; these commands retrieve
+the classes for both an individual server and for "all" servers. For example, the
+following command retrieves all client classes defined for "server1" as well as
+the client classes defined for "all" servers:
+
+.. code-block:: json
+
+ {
+ "command": "remote-class4-get-all",
+ "arguments": {
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "server1" ]
+ }
+ }
+
+The ``server-tags`` parameter is mandatory and contains one or more server
+tags. If other server tags are specified, "all" does not need to be included
+in ``server-tags``, as every server automatically also has the "all" server tag.
+If ``server-tags`` contains only the keyword "all", only the client classes associated
+with "all" servers are returned. When the ``server-tags`` list contains the
+``null`` value, the returned response contains a list of unassigned client
+classes, i.e. the networks which are associated with no servers.
+
+A response to the command looks similar to this:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "2 DHCPv4 client class(es) found.",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "foo",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ },
+ {
+ "name": "bar",
+ "test": "member('foo')",
+ "metadata": {
+ "server-tags": [ "all" ]
+ }
+ }
+ ],
+ "count": 2
+ }
+ }
+
+.. isccmd:: remote-class4-set
+.. _command-remote-class4-set:
+
+.. isccmd:: remote-class6-set
+.. _command-remote-class6-set:
+
+The ``remote-class4-set``, ``remote-class6-set`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands insert a new or replace an existing DHCPv4 or DHCPv6 client class in
+the database. The client class information structure is the same as in the Kea
+configuration file (see :ref:`dhcp4-client-classifier` and
+:ref:`dhcp6-client-classifier` for details).
+
+.. code-block:: json
+
+ {
+ "command": "remote-class4-set",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "foo",
+ "test": "member('KNOWN') or member('bar')",
+ "option-def": [
+ {
+ "name": "configfile",
+ "code": 224,
+ "type": "string"
+ }
+ ],
+ "option-data": [
+ {
+ "name": "configfile",
+ "data": "1APC"
+ }
+ ]
+ }
+ ],
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+
+Client-class ordering rules described in :ref:`classification-using-expressions`
+apply to the classes inserted into the database. They imply that the class `bar`
+referenced in the test expression must exist in the database when issuing the
+above command.
+
+By default, a new client class is inserted at the end of the class hierarchy in
+the database and can reference any class associated with the same server tag or
+with the special server tag "all". If an existing class is updated, it remains
+at its current position within the class hierarchy.
+
+However, the class commands allow the position of the inserted
+or updated client class to be specified. The optional ``follow-class-name`` parameter can be
+included in the command to indicate the name of the existing class after which
+the managed class should be placed. Suppose there are two DHCPv6 classes in the
+database: `first-class` and `second-class`. To add a new class, `third-class`,
+between these two, use a command similar to the following:
+
+.. code-block:: json
+
+ {
+ "command": "remote-class6-set",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "third-class",
+ "test": "member('first-class')"
+ }
+ ],
+ "follow-class-name": "first-class",
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+Note that `third-class` can depend on `first-class` because it is placed
+after `first-class`; `third-class` cannot depend on `second-class`
+because it is placed before it. However, `second-class` could be updated to
+depend on `third-class`.
+
+The ``follow-class-name`` parameter can be explicitly set to ``null``, e.g.:
+
+.. code-block:: json
+
+ {
+ "command": "remote-class6-set",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "third-class",
+ "test": "member('first-class')"
+ }
+ ],
+ "follow-class-name": null,
+ "remote": {
+ "type": "mysql"
+ },
+ "server-tags": [ "all" ]
+ }
+ }
+
+It yields the same behavior as if the ``follow-class-name`` parameter were not included,
+i.e. the new class is appended at the end of the class hierarchy, and the updated
+class remains at the current position.
diff --git a/doc/sphinx/arm/hooks-cb-mysql.rst b/doc/sphinx/arm/hooks-cb-mysql.rst
new file mode 100644
index 0000000..8e5ab42
--- /dev/null
+++ b/doc/sphinx/arm/hooks-cb-mysql.rst
@@ -0,0 +1,18 @@
+.. ischooklib:: libdhcp_mysql_cb.so
+.. _hooks-cb-mysql:
+
+``libdhcp_mysql_cb.so``: Configuration Backend for MySQL
+========================================================
+
+This hook library works in conjunction with :ischooklib:`libdhcp_cb_cmds.so` to
+implement the API to create, read, update, and delete (CRUD) the
+configuration in a MySQL database. Please see :ref:`hooks-cb-cmds`
+for more details.
+
+.. note::
+
+ :ischooklib:`libdhcp_mysql_cb.so` is part of the open source code and is
+ available to every Kea user, but it requires :ischooklib:`libdhcp_cb_cmds.so`
+ which is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
diff --git a/doc/sphinx/arm/hooks-cb-pgsql.rst b/doc/sphinx/arm/hooks-cb-pgsql.rst
new file mode 100644
index 0000000..c652693
--- /dev/null
+++ b/doc/sphinx/arm/hooks-cb-pgsql.rst
@@ -0,0 +1,18 @@
+.. ischooklib:: libdhcp_pgsql_cb.so
+.. _hooks-cb-pgsql:
+
+``libdhcp_pgsql_cb.so``: Configuration Backend for PostgreSQL
+=============================================================
+
+This hook library works in conjunction with :ischooklib:`libdhcp_cb_cmds.so` to
+implement the API to create, read, update, and delete (CRUD) the
+configuration in a PostgreSQL database. Please see :ref:`hooks-cb-cmds`
+for more details.
+
+.. note::
+
+ :ischooklib:`libdhcp_pgsql_cb.so` is part of the open source code and is
+ available to every Kea user, but it requires :ischooklib:`libdhcp_cb_cmds.so`
+ which is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
diff --git a/doc/sphinx/arm/hooks-class-cmds.rst b/doc/sphinx/arm/hooks-class-cmds.rst
new file mode 100644
index 0000000..5a55cc5
--- /dev/null
+++ b/doc/sphinx/arm/hooks-class-cmds.rst
@@ -0,0 +1,255 @@
+.. ischooklib:: libdhcp_class_cmds.so
+.. _hooks-class-cmds:
+
+``libdhcp_class_cmds.so``: Class Commands
+=========================================
+
+This hook library exposes
+several control commands for manipulating client classes (part of the
+Kea DHCP servers' configurations) without the need to restart those
+servers. Using these commands it is possible to add, update, delete, and
+list the client classes configured for a given server.
+
+.. note::
+
+ :ischooklib:`libdhcp_class_cmds.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or
+ :iscman:`kea-dhcp6` process.
+
+.. isccmd:: class-add
+.. _command-class-add:
+
+The ``class-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`class-add` command adds a new client class to the DHCP server
+configuration. This class is appended at the end of the list of classes
+used by the server and may depend on any of the already-configured
+client classes.
+
+The following example demonstrates how to add a new client class to the
+DHCPv4 server configuration:
+
+::
+
+ {
+ "command": "class-add",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "ipxe_efi_x64",
+ "test": "option[93].hex == 0x0009",
+ "next-server": "192.0.2.254",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null"
+ }
+ ]
+ }
+ }
+
+Note that the ``client-classes`` parameter is a JSON list, but it allows
+only a single client class to be present.
+
+Here is the response to the :isccmd:`class-add` command in our example:
+
+::
+
+ {
+ "result": 0,
+ "text": "Class 'ipxe_efi_x64' added."
+ }
+
+.. isccmd:: class-update
+.. _command-class-update:
+
+The ``class-update`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`class-update` command updates an existing client class in the
+DHCP server configuration. If the client class with the given name
+does not exist, the server returns the result code of 3, which means that
+the server configuration is not modified and the client class does not
+exist. The :isccmd:`class-add` command must be used instead to create the new
+client class.
+
+The :isccmd:`class-update` command has the same argument structure as the
+:isccmd:`class-add` command:
+
+::
+
+ {
+ "command": "class-update",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "ipxe_efi_x64",
+ "test": "option[93].hex == 0x0017",
+ "next-server": "0.0.0.0",
+ "server-hostname": "xfce",
+ "boot-file-name": "/dev/null"
+ }
+ ]
+ }
+ }
+
+Here is the response for our example:
+
+::
+
+ {
+ "result": 0,
+ "text": "Class 'ipxe_efi_x64' updated."
+ }
+
+Any parameter of the client class can be modified with this command,
+except ``name``. There is currently no way to rename the class, because
+the class name is used as a key for searching the class to be updated.
+To achieve a similar effect to renaming the class, an existing class can
+be removed with the :isccmd:`class-del` command and then added again with a
+different name using :isccmd:`class-add`. Note, however, that the class with
+the new name will be added at the end of the list of configured classes.
+
+As with other update commands, this command overwrites all the contents of the
+entry. If the client class previously had a resource assigned to it, and the
+:isccmd:`class-update` command is missing the resource, it is deleted from the server
+configuration. If an incremental update of the class is desired, then this can
+be achieved by doing a :isccmd:`class-get` to get the current state
+of the client class, picking the client class out of the response, modifying it
+to the required outcome, and then issuing the ``client-update`` command with the
+resulting client class attached.
+
+.. isccmd:: class-del
+.. _command-class-del:
+
+The ``class-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+The :isccmd:`class-del` command is used to remove a particular class from the server
+configuration. The class to be removed is identified by name. The class
+is not removed if there are other classes depending on it; to remove
+such a class, the dependent classes must be removed first.
+
+The following is a sample command removing the ``ipxe_efi_x64`` class:
+
+::
+
+ {
+ "command": "class-del",
+ "arguments": {
+ "name": "ipxe_efi_x64"
+ }
+ }
+
+Here is the response to the :isccmd:`class-del` command in our example, when
+the specified client class has been found:
+
+::
+
+ {
+ "result": 0,
+ "text": "Class 'ipxe_efi_x64' deleted."
+ }
+
+If the class does not exist, the result of 3 is returned.
+
+.. isccmd:: class-list
+.. _command-class-list:
+
+The ``class-list`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+:isccmd:`class-list` is used to retrieve a list of all client classes. This
+command includes no arguments:
+
+::
+
+ {
+ "command": "class-list"
+ }
+
+Here is the response of the server in our example, including the list of
+client classes:
+
+::
+
+ {
+ "result": 0,
+ "text": "2 classes found",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "ipxe_efi_x64"
+ },
+ {
+ "name": "pxeclient"
+ }
+ ]
+ }
+ }
+
+Note that the returned list does not contain full class definitions, but
+merely class names. To retrieve full class information, the
+:isccmd:`class-get` command should be used.
+
+.. isccmd:: class-get
+.. _command-class-get:
+
+The ``class-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`class-get` is used to retrieve detailed information about a specified
+class. The command structure is very simple:
+
+::
+
+ {
+ "command": "class-get",
+ "arguments": {
+ "name": "pxeclient"
+ }
+ }
+
+If the class with the specified name does not exist, the status code of
+3 is returned. If the specified client class exists, the class details
+are returned in the following format:
+
+::
+
+ {
+ "result": 0,
+ "text": "Class 'pxeclient' definition returned",
+ "arguments": {
+ "client-classes": [
+ {
+ "name": "pxeclient",
+ "only-if-required": true,
+ "test": "option[vendor-class-identifier].text == 'PXEClient'",
+ "option-def": [
+ {
+ "name": "configfile",
+ "code": 209,
+ "type": "string"
+ }
+ ],
+ "option-data": [ ],
+ "next-server": "0.0.0.0",
+ "server-hostname": "xfce",
+ "boot-file-name": "/dev/null"
+ }
+ ]
+ }
+ }
+
+Note that the example above is DHCPv4-specific; the last three
+parameters are only returned by the DHCPv4 server and are never returned
+by the DHCPv6 server. Also, some of the parameters provided in this
+example may not be returned if they are not specified for the class.
+Specifically, ``only-if-required``, ``test``, and ``option-def`` are not
+returned if they are not specified for the class.
diff --git a/doc/sphinx/arm/hooks-ddns-tuning.rst b/doc/sphinx/arm/hooks-ddns-tuning.rst
new file mode 100644
index 0000000..72b2a49
--- /dev/null
+++ b/doc/sphinx/arm/hooks-ddns-tuning.rst
@@ -0,0 +1,217 @@
+.. ischooklib:: libdhcp_ddns_tuning.so
+.. _hooks-ddns-tuning:
+
+``libdhcp_ddns_tuning.so``: DDNS Tuning
+=======================================
+
+This hook library adds support for fine-tuning various DNS update aspects.
+It currently supports procedural host-name generation and the ability to skip
+performing DDNS updates for select clients.
+
+.. note::
+
+ :ischooklib:`libdhcp_ddns_tuning.so` is available as a premium
+ hook library from ISC. Please visit https://www.isc.org/shop/ to purchase
+ the premium hook libraries, or contact us at https://www.isc.org/contact for
+ more information.
+
+The library, which was added in Kea 2.1.5, can be loaded by the :iscman:`kea-dhcp4`
+and :iscman:`kea-dhcp6` daemons by adding it to the ``hooks-libraries`` element of the
+server's configuration:
+
+.. code-block:: javascript
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_ddns_tuning.so",
+ "parameters": {
+ ...
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+Procedural Host-Name Generation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This hook library provides the ability to generate host names procedurally, based on
+an expression. The expression can be defined globally in the hook parameters, using
+`hostname-expr`. If defined globally, it applies to all hosts in all subnets. The
+expressions can use all tokens defined in :ref:`classify`. An example of a global
+expression is shown below:
+
+.. code-block:: javascript
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_ddns_tuning.so",
+ "parameters": {
+ "hostname-expr": "'host-'+hexstring(pkt4.mac,'-')",
+ ...
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+It is also possible to define this parameter in a subnet, using the user-context mechanism.
+If defined at the subnet level, the expression applies to a specific subnet only. If the
+subnet expression is defined as empty, ``""``, it suppresses (or disables) the use of a
+global expression for that subnet. An example subnet expression is shown below:
+
+.. code-block:: javascript
+
+ {
+ "subnet4": [{
+ "subnet": "192.0.2.0/24",
+ "pools": [{
+ "pool": "192.0.2.10 - 192.0.2.20"
+ } ],
+
+ // This is a subnet-specific user context.
+ "user-context": {
+ "ddns-tuning": {
+ "hostname-expr": "'guest-'+int8totext(substring(pkt4.yiaddr, 0,1))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 1,2))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 2,3))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 3,4))"
+ },
+ "last-modified": "2017-09-04 13:32",
+ "description": "you can put anything you like here",
+ "phones": [ "x1234", "x2345" ],
+ "devices-registered": 42,
+ "billing": false
+ }
+ }],
+ ...
+ }
+
+.. note::
+
+ The expression value above uses a backslash, ``\``, to show line continuation. This is for
+ clarity only and is not valid JSON supported by Kea parsing. The actual value must
+ be expressed on a single line.
+
+.. note::
+
+ Privacy should be taken into consideration when generating a host name. The host name
+ is usually inserted into the DNS, which is a public system. Exposing identifiers that
+ can be used to track devices, such as a MAC address, are usually a very bad idea.
+ The global expression example here used a MAC address for simplicity.
+
+DHCPv4 Host-Name Generation
+---------------------------
+
+With this library installed, the behavior for :iscman:`kea-dhcp4` when forming host names in
+response to a client query (e.g. DISCOVER, REQUEST) is as follows:
+
+ 1. If a host name is supplied via a host reservation, use it with the DDNS
+ behavioral parameters to form the final host name. Go to step 4.
+
+ 2. If the client supplied an FQDN option (option 81), use the domain name value
+ specified within it, with the DDNS behavioral parameters, to form the final
+ host name. Go to step 4.
+
+ 3. If the client supplied a host-name option (option 12), use the host name specified
+ within it, with the DDNS behavioral parameters, to form the final host name.
+
+ 4. If there is a ``ddns-tuning`` in-scope host-name expression (either global or subnet),
+ calculate the host name using the expression. If the calculated value is not a fully
+ qualified name and there is an in-scope ``ddns-qualifying-suffix``, append the suffix.
+
+ 5. If the value calculated by the hook is not an empty string and is different than
+ the host name formed in steps 1 or 2, the calculated value becomes the
+ final host name.
+
+DHCPv6 Host-Name Generation
+---------------------------
+
+With this library installed, the behavior for :iscman:`kea-dhcp6` when forming host names in
+response to a client query (e.g. SOLICIT, REQUEST, RENEW, REBIND) is as follows:
+
+ 1. If the client supplied an FQDN option (option 39), use the domain name value
+ specified within it, with the DDNS behavioral parameters, to form the final
+ host name. Go to step 4.
+
+ 2. If the client did not supply an FQDN but ``ddns-replace-client-name`` is either
+ ``always`` or ``when-not-present``, then calculate the final form of the host
+ name and use it to create an outbound FQDN. Go to step 4.
+
+ 3. If there is no outbound FQDN at this point, client-name processing for this
+ packet stops. Without an outbound FQDN there is no way to communicate a host
+ name to the client.
+
+ 4. If a host name is supplied via a host reservation, use it along with the DDNS
+ behavioral parameters to form the final host name; it supersedes the FQDN value
+ calculated in steps 1 or 2.
+
+ 5. If there is a ``ddns-tuning`` in-scope host name expression (either global or subnet),
+ calculate the host name using the expression. If the calculated value is not a fully
+ qualified name and there is an in-scope ``ddns-qualifying-suffix``, append the suffix.
+
+ 6. If the value calculated by the hook is not an empty string and is different than
+ the host name formed in steps 1 or 2, the calculated value becomes the
+ final host name.
+
+
+Skipping DDNS Updates
+~~~~~~~~~~~~~~~~~~~~~
+
+:ischooklib:`libdhcp_ddns_tuning.so` also provides the ability to skip DDNS updates on a
+per-client basis. The library recognizes a special client class, "SKIP_DDNS"; when a
+client is matched to this class, the Kea servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`) do not
+send DDNS update requests (NCRs) to :iscman:`kea-dhcp-ddns`. A common use case would be
+to skip DDNS updates for fixed-address host reservations. This is done easily by
+simply assigning the class to the host reservation as shown below:
+
+.. code-block:: javascript
+
+ {
+ "reservations": [
+ {
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.1",
+ "client-classes": [ "SKIP_DDNS", "foo", "bar" ]
+ }]
+ }
+
+The :ischooklib:`libdhcp_ddns_tuning.so` hook library notes the
+presence of the ``"SKIP_DDNS"`` class in the
+client's class list each time the client requests, renews, or releases its lease,
+and instructs :iscman:`kea-dhcp4` to bypass sending DDNS updates. A similar workflow is
+supported for :iscman:`kea-dhcp6`:
+
+.. code-block:: javascript
+
+ {
+ "reservations": [
+ {
+ "duid": "01:02:03:04:05:06",
+ "ip-address": "2001:db8::1",
+ "client-classes": [ "SKIP_DDNS", "foo", "bar" ]
+ }]
+ }
+
+Although "SKIP_DDNS" is a special class, it can be defined with a test
+expression. Defining it as shown below would omit DDNS updates for all KNOWN
+clients:
+
+.. code-block:: javascript
+
+ {
+ "client-classes":[
+ {
+ "name": "SKIP_DDNS",
+ "test": "member('KNOWN')"
+ }]
+ }
+
+.. note::
+
+ The :ischooklib:`libdhcp_ddns_tuning.so` hook library must be
+ loaded for the ``"SKIP_DDNS"`` class to have an effect.
diff --git a/doc/sphinx/arm/hooks-flex-id.rst b/doc/sphinx/arm/hooks-flex-id.rst
new file mode 100644
index 0000000..d485f0b
--- /dev/null
+++ b/doc/sphinx/arm/hooks-flex-id.rst
@@ -0,0 +1,286 @@
+.. ischooklib:: libdhcp_flex_id.so
+.. _hooks-flex-id:
+
+``libdhcp_flex_id.so``: Flexible Identifier for Host Reservations
+=================================================================
+
+The Kea software provides a way to handle
+host reservations that include addresses, prefixes, options, client
+classes, and other features. The reservation can be based on hardware
+address, DUID, circuit-id, or client-id in DHCPv4 and on hardware
+address or DUID in DHCPv6. However, there are sometimes scenarios where
+the reservation is more complex; it may use options other than those mentioned
+above, use parts of specific options, or perhaps even use a combination of
+several options and fields to uniquely identify a client. Those
+scenarios are addressed by the Flexible Identifiers hook application.
+
+.. note::
+
+ :ischooklib:`libdhcp_flex_id.so` is available as a premium
+ hook library from ISC. Please visit https://www.isc.org/shop/ to purchase
+ the premium hook libraries, or contact us at https://www.isc.org/contact for
+ more information.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6`
+ process.
+
+:ischooklib:`libdhcp_flex_id.so` allows the definition of an expression, using notation initially
+used only for client classification. (See
+:ref:`classification-using-expressions` for a detailed description of
+the syntax available.) One notable difference is that for client
+classification, the expression currently has to evaluate to either ``true``
+or ``false``, while the flexible identifier expression is expected to
+evaluate to a string that will be used as an identifier. It is a valid case
+for the expression to evaluate to an empty string (e.g. in cases where a
+client does not send specific options). This expression is then
+evaluated for each incoming packet, and this evaluation generates an
+identifier that is used to identify the client. In particular, there may
+be host reservations that are tied to specific values of the flexible
+identifier.
+
+The library can be loaded similarly to other hook libraries. It
+takes a mandatory parameter ``identifier-expression`` and some optional boolean
+parameters like ``replace-client-id`` and ``ignore-iaid``:
+
+::
+
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_flex_id.so",
+ "parameters": {
+ "identifier-expression": "expression",
+ "replace-client-id": false,
+ "ignore-iaid": false
+ }
+ },
+ ...
+ ]
+ }
+
+The flexible identifier library supports both DHCPv4 and DHCPv6.
+
+Let's consider a case of an IPv6 network that has an
+independent interface for each of its connected customers. Customers are
+able to plug in whatever device they want, so any type of identifier
+(e.g. a client-id) is unreliable. Therefore, the operator may decide to
+use an option inserted by a relay agent to differentiate between
+clients. In this particular deployment, the operator has verified that the
+interface-id is unique for each customer-facing interface, so it
+is suitable for usage as a reservation. However, only the first six bytes of
+the interface-id are interesting, because the remaining bytes are either
+randomly changed or not unique between devices. Therefore, the customer
+decides to use the first six bytes of the interface-id option inserted by the
+relay agent. After adding ``flex-id``, the ``host-reservation-identifiers`` goal
+can be achieved by using the following configuration:
+
+::
+
+ "Dhcp6": {
+ "subnet6": [{
+ # subnet definition starts here
+ "reservations": [{
+ "flex-id": "'port1234'",
+ # value of the first 8 bytes of the interface-id
+ "ip-addresses": [ "2001:db8::1" ]
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ # end of subnet definitions
+ "host-reservation-identifiers": ["duid", "flex-id"],
+ # add "flex-id" to reservation identifiers
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_flex_id.so",
+ "parameters": {
+ "identifier-expression": "substring(relay6[0].option[18].hex,0,8)"
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+.. note::
+
+ Care should be taken when adjusting the expression. If the expression
+ changes, then all the ``flex-id`` values may change, possibly rendering
+ all reservations based on ``flex-id`` unusable until they are manually updated.
+ It is strongly recommended that administrators start with the expression and a
+ handful of reservations, and then adjust the expression as needed. Once
+ the desired result is obtained with the expression, host reservations
+ can be deployed on a broader scale.
+
+``flex-id`` values in host reservations can be specified in two ways. First,
+they can be expressed as a hex string, e.g. the string "bar" can be represented
+as 626174. Alternatively, it can be expressed as a quoted value (using
+double and single quotes), e.g. "'bar'". The former is more convenient
+for printable characters, while hex string values are more convenient
+for non-printable characters and do not require the use of the
+``hexstring`` operator.
+
+::
+
+ "Dhcp6": {
+ "subnet6": [{
+ # subnet definition starts here
+ "reservations": [{
+ "flex-id": "01:02:03:04:05:06",
+ # value of the first 8 bytes of the interface-id
+ "ip-addresses": [ "2001:db8::1" ]
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ],
+ # end of subnet definitions
+ "host-reservation-identifiers": ["duid", "flex-id"],
+ # add "flex-id" to reservation identifiers
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_flex_id.so",
+ "parameters": {
+ "identifier-expression": "vendor[4491].option[1026].hex"
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+.. note::
+
+ One less common scenario where the examples above may prove useful is for
+ DHCPv6 clients that change their DUIDs between exchanges. Certain PXE
+ clients are known to behave this way.
+
+The ``replace-client-id`` Flag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When ``replace-client-id`` is set to ``false`` (which is the default setting),
+:ischooklib:`libdhcp_flex_id.so` uses the evaluated flexible identifier solely for
+identifying host reservations, i.e. searching for reservations within a
+database. This is the functional equivalent of other identifiers, similar
+to hardware address or circuit-id. However, this mode of operation
+implies that if a client device is replaced, it may cause a
+conflict between an existing lease (allocated to the old device) and the
+new lease being allocated to the new device. The conflict arises
+because the same flexible identifier is computed for the replaced device,
+so the server will try to allocate the same lease. The mismatch between
+client identifiers sent by the new device and the old device causes the server
+to refuse this new allocation until the old lease expires. A
+manifestation of this problem is dependent on the specific expression used
+as the flexible identifier, and is likely to appear if only options
+and other parameters are used that identify where the device is connected
+(e.g. circuit-id), rather than the device identification itself (e.g.
+MAC address).
+
+:ischooklib:`libdhcp_flex_id.so` offers a way to overcome the problem with lease
+conflicts by dynamically replacing the client identifier (or DUID in DHCPv6)
+with a value derived from the flexible identifier. The server
+processes the client's query as if the flexible identifier were sent in the
+client identifier (or DUID) option. This guarantees that a returning
+client (for which the same flexible identifier is evaluated) will be
+assigned the same lease, despite the client identifier and/or MAC address
+change.
+
+The following is a stub configuration that enables this behavior:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_flex_id.so",
+ "parameters": {
+ "identifier-expression": "expression",
+ "replace-client-id": true
+ }
+ },
+ ...
+ ]
+ }
+
+In the DHCPv4 case, the value derived from the flexible identifier is
+formed by prepending one byte with a value of zero to the flexible identifier.
+In the DHCPv6 case, it is formed by prepending two zero bytes before the
+flexible identifier.
+
+Note that for this mechanism to take effect, the DHCPv4 server must be
+configured to respect the client identifier option value during lease
+allocation, i.e. ``match-client-id`` must be set to ``true``. See
+:ref:`dhcp4-match-client-id` for details. No additional settings are
+required for DHCPv6.
+
+If the ``replace-client-id`` option is set to ``true``, the value of the
+``echo-client-id`` parameter (which governs whether to send back a
+client-id option) is ignored.
+
+The :ref:`hooks-lease-cmds` section describes commands used to retrieve,
+update, and delete leases using various identifiers, such as ``hw-address`` and
+``client-id``. :ischooklib:`libdhcp_lease_cmds.so` does not natively support querying
+for leases by flexible identifier. However, when ``replace-client-id`` is
+set to ``true``, it makes it possible to query for leases using a value
+derived from the flexible identifier. In DHCPv4, the query
+looks similar to this:
+
+::
+
+ {
+ "command": "lease4-get",
+ "arguments": {
+ "identifier-type": "client-id",
+ "identifier": "00:54:64:45:66",
+ "subnet-id": 44
+ }
+ }
+
+where the hexadecimal value of "54:64:45:66" is a flexible identifier
+computed for the client.
+
+In DHCPv6, the corresponding query looks something like this:
+
+::
+
+ {
+ "command": "lease6-get",
+ "arguments": {
+ "identifier-type": "duid",
+ "identifier": "00:00:54:64:45:66",
+ "subnet-id": 10
+ }
+ }
+
+The ``ignore-iaid`` Flag
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+When ``ignore-iaid`` is set to ``true`` (the default value is ``false``),
+:ischooklib:`libdhcp_flex_id.so` causes the Kea DHCPv6 server to ignore the IAID value
+from incoming IPv6 packets. This parameter is ignored by the Kea DHCPv4 server.
+
+If the packet contains only one IA_NA, the IAID value will be changed to ``0``
+and stored as such in the lease storage. Similarly, if the packet contains only
+one IA_PD, the IAID value will be changed to ``0`` and stored as such in the
+lease storage. The IAID is restored to its initial value in the response back
+to the client. The change is visible in the identifier expression if the IAID is
+part of the expression.
+
+.. note::
+
+ To avoid lease conflicts, if the incoming packet contains more than one
+ IA_NA, the IAID value is not changed on any of the IA_NAs. Similarly,
+ if the incoming packet contains more than one IA_PD, the IAID value is not
+ changed on any of the IA_PDs.
+
+.. warning::
+
+ This functionality breaks RFC compliance and should be enabled only if
+ required. When enabled, a warning message is issued at configure time.
diff --git a/doc/sphinx/arm/hooks-flex-option.rst b/doc/sphinx/arm/hooks-flex-option.rst
new file mode 100644
index 0000000..ffac090
--- /dev/null
+++ b/doc/sphinx/arm/hooks-flex-option.rst
@@ -0,0 +1,196 @@
+.. ischooklib:: libdhcp_flex_option.so
+.. _hooks-flex-option:
+
+``libdhcp_flex_option.so``: Flexible Option Actions for Option Value Settings
+=============================================================================
+
+This library allows administrators to define an action to take, for a given
+option, based upon on the result of an expression. These actions are carried
+out during the final stages of constructing a query response packet, just
+before it is sent to the client. The three actions currently supported are
+``add``, ``supersede``, and ``remove``.
+
+.. note::
+
+ :ischooklib:`libdhcp_flex_option.so` is part of the open source code and is
+ available to every Kea user.
+
+The syntax used for the action expressions is the same syntax used
+for client classification and the Flexible Identifier hook library;
+see either :ref:`classification-using-expressions` or :ref:`hooks-flex-id`
+for a detailed description of the syntax.
+
+The ``add`` and ``supersede`` actions use an expression returning a
+string, and do nothing if the string is empty. The
+``remove`` application uses an expression returning ``true`` or ``false``,
+and does nothing on ``false``. When it is necessary to set an option to the
+empty value this mechanism does not work, but a client class can be
+used instead.
+
+The ``add`` action adds an option only when the option does not already
+exist and the expression does not evaluate to the empty string.
+The ``supersede`` action is similar, but it overwrites the option value
+if it already exists. The ``remove`` action removes the option from
+the response packet if it already exists and the expression evaluates to
+true.
+
+The option to which an action applies may be specified by either its
+numeric code or its name; either the code or the name must be
+specified. The option space is DHCPv4 or DHCPv6, depending
+on the server where the hook library is loaded.
+
+Similar to other hook libraries, :ischooklib:`libdhcp_flex_option.so` can be loaded
+by either the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6`
+process. It takes a mandatory ``options`` parameter with a list of
+per-option parameter maps, with ``code``, ``name``, ``add``, ``supersede``, and
+``remove`` actions. Action entries take a string value representing an
+expression.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_flex_option.so",
+ "parameters": {
+ "options": [
+ {
+ "code": 67,
+ "add": "ifelse(option[host-name].exists,concat(option[host-name].text,'.boot'),'')"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+
+If (and only if) the **query** includes a ``host-name`` option (code 12), a
+``boot-file-name`` option (code 67) is added to the response with the host name
+followed by ``.boot`` for content.
+
+A commonly discussed use case is modifying the DHCPv4 subnet mask option
+(code 1). The following example demonstrates that capability. All ingress
+packets identified by the gateway address 192.168.0.1 are met with a /32 subnet
+mask in the response.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_flex_option.so",
+ "parameters": {
+ "options": [
+ {
+ "code": 1,
+ "supersede": "ifelse(pkt4.giaddr==192.168.0.1, '255.255.255.255', '')"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+
+The flexible option library supports both DHCPv4 and DHCPv6.
+
+Since Kea 1.9.0, the ``add`` and ``supersede`` actions take an optional
+```csv-format``` boolean parameter. If not specified or set to ``false``, the
+option data is set using the raw value of the evaluated expression. When it is
+configured to ``true``, this value is parsed using the option definition from
+the option data specified in the configuration file. This eases option setting
+for options using complex record formats or fully qualified domain names.
+
+For instance, if the expression evaluation returns "example.com" and
+the option is defined with the ``fqdn`` type, the domain name will be
+encoded into DNS binary format.
+
+Since Kea 2.1.4, the ``client-class`` parameter specifies a class guard.
+It takes a client class name. If not empty, the client's packet needs to
+belong to specified class for this entry to be used.
+
+Since Kea 2.1.4, it is allowed to have multiple entries for the same option,
+but each entry must have exactly one action. If the option is not defined
+in the ``dhcp4`` for DHCPv4 or ``dhcp6`` for DHCPv6 you can specify the
+space where to find the option definition using its name with the new
+``space`` parameter.
+
+Since Kea 2.1.4, sub-options are supported with a new entry ``sub-options``
+which replaces the action in the configuration of the container option,
+i.e. the option where sub-options are located.
+
+The ``sub-options`` entry takes a list of sub-option configuration similar
+to the option one with:
+
+- ``code`` - specifies the sub-option code, either the ``code`` or ``name``
+ must be specified. When both are given they must match or the configuration
+ is rejected at load time.
+
+- ``name`` - specifies the sub-option name, either the ``code`` or ``name``
+ must be specified. When both are given they must match or the configuration
+ is rejected at load time.
+
+- ``space`` - specifies the space where the sub-option can be defined. This
+ parameter is optional because it can be found in the container option
+ definition. The configuration is rejected if no valid space name is
+ available at load time. Note that vendor spaces are supported for the
+ DHCPv4 ``vivso-suboptions`` and for the DHCPv6 ``vendor-opts``, both
+ pre-defined (e.g. DoCSIS vendor id 4491) or custom.
+
+- ``add`` - (action) adds a sub-option only if it does not already exist
+ and the expression does not evaluate to the empty string.
+
+- ``supersede`` - (action) adds or overwrites a sub-option if the expression
+ does not evaluate to the empty string.
+
+- ``remove`` - (action) removes a sub-option if it already exists and the
+ expression evaluates to true.
+
+- ``container-add`` - boolean value which specifies if the container option
+ should be created if it does not exit in the ``add`` and ``supersede``
+ action. When not specified, it defaults to true.
+
+- ``container-remove`` - boolean value which specifies if the container option
+ should be deleted if it remains empty after the removal of a sub-option by
+ the ``remove`` action. When not specified, it defaults to true.
+
+- ``csv-format`` - boolean value which specifies if the raw value of the
+ evaluated expression is used (false, default) or parsed using the sub-option
+ definition (true).
+
+- ``client-class`` - specifies if the sub-option entry must be skipped when
+ the **query** does not belong to the specified client class. Note the similar
+ parameter in the container option entry applies to the whole ``sub-options``
+ list.
+
+For instance this configuration adds a string sub-option in the DHCPv4
+``vendor-encapsulated-options`` (code 43) option. Note this option
+in last resort encapsulates the ``vendor-encapsulated-options`` space.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_flex_option.so",
+ "parameters": {
+ "options": [
+ {
+ "code": 43,
+ "sub-options": [
+ {
+ "code": 1,
+ "add": "'foobar'"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
diff --git a/doc/sphinx/arm/hooks-gss-tsig.rst b/doc/sphinx/arm/hooks-gss-tsig.rst
new file mode 100644
index 0000000..7c4e0b9
--- /dev/null
+++ b/doc/sphinx/arm/hooks-gss-tsig.rst
@@ -0,0 +1,15 @@
+.. ischooklib:: libddns_gss_tsig.so
+.. _hooks-gss-tsig:
+
+``libddns_gss_tsig.so``: Sign DNS Updates With GSS-TSIG
+=======================================================
+
+This hook library allows the :iscman:`kea-dhcp-ddns` server to use
+GSS-TSIG to sign DNS updates. For a full discussion of GSS-TSIG in Kea,
+please see :ref:`gss-tsig`.
+
+.. note::
+
+ :ischooklib:`libddns_gss_tsig.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
diff --git a/doc/sphinx/arm/hooks-ha.rst b/doc/sphinx/arm/hooks-ha.rst
new file mode 100644
index 0000000..9acfffe
--- /dev/null
+++ b/doc/sphinx/arm/hooks-ha.rst
@@ -0,0 +1,2662 @@
+.. ischooklib:: libdhcp_ha.so
+.. _hooks-high-availability:
+
+``libdhcp_ha.so``: High Availability Outage Resilience for Kea Servers
+======================================================================
+
+This hook library can be loaded on a pair of DHCPv4 or DHCPv6 servers, to
+increase the reliability of the DHCP service in the event of an outage on one
+server.
+
+.. note::
+
+ :ischooklib:`libdhcp_ha.so` is part of the open source code and is
+ available to every Kea user. It was previously available only to ISC
+ customers with a paid support contract.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` process.
+
+High Availability (HA) of the DHCP service is provided by running multiple
+cooperating server instances. If any of these instances becomes unavailable for
+any reason (DHCP software crash, Control Agent software crash, power outage,
+hardware failure), a surviving server instance can continue providing reliable
+service to clients. Many DHCP server implementations include the "DHCP Failover"
+protocol, whose most significant features are communication between the servers,
+partner failure detection, and lease synchronization between the servers.
+However, the DHCPv4 failover standardization process was never completed by the
+IETF. The DHCPv6 failover standard (RFC 8156) was published, but it is complex
+and difficult to use, has significant operational constraints, and is different
+from its v4 counterpart. Although it may be useful to use a "standard" failover
+protocol, most Kea users are simply interested in a working solution which
+guarantees high availability of the DHCP service. Therefore, the Kea HA hook
+library derives major concepts from the DHCP failover protocol but uses its own
+solutions for communication and configuration. It offers its own state machine,
+which greatly simplifies its implementation and generally fits better into Kea,
+and it provides the same features in both DHCPv4 and DHCPv6. This document
+intentionally uses the term "high availability" rather than "failover" to
+emphasize that it is not the failover protocol implementation.
+
+The following sections describe the configuration and operation of the Kea HA
+hook library.
+
+.. _ha-supported-configurations:
+
+Supported Configurations
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Kea HA hook library supports three configurations, also known as HA modes:
+``load-balancing``, ``hot-standby``, and ``passive-backup``. In the
+``load-balancing`` mode, two servers respond to DHCP requests. The
+``load-balancing`` function is implemented as described in `RFC
+3074 <https://tools.ietf.org/html/rfc3074>`__, with each server responding to
+half the received DHCP queries. When one of the servers allocates a lease for a
+client, it notifies the partner server over the control channel (via the RESTful
+API), so the partner can save the lease information in its own database. If the
+communication with the partner is unsuccessful, the DHCP query is dropped and
+the response is not returned to the DHCP client. If the lease update is
+successful, the response is returned to the DHCP client by the server which has
+allocated the lease. By exchanging lease updates, both servers get a copy of all
+leases allocated by the entire HA setup, and either server can be switched to
+handle the entire DHCP traffic if its partner becomes unavailable.
+
+In the ``load-balancing`` configuration, one of the servers must be designated
+as ``primary`` and the other as ``secondary``. Functionally, there is no
+difference between the two during normal operation. However, this distinction is
+required when the two servers are started at (nearly) the same time and have to
+synchronize their lease databases. The primary server synchronizes the database
+first. The secondary server waits for the primary server to complete the lease
+database synchronization before it starts the synchronization.
+
+In the ``hot-standby`` configuration, one of the servers is designated as
+``primary`` and the other as ``standby``. During normal operation, the primary
+server is the only one that responds to DHCP requests. The standby server
+receives lease updates from the primary over the control channel; however, it
+does not respond to any DHCP queries as long as the primary is running or, more
+accurately, until the standby considers the primary to be offline. If the
+standby server detects the failure of the primary, it starts responding to all
+DHCP queries.
+
+.. note::
+
+ Operators often wonder whether to use ``load-balancing`` or ``hot-standby``
+ mode. The ``load-balancing`` mode has the benefit of splitting the DHCP load
+ between two instances, reducing the traffic processed by each of them.
+ However, it is not always clear to the operators that using the
+ ``load-balancing`` mode requires manually splitting the address pools between
+ two Kea instances using client classification, to preclude both servers from
+ allocating the same address to different clients.
+ Such a split is not needed in the ``hot-standby`` mode. Thus, the benefit
+ of using ``hot-standby`` over ``load-balancing`` is that the former has a
+ simpler configuration. Conversely, ``load-balancing`` has higher performance
+ potential at the cost of more complex configuration.
+ See :ref:`ha-load-balancing-config` for details on how to split the pools
+ using client classification.
+
+In the configurations described above, both the primary and secondary/standby
+are referred to as ``active`` servers, because they receive lease updates and
+can automatically react to the partner's failures by responding to the DHCP
+queries which would normally be handled by the partner. The HA hook library
+supports another server type/role: ``backup``. The use of a backup server is
+optional, and can be implemented in both ``load-balancing`` and ``hot-standby``
+setup, in addition to the active servers. There is no limit on the number of
+backup servers in the HA setup; however, the presence of backup servers may
+increase the latency of DHCP responses, because not only do active servers send
+lease updates to each other, but also to the backup servers. The active servers
+do not expect acknowledgments from the backup servers before responding to the
+DHCP clients, so the overhead of sending lease updates to the backup servers is
+minimized.
+
+In the last supported configuration, ``passive-backup``, there is only one
+active server and typically one or more backup servers. A ``passive-backup``
+configuration with no backup servers is also accepted, but it is no different
+than running a single server with no HA function at all.
+
+The ``passive-backup`` configuration is used in situations when an administrator
+wants to take advantage of the backup server(s) as an additional storage for
+leases without running the full-blown failover setup. In this case, if the
+primary server fails, the DHCP service is lost; it requires the administrator to
+manually restart the primary to resume DHCP service. The administrator may also
+configure one of the backup servers to provide DHCP service to the clients, as
+these servers should have accurate or nearly accurate information about the
+allocated leases. The major advantage of the ``passive-backup`` mode is that it
+provides some redundancy of the lease information but with better performance of
+the primary server responding to the DHCP queries.
+The primary server does not have to wait for acknowledgments to the lease
+updates from the backup servers before it sends a response to the DHCP client.
+This reduces the response time compared to the ``load-balancing`` and
+``hot-standby`` cases, in which the server responding to the DHCP query has to
+wait for the acknowledgment from the other active server before it can respond
+to the client.
+
+.. note::
+
+ An interesting use case for a single active server running in the
+ ``passive-backup`` mode is a notification service, in which software
+ pretending to be a backup server receives live notifications about allocated
+ and deleted leases from the primary server and can display them on a
+ monitoring screen, trigger alerts, etc.
+
+Clocks on Active Servers
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Synchronized clocks are essential for the HA setup to operate reliably.
+The servers share lease information - via lease updates and during
+synchronization of the databases - including the time when the lease was
+allocated and when it expires. Some clock skew between the servers participating
+in the HA setup usually exists; this is acceptable as long as the clock skew is
+relatively low, compared to the lease lifetimes. However, if the clock skew
+becomes too high, the different lease expiration times on different servers may
+cause the HA system to malfunction. For example, one server may consider a lease
+to be expired when it is actually still valid. The lease reclamation process may
+remove a name associated with this lease from the DNS, causing problems when the
+client later attempts to renew the lease.
+
+Each active server monitors the clock skew by comparing its current time with
+the time returned by its partner in response to the :isccmd:`ha-heartbeat` command. This
+gives a good approximation of the clock skew, although it does not take into
+account the time between the partner sending the response and the receipt of
+this response by the server which sent the :isccmd:`ha-heartbeat` command. If the clock skew
+exceeds 30 seconds, a warning log message is issued. The administrator may
+correct this problem by synchronizing the clocks (e.g. using NTP); the servers
+should notice the clock skew correction and stop issuing the warning.
+
+If the clock skew is not corrected and exceeds 60 seconds, the HA service on
+each of the servers is terminated, i.e. the state machine enters the
+``terminated`` state. The servers will continue to respond to DHCP clients (as
+in the ``load-balancing`` or ``hot-standby`` mode), but will exchange neither
+lease updates nor heartbeats and their lease databases will diverge. In this
+case, the administrator should synchronize the clocks and restart the servers.
+
+.. note::
+
+ It is possible to restart the servers one at a time, in no particular order.
+ The clocks must be in sync before restarting the servers.
+
+.. note::
+
+ The clock skew is only assessed between two active servers, and only the
+ active servers enter the ``terminated`` state if the skew is too high. The
+ clock skew between active and backup servers is not assessed, because active
+ servers do not exchange heartbeat messages with backup servers.
+
+.. _ha-https-support:
+
+HTTPS Support
+~~~~~~~~~~~~~
+
+Since Kea 1.9.7, the High Availability hook library supports HTTPS via TLS, as
+described in :ref:`tls`.
+
+The HTTPS configuration parameters are:
+
+- ``trust-anchor`` - specifies the name of a file or directory where the
+ certification authority certificate of a Control Agent can be found.
+
+- ``cert-file`` - specifies the name of the file containing the end-entity
+ certificate to use.
+
+- ``key-file`` - specifies the private key of the end-entity certificate to use.
+
+These parameters can be configured at the global and peer levels. When
+configured at both levels the peer value is used, allowing common values to be
+shared.
+
+The three parameters must be either all not specified (HTTPS disabled) or all
+specified (HTTPS enabled). Specification of the empty string is considered not
+specified; this can be used, for instance, to disable HTTPS for a particular
+peer when it is enabled at the global level.
+
+As the High Availability hook library is an HTTPS client, there is no
+``cert-required`` parameter in this hook configuration.
+This parameter can be set in the Control Agent to require and verify a client
+certificate in client-server communication. It does not affect communication
+between HA peers at the client side; see below for information on the server
+side.
+
+Before Kea 2.1.7 using HTTPS in the HA setup required use of the Control Agent
+on all peers. (See :ref:`tls` for Control Agent TLS configuration).
+
+Since Kea 2.1.7 the HTTPS server side is supported:
+
+- the peer entry for the server name is used for the TLS setting.
+
+- the new ``require-client-certs`` parameter specifies whether client
+ certificates are required and verified, i.e. like ``cert-required``. It
+ defaults to ``true`` and is an HA config (vs. peer config) parameter.
+
+Kea 2.1.7 added a new security feature with the ``restrict-commands`` HA config
+parameter: when set to ``true``, commands which are not used by the hook are
+rejected. The default is ``false``.
+
+The following is an example of an HA server pair and Control Agent configuration
+for ``hot-standby`` with TLS.
+
+Server 1:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ "this-server-name": "server1",
+ "trust-anchor": "/usr/lib/kea/CA.pem",
+ "cert-file": "/usr/lib/kea/server1_cert.pem",
+ "key-file": "/usr/lib/kea/server1_key.pem",
+ "mode": "hot-standby",
+ "heartbeat-delay": 10000,
+ "max-response-delay": 60000,
+ "max-ack-delay": 5000,
+ "max-unacked-clients": 5,
+ "peers": [{
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary",
+ "auto-failover": true
+ }, {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }]
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.250"
+ }]
+ }]
+ }
+ }
+
+Server 2:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ "this-server-name": "server2",
+ "trust-anchor": "/usr/lib/kea/CA.pem",
+ "cert-file": "/usr/lib/kea/server2_cert.pem",
+ "key-file": "/usr/lib/kea/server2_key.pem",
+ "mode": "hot-standby",
+ "heartbeat-delay": 10000,
+ "max-response-delay": 60000,
+ "max-ack-delay": 5000,
+ "max-unacked-clients": 5,
+ "peers": [{
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary",
+ "auto-failover": true
+ }, {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }]
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.250"
+ }]
+ }]
+ }
+ }
+
+Control Agent on Server 1:
+::
+
+ {
+ "Control-agent": {
+ "http-host": "192.168.56.33",
+ "http-port": 8000,
+ "control-sockets": {
+ "dhcp4": {
+ "socket-type": "unix",
+ "socket-name": "/var/run/kea/control_socket"
+ }
+ },
+ "trust-anchor": "/var/lib/kea/CA.pem",
+ "cert-file": "/var/lib/kea/server1_cert.pem",
+ "key-file": "/var/lib/kea/server1_key.pem",
+ "cert-required": true
+ }
+ }
+
+Control Agent on Server 2:
+::
+
+ {
+ "Control-agent": {
+ "http-host": "192.168.56.66",
+ "http-port": 8000,
+ "control-sockets": {
+ "dhcp4": {
+ "socket-type": "unix",
+ "socket-name": "/var/run/kea/control_socket"
+ }
+ },
+ "trust-anchor": "/var/lib/kea/CA.pem",
+ "cert-file": "/var/lib/kea/server2_cert.pem",
+ "key-file": "/var/lib/kea/server2_key.pem",
+ "cert-required": true
+ }
+ }
+
+.. _ha-server-states:
+
+Server States
+~~~~~~~~~~~~~
+
+A DHCP server operating within an HA setup runs a state machine, and the state
+of the server can be retrieved by its peers using the :isccmd:`ha-heartbeat` command
+sent over the RESTful API. If the partner server does not respond to the
+:isccmd:`ha-heartbeat` command within the specified amount of time, the communication
+is considered interrupted and the server may, depending on the configuration,
+use additional measures (described later in this document) to verify that the
+partner is still operating. If it finds that the partner is not operating, the
+server transitions to the ``partner-down`` state to handle all the DHCP traffic
+directed to the system.
+
+In this case, the surviving server continues to send the :isccmd:`ha-heartbeat`
+command to detect when the partner wakes up. At that time, the partner
+synchronizes the lease database. When it is again ready to operate, the
+surviving server returns to normal operation, i.e. the ``load-balancing`` or
+``hot-standby`` state.
+
+The following is the list of all possible server states:
+
+- ``backup`` - normal operation of the backup server. In this state it receives
+ lease updates from the active server(s).
+
+- ``communication-recovery`` - an active server running in ``load-balancing``
+ mode may transition to this state when it experiences communication issues
+ with a partner server over the control channel. This is an intermediate state
+ between the ``load-balancing`` and ``partner-down`` states. In this state the
+ server continues to respond to DHCP queries but does not send lease updates
+ to the partner; lease updates are queued and are sent when normal
+ communication is resumed. If communication does not resume within the time
+ specified, the primary server then transitions to the ``partner-down`` state.
+ The ``communication-recovery`` state was introduced to ensure reliable DHCP
+ service when both active servers remain operational but the communication
+ between them is interrupted for a prolonged period of time. Either server can
+ be configured to never enter this state by setting the
+ ``delayed-updates-limit`` to 0 (please refer to
+ :ref:`ha-load-balancing-config`, later in this chapter, for details on this
+ parameter). Disabling entry into the ``communication-recovery`` state causes
+ the server to begin testing for the ``partner-down`` state as soon as the
+ server is unable to communicate with its partner.
+
+.. note::
+
+ In Kea 1.9.4, with the introduction of ``delayed-updates-limit``, the default
+ server's behavior in ``load-balancing`` mode changed. When a server
+ experiences communication issues with its partner, it now enters the
+ ``communication-recovery`` state and queues lease updates until communication
+ is resumed. Prior to Kea 1.9.4, a server that could not communicate with its
+ partner in ``load-balancing`` mode would immediately begin the transition to
+ the ``partner-down`` state.
+
+- ``hot-standby`` - normal operation of the active server running in the
+ ``hot-standby`` mode; both the primary and the standby server are in this
+ state during their normal operation. The primary server responds to DHCP
+ queries and sends lease updates to the standby server and to any backup
+ servers that are present.
+
+- ``load-balancing`` - normal operation of the active server running in the
+ ``load-balancing`` mode; both the primary and the secondary server are in
+ this state during their normal operation. Both servers respond to DHCP
+ queries and send lease updates to each other and to any backup servers that
+ are present.
+
+- ``in-maintenance`` - an active server transitions to this state as a result
+ of being notified by its partner that the administrator requested maintenance
+ of the HA setup. The administrator requests the maintenance by sending the
+ :isccmd:`ha-maintenance-start` command to the server which is supposed to take over
+ the responsibility for responding to the DHCP clients while the other server
+ is taken offline for maintenance. If the server is in the ``in-maintenance``
+ state it can be safely shut down. The partner transitions to the
+ ``partner-down`` state immediately after discovering that the server in
+ maintenance has been shut down.
+
+- ``partner-down`` - an active server transitions to this state after detecting
+ that its partner (another active server) is offline. The server does not
+ transition to this state if only a backup server is unavailable. In the
+ ``partner-down`` state the active server responds to all DHCP queries,
+ including those queries which are normally handled by the server that is now
+ unavailable.
+
+- ``partner-in-maintenance`` - an active server transitions to this state
+ after receiving a :isccmd:`ha-maintenance-start` command from the administrator.
+ The server in this state becomes responsible for responding to all DHCP
+ requests. The server sends a :isccmd:`ha-maintenance-notify` command to the partner,
+ which should enter the ``in-maintenance`` state. The server remaining in the
+ ``partner-in-maintenance`` state keeps sending lease updates to the partner
+ until it finds that the partner has stopped responding to those lease updates,
+ heartbeats, or any other commands. In this case, the server in the
+ ``partner-in-maintenance`` state transitions to the ``partner-down`` state
+ and keeps responding to the queries, but no longer sends lease updates.
+
+- ``passive-backup`` - a primary server running in the ``passive-backup`` HA
+ mode transitions to this state immediately after it boots up. The primary
+ server in this state responds to all DHCP traffic and sends lease updates to
+ the backup servers it is connected to. By default, the primary server does
+ not wait for acknowledgments from the backup servers and responds to a DHCP
+ query right after sending lease updates to all backup servers. If any of the
+ lease updates fail, a backup server misses the lease update but the DHCP
+ client is still provisioned. This default configuration can be changed by
+ setting the ``wait-backup-ack`` configuration parameter to ``true``, in which
+ case the primary server always waits for the acknowledgements and drops the
+ DHCP query if sending any of the corresponding lease updates fails. This
+ improves lease database consistency between the primary and the secondary.
+ However, if a communication failure between the active server and any of the
+ backups occurs, it effectively causes the failure of the DHCP service from
+ the DHCP clients' perspective.
+
+- ``ready`` - an active server transitions to this state after synchronizing
+ its lease database with an active partner. This state indicates to the
+ partner (which may be in the ``partner-down`` state) that it should return to
+ normal operation. If and when it does, the server in the ``ready`` state also
+ starts normal operation.
+
+- ``syncing`` - an active server transitions to this state to fetch leases from
+ the active partner and update the local lease database. When in this state,
+ the server issues the :isccmd:`dhcp-disable` command to disable the DHCP service of
+ the partner from which the leases are fetched. The DHCP service is disabled
+ for a maximum time of 60 seconds, after which it is automatically re-enabled,
+ in case the syncing partner was unable to re-enable the service. If the
+ synchronization completes successfully, the synchronizing server issues the
+ :isccmd:`ha-sync-complete-notify` command to notify the partner. In most states,
+ the partner re-enables its DHCP service to continue responding to the DHCP
+ queries. In the ``partner-down`` state, the partner first ensures that
+ communication between the servers is re-established before enabling the DHCP
+ service. The syncing operation is synchronous; the server waits for an answer
+ from the partner and does nothing else while the lease synchronization takes
+ place. A server that is configured not to synchronize the lease database with
+ its partner, i.e. when the ``sync-leases`` configuration parameter is set to
+ ``false``, will never transition to this state. Instead, it transitions
+ directly from the ``waiting`` state to the ``ready`` state.
+
+- ``terminated`` - an active server transitions to this state when the High
+ Availability hook library is unable to further provide reliable service and a
+ manual intervention of the administrator is required to correct the problem.
+ Various issues with the HA setup may cause the server to transition to this
+ state. While in this state, the server continues responding to DHCP clients
+ based on the HA mode selected (``load-balancing`` or ``hot-standby``), but
+ lease updates are not exchanged and heartbeats are not sent. Once a server
+ has entered the ``terminated`` state, it remains in this state until it is
+ restarted. The administrator must correct the issue which caused this
+ situation prior to restarting the server (e.g. synchronize the clocks);
+ otherwise, the server will return to the ``terminated`` state once it finds
+ that the issue persists.
+
+- ``waiting`` - each started server instance enters this state. A backup server
+ transitions directly from this state to the ``backup`` state. An active
+ server sends a heartbeat to its partner to check its state; if the partner
+ appears to be unavailable, the server transitions to the ``partner-down``
+ state. If the partner is available, the server transitions to the ``syncing``
+ or ``ready`` state, depending on the setting of the ``sync-leases``
+ configuration parameter. If both servers appear to be in the ``waiting``
+ state (concurrent startup), the primary server transitions to the next state
+ first. The secondary or standby server remains in the ``waiting`` state until
+ the primary transitions to the ``ready`` state.
+
+.. note::
+
+ Currently, restarting the HA service from the ``terminated`` state requires
+ restarting the DHCP server or reloading its configuration.
+
+Whether the server responds to DHCP queries and which queries it responds to is
+a matter of the server's state, if no administrative action is performed to
+configure the server otherwise. The following table provides the default
+behavior for various states.
+
+The ``DHCP Service Scopes`` denote which group of received DHCP queries the
+server responds to in the given state. The HA configuration must specify a
+unique name for each server within the HA setup. This document uses the
+following convention within the provided examples: "server1" for a primary
+server, "server2" for the secondary or standby server, and "server3" for the
+backup server. In real life any names can be used as long as they remain unique.
+
+An in-depth explanation of the scopes can be found below.
+
+.. table:: Default behavior of the server in various HA states
+
+ +------------------------+-----------------+-----------------+----------------+
+ | State | Server Type | DHCP Service | DHCP Service |
+ | | | | Scopes |
+ +========================+=================+=================+================+
+ | backup | backup server | disabled | none |
+ +------------------------+-----------------+-----------------+----------------+
+ | communication-recovery | primary or | enabled | "HA_server1" |
+ | | secondary | | or |
+ | | (load-balancing | | "HA_server2" |
+ | | mode only) | | |
+ +------------------------+-----------------+-----------------+----------------+
+ | hot-standby | primary or | enabled | "HA_server1" |
+ | | standby | | if primary, |
+ | | (hot-standby | | none otherwise |
+ | | mode) | | |
+ +------------------------+-----------------+-----------------+----------------+
+ | load-balancing | primary or | enabled | "HA_server1" |
+ | | secondary | | or |
+ | | (load-balancing | | "HA_server2" |
+ | | mode) | | |
+ +------------------------+-----------------+-----------------+----------------+
+ | in-maintenance | active server | disabled | none |
+ +------------------------+-----------------+-----------------+----------------+
+ | partner-down | active server | enabled | all scopes |
+ +------------------------+-----------------+-----------------+----------------+
+ | partner-in-maintenance | active server | enabled | all scopes |
+ +------------------------+-----------------+-----------------+----------------+
+ | passive-backup | active server | enabled | all scopes |
+ +------------------------+-----------------+-----------------+----------------+
+ | ready | active server | disabled | none |
+ +------------------------+-----------------+-----------------+----------------+
+ | syncing | active server | disabled | none |
+ +------------------------+-----------------+-----------------+----------------+
+ | terminated | active server | enabled | same as in the |
+ | | | | load-balancing |
+ | | | | or hot-standby |
+ | | | | state |
+ +------------------------+-----------------+-----------------+----------------+
+ | waiting | any server | disabled | none |
+ +------------------------+-----------------+-----------------+----------------+
+
+In the ``load-balancing`` mode there are two scopes specified for the active
+servers: "HA_server1" and "HA_server2". The DHCP queries load-balanced to
+``server1`` belong to the "HA_server1" scope and the queries load-balanced to
+``server2`` belong to the "HA_server2" scope. If either server is in the
+``partner-down`` state, the active partner is responsible for serving both
+scopes.
+
+In the ``hot-standby`` mode, there is only one scope - "HA_server1" - because
+only ``server1`` is responding to DHCP queries. If that server becomes
+unavailable, ``server2`` becomes responsible for this scope.
+
+The backup servers do not have their own scopes. In some cases they can be used
+to respond to queries belonging to the scopes of the active servers. Also, a
+backup server which is neither in the ``partner-down`` state nor in normal
+operation serves no scopes.
+
+The scope names can be used to associate pools, subnets, and networks with
+certain servers, so that only these servers can allocate addresses or prefixes
+from those pools, subnets, or networks. This is done via the client
+classification mechanism (see :ref:`ha-load-balancing-advanced-config` for more
+details).
+
+.. _ha-scope-transition:
+
+Scope Transition in a Partner-Down Case
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When one of the servers finds that its partner is unavailable, it starts serving
+clients from both its own scope and the scope of the unavailable partner. This
+is straightforward for new clients, i.e. those sending DHCPDISCOVER (DHCPv4) or
+Solicit (DHCPv6), because those requests are not sent to any particular server.
+The available server responds to all such queries when it is in the
+``partner-down`` state.
+
+When a client renews a lease, it sends its DHCPREQUEST (DHCPv4) or Renew (DHCPv6)
+message directly to the server which has allocated the lease being renewed. If
+this server is no longer available, the client will get no response. In that
+case, the client continues to use its lease and attempts to renew until the
+rebind timer (T2) elapses. The client then enters the rebinding phase, in which
+it sends a DHCPREQUEST (DHCPv4) or Rebind (DHCPv6) message to any available
+server. The surviving server receives the rebinding request and typically
+extends the lifetime of the lease. The client then continues to contact that new
+server to renew its lease as appropriate.
+
+If and when the other server once again becomes available, both active servers
+will eventually transition to the ``load-balancing`` or ``hot-standby`` state,
+in which they will again be responsible for their own scopes. Some clients
+belonging to the scope of the restarted server will try to renew their leases
+via the surviving server, but this server will no longer respond to them; the
+client will eventually transition back to the correct server via the rebinding
+mechanism.
+
+.. _ha-load-balancing-config:
+
+Load-Balancing Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following is the configuration snippet to enable high availability on the
+primary server within the ``load-balancing`` configuration. The same
+configuration should be applied on the secondary and backup servers, with the
+only difference that ``this-server-name`` should be set to "server2" and
+"server3" on those servers, respectively.
+
+.. note::
+
+ Remember that ``load-balancing`` mode requires the address pools and
+ delegated prefix pools to be split between the active servers. During normal
+ operation, the servers use non-overlapping pools to avoid allocating the same
+ lease to different clients by both instances. A server only uses the pool
+ fragments owned by the partner when the partner is not running. See the notes
+ in :ref:`ha-supported-configurations` highlighting differences between the
+ ``load-balancing`` and ``hot-standby`` modes. The semantics of pool
+ partitioning is explained further in this section.
+ The :ref:`ha-load-balancing-advanced-config` section provides advanced
+ pool-partitioning examples.
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ "this-server-name": "server1",
+ "mode": "load-balancing",
+ "heartbeat-delay": 10000,
+ "max-response-delay": 60000,
+ "max-ack-delay": 5000,
+ "max-unacked-clients": 5,
+ "max-rejected-lease-updates": 10,
+ "delayed-updates-limit": 100,
+ "peers": [{
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary",
+ "auto-failover": true
+ }, {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "secondary",
+ "auto-failover": true
+ }, {
+ "name": "server3",
+ "url": "http://192.168.56.99:8000/",
+ "role": "backup",
+ "basic-auth-user": "foo",
+ "basic-auth-password": "bar",
+ "auto-failover": false
+ }]
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.150",
+ "client-class": "HA_server1"
+ }, {
+ "pool": "192.0.3.200 - 192.0.3.250",
+ "client-class": "HA_server2"
+ }],
+
+ "option-data": [{
+ "name": "routers",
+ "data": "192.0.3.1"
+ }],
+
+ "relay": { "ip-address": "10.1.2.3" }
+ }]
+ }
+
+Two hook libraries must be loaded to enable HA: :ischooklib:`libdhcp_lease_cmds.so` and
+:ischooklib:`libdhcp_ha.so`. The latter implements the HA feature, while the former
+enables control commands required by HA to fetch and manipulate leases on the
+remote servers. In the example provided above, it is assumed that Kea libraries
+are installed in the ``/usr/lib`` directory. If Kea is not installed in the
+``/usr`` directory, the hook libraries' locations must be updated accordingly.
+
+The HA configuration is specified within the scope of :ischooklib:`libdhcp_ha.so`.
+Note that while the top-level parameter ``high-availability`` is a list, only a
+single entry is currently supported.
+
+The following are the global parameters which control the server's behavior with
+respect to HA:
+
+- ``this-server-name`` - is a unique identifier of the server within this HA
+ setup. It must match one of the servers specified within the ``peers`` list.
+
+- ``mode`` - specifies an HA mode of operation. The currently supported modes
+ are ``load-balancing`` and ``hot-standby``.
+
+- ``heartbeat-delay`` - specifies a duration in milliseconds between sending
+ the last heartbeat (or other command sent to the partner) and the next
+ heartbeat. Heartbeats are sent periodically to gather the status of the
+ partner and to verify whether the partner is still operating. The default
+ value of this parameter is 10000 ms.
+
+- ``max-response-delay`` - specifies a duration in milliseconds since the last
+ successful communication with the partner, after which the server assumes
+ that communication with the partner is interrupted. This duration should be
+ greater than the ``heartbeat-delay``; typically it should be a multiple of
+ ``heartbeat-delay``. When the server detects that communication is
+ interrupted, it may transition to the ``partner-down`` state (when
+ ``max-unacked-clients`` is 0) or trigger the failure-detection procedure
+ using the values of the two parameters below. The default value of this
+ parameter is 60000 ms.
+
+- ``max-ack-delay`` - is one of the parameters controlling partner
+ failure-detection. When communication with the partner is interrupted, the
+ server examines the values of the "secs" field (DHCPv4) or "elapsed time"
+ option (DHCPv6), which denote how long the DHCP client has been trying to
+ communicate with the DHCP server. This parameter specifies the maximum time
+ in milliseconds for the client to try to communicate with the DHCP server,
+ after which this server assumes that the client failed to communicate with
+ the DHCP server (is unacknowledged or "unacked"). The default value of this
+ parameter is 10000.
+
+- ``max-unacked-clients`` - specifies how many "unacked" clients are allowed
+ (see ``max-ack-delay``) before this server assumes that the partner is
+ offline and transitions to the ``partner-down`` state. The special value of 0
+ is allowed for this parameter, which disables the failure-detection mechanism.
+ In this case, a server that cannot communicate with its partner over the
+ control channel assumes that the partner server is down and transitions to
+ the ``partner-down`` state immediately. The default value of this parameter
+ is 10.
+
+- ``max-rejected-lease-updates`` - specifies how many lease updates for distinct
+ clients can fail, due to a conflict between the lease and the partner configuration
+ or state, before the server transitions to the ``terminated`` state. Conflict
+ can be a sign of a misconfiguration; usually, a small number of conflicted
+ leases are acceptable because they affect only a few devices. However, if
+ the conflicts occur for many devices (e.g., an entire subnet), the HA service
+ becomes unreliable and should be terminated, and the problem must be manually
+ corrected by an administrator. It is up to the administrator to select
+ the highest acceptable value of ``max-rejected-lease-updates``. The default
+ value is 10. The special value of 0 configures the server to never terminate
+ the HA service due to lease conflicts. If the value is 1, the server
+ transitions to the ``terminated`` state when the first conflict occurs.
+ This parameter does not pertain to conflicting lease updates sent to
+ the backup servers.
+
+- ``delayed-updates-limit`` - specifies the maximum number of lease updates
+ which can be queued while the server is in the ``communication-recovery``
+ state. This parameter was introduced in Kea 1.9.4. The special value of 0
+ configures the server to never transition to the ``communication-recovery``
+ state and the server behaves as in earlier Kea versions, i.e. if the server
+ cannot reach its partner, it goes straight into the ``partner-down`` state.
+ The default value of this parameter is 100.
+
+.. note::
+
+ The ``max-rejected-lease-updates`` parameter was introduced in Kea 2.3.1.
+ Previously, the server did not differentiate between a lease update
+ failure due to a non-functioning partner and a failure due to a conflict
+ (e.g., configuration issues).
+ As a result, the server could sometimes transition to the ``partner-down``
+ state even though the partner was operating normally, but only certain leases
+ had issues. Conflicts should no longer cause such a transition. However,
+ depending on the ``max-rejected-lease-updates`` setting, too many conflicts
+ can lead to termination of the High Availability service. In that case, both
+ servers continue to respond to DHCP queries but no longer send lease updates.
+
+The values of ``max-ack-delay`` and ``max-unacked-clients`` must be selected
+carefully, taking into account the specifics of the network in which the DHCP
+servers are operating. The server in question may not respond to some DHCP
+clients following administrative policy, or the server may drop malformed
+queries from clients. Therefore, selecting too low a value for the
+``max-unacked-clients`` parameter may result in a transition to the
+``partner-down`` state even though the partner is still operating. On the other
+hand, selecting too high a value may result in never transitioning to the
+``partner-down`` state if the DHCP traffic in the network is very low (e.g. at
+night), because the number of distinct clients trying to communicate with the
+server could be lower than the ``max-unacked-clients`` setting.
+
+In some cases it may be useful to disable the failure-detection mechanism
+altogether, if the servers are located very close to each other and network
+partitioning is unlikely, i.e. failure to respond to heartbeats is only possible
+when the partner is offline. In such cases, set ``max-unacked-clients`` to 0.
+
+The ``delayed-updates-limit`` parameter is used to enable or disable the
+``communication-recovery`` procedure, and controls the server's behavior in the
+``communication-recovery`` state. This parameter can only be used in the
+``load-balancing`` mode.
+
+If a server in the ``load-balancing`` state experiences communication issues
+with its partner (a heartbeat or lease-update failure), the server transitions
+to the ``communication-recovery`` state. In this state, the server keeps
+responding to DHCP queries but does not send lease updates to the partner. The
+lease updates are queued until communication is re-established, to ensure that
+DHCP service remains available even in the event of the communication loss
+between the partners. There may appear to be communication loss when either one
+of the servers has terminated, or when both servers remain available but cannot
+communicate with each other. In the former case, the surviving server will
+follow the normal procedure and should eventually transition to the
+``partner-down`` state. In the latter case, both servers should transition to
+the ``communication-recovery`` state and should never transition to the
+``partner-down`` state (if ``max-unacked-clients`` is set to a non-zero value),
+because all DHCP queries are answered and neither server would see any unacked
+DHCP queries.
+
+Introduction of the ``communication-recovery`` procedure was motivated by issues
+which may appear when two servers remain online but the communication between
+them remains interrupted for a period of time. In earlier Kea versions, the
+servers having communication issues used to drop DHCP packets before
+transitioning to the ``partner-down`` state. In some cases they both
+transitioned to the ``partner-down`` state, which could potentially result in
+allocations of the same IP addresses or delegated prefixes to different clients
+by both servers. By entering the intermediate ``communication-recovery`` state,
+these problems are avoided.
+
+If a server in the ``communication-recovery`` state re-establishes communication
+with its partner, it tries to send the partner all of the outstanding lease
+updates it has queued. This is done synchronously and may take a considerable
+amount of time before the server transitions to the ``load-balancing`` state and
+resumes normal operation.
+The maximum number of lease updates which can be queued in the
+``communication-recovery`` state is controlled by ``delayed-updates-limit``.
+If the limit is exceeded, the server stops queuing lease updates and performs a
+full database synchronization after re-establishing the connection with the
+partner, instead of sending outstanding lease updates before transitioning to
+the ``load-balancing`` state. Even if the limit is exceeded, the server in the
+``communication-recovery`` state remains responsive to DHCP clients.
+
+It may be preferable to set higher values of ``delayed-updates-limit`` when
+there is a risk of prolonged communication interruption between the servers and
+when the lease database is large, to avoid costly lease-database synchronization.
+On the other hand, if the lease database is small, the time required to send
+outstanding lease updates may be longer than the lease-database synchronization.
+In such cases it may be better to use a lower value, e.g. 10. The default value
+of 100 is a reasonable compromise and should work well in most deployments with
+moderate traffic.
+
+.. note::
+
+ This parameter is new and values for it that work well in some environments
+ may not work well in others. Feedback from users will help us build a better
+ working set of recommendations.
+
+The ``peers`` parameter contains a list of servers within this HA setup.
+This configuration must contain at least one primary and one secondary server.
+It may also contain an unlimited number of backup servers. In this example,
+there is one backup server which receives lease updates from the active servers.
+
+Since Kea version 1.9.0, basic HTTP authentication is available
+to protect the Kea control agent against local attackers.
+
+These are the parameters specified for each of the peers within this
+list:
+
+- ``name`` - specifies a unique name for the server.
+
+- ``url`` - specifies the URL to be used to contact this server over the
+ control channel. Other servers use this URL to send control commands to that
+ server.
+
+- ``basic-auth-user`` - specifies the user ID for basic HTTP authentication. If
+ not specified or specified as an empty string, no authentication header is
+ added to HTTP transactions. It must not contain the colon (:) character.
+
+- ``basic-auth-password`` - specifies the password for basic HTTP
+ authentication. This parameter is ignored when the user ID is not specified
+ or is empty. The password is optional; if not specified, an empty password is
+ used.
+
+- ``basic-auth-password-file`` - is an alternative to ``basic-auth-password``:
+ instead of presenting the password in the configuration file it is specified
+ in the file indicated by this parameter.
+
+- ``role`` - denotes the role of the server in the HA setup. The following
+ roles are supported in the ``load-balancing`` configuration: ``primary``,
+ ``secondary``, and ``backup``. There must be exactly one primary and one
+ secondary server in the ``load-balancing`` setup.
+
+- ``auto-failover`` - a boolean value which denotes whether a server detecting
+ a partner's failure should automatically start serving the partner's clients.
+ The default value of this parameter is ``true``.
+
+In our example configuration above, both active servers can allocate leases from
+the subnet "192.0.3.0/24". This subnet contains two address pools:
+"192.0.3.100 - 192.0.3.150" and "192.0.3.200 - 192.0.3.250", which are
+associated with HA server scopes using client classification. When ``server1``
+processes a DHCP query, it uses the first pool for lease allocation. Conversely,
+when ``server2`` processes a DHCP query it uses the second pool. If either of
+the servers is in the ``partner-down`` state, the other can serve leases from
+both pools; it selects the pool which is appropriate for the received query. In
+other words, if the query would normally be processed by ``server2`` but this
+server is not available, ``server1`` allocates the lease from the pool of
+"192.0.3.200 - 192.0.3.250". The Kea control agent in front of ``server3``
+requires basic HTTP authentication, and authorizes the user ID "foo" with the
+password "bar".
+
+.. note::
+
+ The ``url`` schema can be ``http`` or ``https``, but since Kea version 1.9.6
+ the ``https`` schema requires a TLS setup. The hostname part must be an IPv4
+ address or an IPv6 address between square brackets, e.g.
+ ``http://[2001:db8::1]:8080/``. Names are not accepted.
+
+.. _ha-load-balancing-advanced-config:
+
+Load Balancing With Advanced Classification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the previous section, we provided an example of a ``load-balancing``
+configuration with client classification limited to the "HA_server1" and
+"HA_server2" classes, which are dynamically assigned to the received DHCP
+queries. In many cases, HA is needed in deployments which already use some other
+client classification.
+
+Suppose there is a system which classifies devices into two groups: "phones" and
+"laptops", based on some classification criteria specified in the Kea
+configuration file. Both types of devices are allocated leases from different
+address pools. Introducing HA in ``load-balancing`` mode results in a further
+split of each of those pools, as each server allocates leases for some phones
+and some laptops. This requires each of the existing pools to be split between
+"HA_server1" and "HA_server2", so we end up with the following classes:
+
+- "phones_server1"
+- "laptops_server1"
+- "phones_server2"
+- "laptops_server2"
+
+The corresponding server configuration, using advanced classification (and the
+``member`` expression), is provided below. For brevity's sake, the HA hook
+library configuration has been removed from this example.
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "client-classes": [{
+ "name": "phones",
+ "test": "substring(option[60].hex,0,6) == 'Aastra'"
+ }, {
+ "name": "laptops",
+ "test": "not member('phones')"
+ }, {
+ "name": "phones_server1",
+ "test": "member('phones') and member('HA_server1')"
+ }, {
+ "name": "phones_server2",
+ "test": "member('phones') and member('HA_server2')"
+ }, {
+ "name": "laptops_server1",
+ "test": "member('laptops') and member('HA_server1')"
+ }, {
+ "name": "laptops_server2",
+ "test": "member('laptops') and member('HA_server2')"
+ }],
+
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.125",
+ "client-class": "phones_server1"
+ }, {
+ "pool": "192.0.3.126 - 192.0.3.150",
+ "client-class": "laptops_server1"
+ }, {
+ "pool": "192.0.3.200 - 192.0.3.225",
+ "client-class": "phones_server2"
+ }, {
+ "pool": "192.0.3.226 - 192.0.3.250",
+ "client-class": "laptops_server2"
+ }],
+
+ "option-data": [{
+ "name": "routers",
+ "data": "192.0.3.1"
+ }],
+
+ "relay": { "ip-address": "10.1.2.3" }
+ }]
+ }
+ }
+
+The configuration provided above splits the address range into four pools: two
+pools dedicated to "HA_server1" and two to "HA_server2". Each server can assign
+leases to both phones and laptops. Both groups of devices are assigned addresses
+from different pools. The "HA_server1" and "HA_server2" classes are built-in
+(see :ref:`built-in-client-classes`) and do not need to be declared.
+They are assigned dynamically by the HA hook library as a result of the
+``load-balancing`` algorithm. "phones_*" and "laptop_*" evaluate to ``true``
+when the query belongs to a given combination of other classes, e.g. "HA_server1"
+and "phones". The pool is selected accordingly as a result of such an evaluation.
+
+Consult :ref:`classify` for details on how to use the ``member`` expression and
+class dependencies.
+
+.. _ha-hot-standby-config:
+
+Hot-Standby Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following is an example configuration of the primary server in a
+``hot-standby`` configuration:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ "this-server-name": "server1",
+ "mode": "hot-standby",
+ "heartbeat-delay": 10000,
+ "max-response-delay": 60000,
+ "max-ack-delay": 5000,
+ "max-unacked-clients": 5,
+ "max-rejected-lease-updates": 10,
+ "peers": [{
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary",
+ "auto-failover": true
+ }, {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }, {
+ "name": "server3",
+ "url": "http://192.168.56.99:8000/",
+ "basic-auth-user": "foo",
+ "basic-auth-password": "bar",
+ "role": "backup",
+ "auto-failover": false
+ }]
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.250",
+ "client-class": "HA_server1"
+ }],
+
+ "option-data": [{
+ "name": "routers",
+ "data": "192.0.3.1"
+ }],
+
+ "relay": { "ip-address": "10.1.2.3" }
+ }]
+ }
+
+This configuration is very similar to the ``load-balancing`` configuration
+described in :ref:`ha-load-balancing-config`, with a few notable differences.
+
+The ``mode`` is now set to ``hot-standby``, in which only one server responds to
+DHCP clients. If the primary server is online, it responds to all DHCP queries.
+The ``standby`` server takes over all DHCP traffic only if it discovers that the
+primary is unavailable.
+
+In this mode, the non-primary active server is called ``standby`` and that is
+its role.
+
+Finally, because there is always only one server responding to DHCP queries,
+there is only one scope - "HA_server1" - in use within pool definitions. In fact,
+the ``client-class`` parameter could be removed from this configuration without
+harm, because there can be no conflicts in lease allocations by different
+servers as they do not allocate leases concurrently. The ``client-class``
+remains in this example mostly for demonstration purposes, to highlight the
+differences between the ``hot-standby`` and ``load-balancing`` modes of
+operation.
+
+.. _ha-passive-backup-config:
+
+Passive-Backup Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following is an example configuration file for the primary server in a
+``passive-backup`` configuration:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [{
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ }, {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [{
+ "this-server-name": "server1",
+ "mode": "passive-backup",
+ "wait-backup-ack": false,
+ "peers": [{
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary"
+ }, {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "backup"
+ }, {
+ "name": "server3",
+ "url": "http://192.168.56.99:8000/",
+ "basic-auth-user": "foo",
+ "basic-auth-password": "bar",
+ "role": "backup"
+ }]
+ }]
+ }
+ }],
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.3.0/24",
+ "pools": [{
+ "pool": "192.0.3.100 - 192.0.3.250"
+ }],
+
+ "option-data": [{
+ "name": "routers",
+ "data": "192.0.3.1"
+ }],
+
+ "relay": { "ip-address": "10.1.2.3" }
+ }]
+ }
+ }
+
+The configurations of three peers are included: one for the primary and two for
+the backup servers.
+
+Many of the parameters present in the ``load-balancing`` and ``hot-standby``
+configuration examples are not relevant in the ``passive-backup`` mode, thus
+they are not specified here. For example: ``heartbeat-delay``,
+``max-unacked-clients``, ``max-rejected-lease-updates``, and others related to
+the failover mechanism should not be specified in the ``passive-backup`` mode.
+
+The ``wait-backup-ack`` is a boolean parameter not present in previous examples.
+It defaults to ``false`` and must not be modified in the ``load-balancing`` and
+``hot-standby`` modes. In the ``passive-backup`` mode this parameter can be set
+to ``true``, which causes the primary server to expect acknowledgments to the
+lease updates from the backup servers prior to responding to the DHCP client. It
+ensures that the lease has propagated to all servers before the client is given
+the lease, but it poses a risk of losing a DHCP service if there is a
+communication problem with one of the backup servers. This setting also
+increases the latency of the DHCP response, because of the time that the primary
+spends waiting for the acknowledgements. We recommend that the
+``wait-backup-ack`` setting be left at its default value (``false``) if the DHCP
+service reliability is more important than consistency of the lease information
+between the primary and the backups, and in all cases when the DHCP service
+latency should be minimal.
+
+.. note::
+
+ Currently, active servers place lease updates to be sent to peers onto
+ internal queues (one queue per peer/URL). In ``passive-backup`` mode, active
+ servers do not wait for lease updates to be acknowledged; thus during times
+ of heavy client traffic it is possible for the number of lease updates queued
+ for transmission to accumulate faster than they can be delivered. As client
+ traffic lessens the queues begin to empty. Since Kea 2.0.0, active servers
+ monitor the size of these queues and emit periodic warnings (see
+ HTTP_CLIENT_QUEUE_SIZE_GROWING in :ref:`kea-messages`) if they perceive a
+ queue as growing too quickly. The warnings cease once the queue size begins
+ to shrink. These messages are intended as a bellwether and seeing them
+ sporadically during times of heavy traffic load does not necessarily indicate
+ a problem. If, however, they occur continually during times of routine
+ traffic load, they likely indicate potential mismatches in server
+ capabilities and/or configuration; this should be investigated, as the size
+ of the queues may eventually impair an active server's ability to respond to
+ clients in a timely manner.
+
+.. _ha-sharing-lease-info:
+
+Lease Information Sharing
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An HA-enabled server informs its active partner about allocated or renewed
+leases by sending appropriate control commands, and the partner updates the
+lease information in its own database. When the server starts up for the first
+time or recovers after a failure, it synchronizes its lease database with its
+partner. These two mechanisms guarantee consistency of the lease information
+between the servers and allow the designation of one of the servers to handle
+the entire DHCP traffic load if the other server becomes unavailable.
+
+In some cases, though, it is desirable to disable lease updates and/or database
+synchronization between the active servers, if the exchange of information about
+the allocated leases is performed using some other mechanism. Kea supports
+various database types that can be used to store leases, including MySQL and
+PostgreSQL. Those databases include built-in solutions for data replication
+which are often used by Kea administrators to provide redundancy.
+
+The HA hook library supports such scenarios by disabling lease updates over the
+control channel and/or lease-database synchronization, leaving the server to
+rely on the database replication mechanism. This is controlled by the two
+boolean parameters ``send-lease-updates`` and ``sync-leases``, whose values
+default to ``true``:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ "mode": "load-balancing",
+ "send-lease-updates": false,
+ "sync-leases": false,
+ "peers": [
+ {
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary"
+ },
+ {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "secondary"
+ }
+ ]
+ } ]
+ }
+ }
+ ],
+ ...
+ }
+
+In the most typical use case, both parameters are set to the same value, i.e.
+both are ``false`` if database replication is in use, or both are ``true``
+otherwise. Introducing two separate parameters to control lease updates and
+lease-database synchronization is aimed at possible special use cases; for
+example, when synchronization is performed by copying a lease file (therefore
+``sync-leases`` is set to ``false``), but lease updates should be conducted as
+usual (``send-lease-updates`` is set to ``true``). It should be noted that Kea
+does not natively support such use cases, but users may develop their own
+scripts and tools around Kea to provide such mechanisms. The HA hook library
+configuration is designed to maximize flexibility of administration.
+
+.. _ha-syncing-page-limit:
+
+Controlling Lease-Page Size Limit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An HA-enabled server initiates synchronization of the lease database after
+downtime or upon receiving the :isccmd:`ha-sync` command. The server uses commands
+:isccmd:`lease4-get-page` and :isccmd:`lease6-get-page`
+to fetch leases from its partner server (lease queries). The size of the results
+page (the maximum number of leases to be returned in a single response to one of
+these commands) can be controlled via configuration of the HA hook library.
+Increasing the page size decreases the number of lease queries sent to the
+partner server, but it causes the partner server to generate larger responses,
+which lengthens transmission time as well as increases memory and CPU
+utilization on both servers. Decreasing the page size helps to decrease resource
+utilization, but requires more lease queries to be issued to fetch the entire
+lease database.
+
+The default value of the ``sync-page-limit`` command controlling the page size
+is 10000. This means that the entire lease database can be fetched with a single
+command if the size of the database is equal to or less than 10000 lines.
+
+.. _ha-syncing-timeouts:
+
+Timeouts
+~~~~~~~~
+
+In deployments with a large number of clients connected to the network,
+lease-database synchronization after a server failure may be a time-consuming
+operation. The synchronizing server must gather all leases from its partner,
+which yields a large response over the RESTful interface. The server receives
+leases using the paging mechanism described in :ref:`ha-syncing-page-limit`.
+Before the page of leases is fetched, the synchronizing server sends a
+:isccmd:`dhcp-disable` command to disable the DHCP service on the partner server. If
+the service is already disabled, this command resets the timeout for the DHCP
+service being disabled, which by default is set to 60 seconds. If fetching a
+single page of leases takes longer than the specified time, the partner server
+assumes that the synchronizing server has died and resumes its DHCP service. The
+connection of the synchronizing server with its partner is also protected by the
+timeout. If the synchronization of a single page of leases takes longer than the
+specified time, the synchronizing server terminates the connection and the
+synchronization fails. Both timeout values are controlled by a single
+configuration parameter, ``sync-timeout``. The following configuration snippet
+demonstrates how to modify the timeout for automatic re-enabling of the DHCP
+service on the partner server and how to increase the timeout for fetching a
+single page of leases from 60 seconds to 90 seconds:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ "mode": "load-balancing",
+ "sync-timeout": 90000,
+ "peers": [
+ {
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary"
+ },
+ {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "secondary"
+ }
+ ]
+ } ]
+ }
+ }
+ ],
+ ...
+ }
+
+It is important to note that extending this ``sync-timeout`` value may sometimes
+be insufficient to prevent issues with timeouts during lease-database
+synchronization. The control commands travel via the Control Agent, which also
+monitors incoming (with a synchronizing server) and outgoing (with a DHCP server)
+connections for timeouts. The DHCP server also monitors the connection from the
+Control Agent for timeouts. Those timeouts cannot currently be modified via
+configuration; extending these timeouts is only possible by modifying them in
+the Kea code and recompiling the server. The relevant constants are located in
+the Kea source at: ``src/lib/config/timeouts.h``.
+
+.. _ha-pause-state-machine:
+
+Pausing the HA State Machine
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``high-availability`` state machine includes many different states described
+in detail in :ref:`ha-server-states`. The server enters each state when certain
+conditions are met, most often taking into account the partner server's state.
+In some states the server performs specific actions, e.g. synchronization of the
+lease database in the ``syncing`` state, or responding to DHCP queries according
+to the configured mode of operation in the ``load-balancing`` and ``hot-standby``
+states.
+
+By default, transitions between the states are performed automatically and the
+server administrator has no direct control over when the transitions take place;
+in most cases, the administrator does not need such control. In some situations,
+however, the administrator may want to "pause" the HA state machine in a
+selected state to perform some additional administrative actions before the
+server transitions to the next state.
+
+Consider a server failure which results in the loss of the entire lease database.
+Typically, the server rebuilds its lease database when it enters the ``syncing``
+state by querying the partner server for leases, but it is possible that the
+partner was also experiencing a failure and lacks lease information. In this
+case, it may be required to reconstruct lease databases on both servers from
+some external source, e.g. a backup server. If the lease database is to be
+reconstructed via the RESTful API, the servers should be started in the initial,
+i.e. ``waiting``, state and remain in this state while leases are being added.
+In particular, the servers should not attempt to synchronize their lease
+databases nor start serving DHCP clients.
+
+The HA hook library provides configuration parameters and a command to control
+pausing and resuming the HA state machine. The following configuration causes
+the HA state machine to pause in the ``waiting`` state after server startup.
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ "mode": "load-balancing",
+ "peers": [
+ {
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary"
+ },
+ {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "secondary"
+ }
+ ],
+ "state-machine": {
+ "states": [
+ {
+ "state": "waiting",
+ "pause": "once"
+ }
+ ]
+ }
+ } ]
+ }
+ }
+ ],
+ ...
+ }
+
+The ``pause`` parameter value ``once`` denotes that the state machine should be
+paused upon the first transition to the ``waiting`` state; later transitions to
+this state will not cause the state machine to pause. Two other supported values
+of the ``pause`` parameter are ``always`` and ``never``. The latter is the
+default value for each state, which instructs the server never to pause the
+state machine.
+
+In order to "unpause" the state machine, the :isccmd:`ha-continue` command must be
+sent to the paused server. This command does not take any arguments. See
+:ref:`ha-control-commands` for details about commands specific to :ischooklib:`libdhcp_ha.so`.
+
+It is possible to configure the state machine to pause in more than one state.
+Consider the following configuration:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ "mode": "load-balancing",
+ "peers": [
+ {
+ "name": "server1",
+ "url": "http://192.168.56.33:8000/",
+ "role": "primary"
+ },
+ {
+ "name": "server2",
+ "url": "http://192.168.56.66:8000/",
+ "role": "secondary"
+ }
+ ],
+ "state-machine": {
+ "states": [
+ {
+ "state": "ready",
+ "pause": "always"
+ },
+ {
+ "state": "partner-down",
+ "pause": "once"
+ }
+ ]
+ }
+ } ]
+ }
+ }
+ ],
+ ...
+ }
+
+This configuration instructs the server to pause the state machine every time it
+transitions to the ``ready`` state and upon the first transition to the
+``partner-down`` state.
+
+Refer to :ref:`ha-server-states` for a complete list of server states. The state
+machine can be paused in any of the supported states; however, it is not
+practical to pause in the ``backup`` or ``terminated`` states because the server
+never transitions out of these states anyway.
+
+.. note::
+
+ In the ``syncing`` state the server is paused before it makes an attempt to
+ synchronize the lease database with a partner. To pause the state machine
+ after lease-database synchronization, use the ``ready`` state instead.
+
+.. note::
+
+ The state of the HA state machine depends on the state of the cooperating
+ server. Therefore, pausing the state machine of one server may affect the
+ operation of the partner server. For example: if the primary server is paused
+ in the ``waiting`` state, the partner server will also remain in the
+ ``waiting`` state until the state machine of the primary server is resumed
+ and that server transitions to the ``ready`` state.
+
+.. _ha-ctrl-agent-config:
+
+Control Agent Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :ref:`kea-ctrl-agent` describes in detail the Kea daemon, which provides a
+RESTful interface to control the Kea servers. The same functionality is used by
+the High Availability hook library to establish communication between the HA
+peers. Therefore, the HA library requires that the Control Agent (CA) be started
+for each DHCP instance within the HA setup. If the Control Agent is not started,
+the peers cannot communicate with a particular DHCP server (even if the DHCP
+server itself is online) and may eventually consider this server to be offline.
+
+The following is an example configuration for the CA running on the same
+machine as the primary server. This configuration is valid for both the
+``load-balancing`` and the ``hot-standby`` cases presented in previous sections.
+
+::
+
+ {
+ "Control-agent": {
+ "http-host": "192.168.56.33",
+
+ // If enabling HA and multi-threading, the 8000 port is used by the HA
+ // hook library http listener. When using HA hook library with
+ // multi-threading to function, make sure the port used by dedicated
+ // listener is different (e.g. 8001) than the one used by CA. Note
+ // the commands should still be sent via CA. The dedicated listener
+ // is specifically for HA updates only.
+ "http-port": 8000,
+
+ "control-sockets": {
+ "dhcp4": {
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea-dhcp4-ctrl.sock"
+ },
+ "dhcp6": {
+ "socket-type": "unix",
+ "socket-name": "/tmp/kea-dhcp6-ctrl.sock"
+ }
+ }
+ }
+ }
+
+Since Kea 1.9.0, basic HTTP authentication is supported.
+
+.. _ha-mt-config:
+
+Multi-Threaded Configuration (HA+MT)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+HA peer communication consists of specialized API commands sent between HA peers.
+Prior to Kea 1.9.7, each peer had to be paired with a local instance of
+:iscman:`kea-ctrl-agent` in order to exchange commands. The agent received HA commands
+via HTTP, communicated via Linux socket with the local peer to carry out the
+command, and then sent the response back to the requesting peer via HTTP. To
+send HA commands, each peer opened its own HTTP client connection to the URL of
+each of its peers.
+
+In Kea 1.9.7 and newer, it is possible to configure HA to use direct
+multi-threaded communication between peers. We refer to this mode as HA+MT.
+With HA+MT enabled, each peer runs its own dedicated, internal HTTP listener
+(i.e. server) which receives and responds to commands directly, thus eliminating
+the need for an agent to carry out HA protocol between peers. In addition, both
+the listener and client components use multi-threading to support multiple,
+concurrent connections between peers. By eliminating the agent and executing
+multiple command exchanges in parallel, HA throughput between peers should
+improve considerably in most situations.
+
+The following parameters have been added to the HA configuration, to support
+HA+MT operation:
+
+- ``enable-multi-threading`` - enables or disables multi-threading HA peer
+ communication (HA+MT). Kea core multi-threading must be enabled for HA+MT to
+ operate. When ``false``, the server relies on :iscman:`kea-ctrl-agent` for
+ communication with its peer, and uses single-threaded HTTP client processing.
+ The default is ``true``.
+
+- ``http-dedicated-listener`` - enables or disables the creation of a dedicated,
+ internal HTTP listener through which the server receives HA messages from its
+ peers. The internal listener replaces the role of :iscman:`kea-ctrl-agent` traffic,
+ allowing peers to send their HA commands directly to each other. The listener
+ listens on the peer's ``url``. When ``false``, the server
+ relies on :iscman:`kea-ctrl-agent`. This parameter has been provided largely for
+ flexibility and testing; running HA+MT without dedicated listeners enabled
+ will substantially limit HA throughput. The default is ``true``.
+
+- ``http-listener-threads`` - indicates the maximum number of threads the
+ dedicated listener should use. A value of ``0`` instructs the server to use the
+ same number of threads that the Kea core is using for DHCP multi-threading.
+ The default is ``0``.
+
+- ``http-client-threads`` - indicates the maximum number of threads that should
+ be used to send HA messages to its peers. A value of ``0`` instructs the server
+ to use the same number of threads that the Kea core is using for DHCP
+ multi-threading. The default is ``0``.
+
+These parameters are grouped together under a map element, ``multi-threading``,
+as illustrated below:
+
+::
+
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "http-dedicated-listener": true,
+ "http-listener-threads": 4,
+ "http-client-threads": 4
+ },
+ "peers": [
+ // This is the configuration of this server instance.
+ {
+ "name": "server1",
+ // This specifies the URL of our server instance.
+ // Since the HA+MT uses a direct connection, the
+ // DHCPv4 server open its own socket. Note that it
+ // must be different than the one used by the CA
+ // (typically 8000). In this example, 8001 is used.
+ "url": "http://192.0.2.1:8001/",
+ // This server is primary. The other one must be
+ // secondary.
+ "role": "primary"
+ },
+ // This is the configuration of our HA peer.
+ {
+ "name": "server2",
+ // This specifies the URL of our server instance.
+ // Since the HA+MT uses a direct connection, the
+ // DHCPv4 server open its own socket. Note that it
+ // must be different than the one used by the CA
+ // (typically 8000). In this example, 8001 is used.
+ "url": "http://192.0.2.2:8001/",
+ // The partner is a secondary. This server is a
+ // primary as specified in the previous "peers"
+ // entry and in "this-server-name" before that.
+ "role": "secondary"
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ]
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+
+In the example above, HA+MT is enabled with four threads for the listener and
+four threads for the client.
+
+.. note::
+
+ It is essential to configure the ports correctly. One common mistake is to
+ configure CA to listen on port 8000 and also configure dedicated listeners on
+ port 8000. In such a configuration, the communication will still work over CA,
+ but it will be slow and the DHCP server will fail to bind sockets.
+ Administrators should ensure that dedicated listeners use a different port
+ (8001 is a suggested alternative); if ports are misconfigured or the ports
+ dedicated to CA are used, the performance bottlenecks caused by the
+ single-threaded nature of CA and the sequential nature of the UNIX socket
+ that connects CA to DHCP servers will nullify any performance gains offered
+ by HA+MT.
+
+.. _ha-parked-packet-limit:
+
+Parked-Packet Limit
+~~~~~~~~~~~~~~~~~~~
+
+Kea servers contain a mechanism by which the response to a client packet may
+be held, pending completion of hook library work. We refer to this as "parking"
+the packet. The HA hook library makes use of this mechanism. When an HA server
+needs to send a lease update to its peer(s) to notify it of the change to the
+lease, it will "park" the client response until the peer acknowledges the lease
+update. At that point, the server will "unpark" the response and send it to the
+client. This applies to client queries which cause lease changes, such as
+DHCPREQUEST for DHCPv4 and Request, Renew, and Rebind for DHCPv6. It does not
+apply to DHPCDISCOVERs (v4) or Solicits (v6).
+
+There is a global parameter, ``parked-packet-limit``, that may be used to limit
+the number of responses that may be parked at any given time. This acts as a
+form of congestion handling and protects the server from being swamped when the
+volume of client queries is outpacing the server's ability to respond. Once the
+limit is reached, the server emits a log and drops any new responses until
+parking spaces are available.
+
+In general, smaller values for the parking lot limit are likely to cause more
+drops but with shorter response times. Larger values are likely to result in
+fewer drops but with longer response times. Currently, the default value for
+``parked-packet-limit`` is 256.
+
+.. warning::
+
+ Using too small a value may result in an unnecessarily high drop rate, while
+ using too large a value may lead to response times that are simply too long
+ to be useful. A value of 0, while allowed, disables the limit altogether, but
+ this is highly discouraged as it may lead to Kea servers becoming
+ unresponsive to clients. Choosing the best value is very site-specific; we
+ recommend users initially leave it at the default value of 256 and observe
+ how the system behaves over time with varying load conditions.
+
+::
+
+ "Dhcp6": {
+ // Limit the number of concurrently parked packets to 128.
+ "parked-packet-limit": 128,
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": { }
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [ {
+ "this-server-name": "server1",
+ ...
+ } ]
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+.. note::
+
+ While ``parked-packet-limit`` is not specifically tied to HA, currently HA
+ is the only ISC hook that employs packet parking.
+
+.. _ha-maintenance:
+
+Controlled Shutdown and Maintenance of DHCP Servers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Having a pair of servers providing High Availability allows for controlled
+shutdown and maintenance of those servers without disrupting the DHCP service.
+For example, an administrator can perform an upgrade of one of the servers while
+the other one continues to respond to DHCP queries. When the first server is
+upgraded and back online, the upgrade can be performed for the second server.
+
+A typical problem reported with early versions of the High Availability hook
+library was that the administrator did not have direct control over the state of
+the DHCP server. Shutting down one of the servers for maintenance did not
+necessarily cause the other server to start responding to all DHCP queries,
+because the failure-detection algorithm described in :ref:`ha-scope-transition`
+requires that the partner not respond for a configured period of time and,
+depending on the configuration, may also require that a number of DHCP requests
+not be responded to for a specified period of time. The maintenance procedure,
+however, requires that the administrator be able to instruct one of the servers
+to instantly start serving all DHCP clients, and the other server to instantly
+stop serving any DHCP clients, so it can be safely shut down.
+
+The maintenance feature of the High Availability hook library addresses this
+situation. The :isccmd:`ha-maintenance-start` command was introduced to allow the
+administrator to put the pairs of the active servers in a state in which one of
+them is responding to all DHCP queries and the other one is awaiting shutdown.
+
+Suppose that the HA setup includes two active servers, ``server1`` and
+``server2``, and the latter needs to be shut down for maintenance.
+The administrator can send the :isccmd:`ha-maintenance-start` command to ``server1``,
+as this is the server which is going to handle the DHCP traffic while the other
+one is offline. ``server1`` responds with an error if its state or the partner's
+state does not allow for a maintenance shutdown: for example, if maintenance is
+not supported for the backup server or if the server is in the ``terminated``
+state. Also, an error is returned if the :isccmd:`ha-maintenance-start` request was
+already sent to the other server.
+
+Upon receiving the :isccmd:`ha-maintenance-start` command, ``server1`` sends the
+:isccmd:`ha-maintenance-notify` command to ``server2`` to put it in the
+``in-maintenance`` state. If ``server2`` confirms, ``server1`` transitions to
+the ``partner-in-maintenance`` state. This is similar to the ``partner-down``
+state, except that in the ``partner-in-maintenance`` state ``server1`` continues
+to send lease updates to ``server2`` until the administrator shuts down
+``server2``. ``server1`` now responds to all DHCP queries.
+
+The administrator can now safely shut down ``server2`` in the ``in-maintenance``
+state and perform any necessary maintenance actions. While ``server2`` is
+offline, ``server1`` will obviously not be able to communicate with its partner,
+so it will immediately transition to the ``partner-down`` state; it will
+continue to respond to all DHCP queries but will no longer send lease updates to
+``server2``. Restarting ``server2`` after the maintenance will trigger normal
+state negotiation, lease-database synchronization, and, ultimately, a transition
+to the normal ``load-balancing`` or ``hot-standby`` state. Maintenance can then
+be performed on ``server1``, after sending the :isccmd:`ha-maintenance-start` command
+to ``server2``.
+
+If the :isccmd:`ha-maintenance-start` command was sent to the server and the server
+has transitioned to the ``partner-in-maintenance`` state, it is possible to
+transition both it and its partner back to their previous states to resume the
+normal operation of the HA pair. This is achieved by sending the
+:isccmd:`ha-maintenance-cancel` command to the server that is in the
+``partner-in-maintenance`` state. However, if the server has already
+transitioned to the ``partner-down`` state as a result of detecting that the
+partner is offline, canceling the maintenance is no longer possible. In that
+case, it is necessary to restart the other server and allow it to complete its
+normal state negotiation process.
+
+If the server has many relationships with different partners, the ``ha-maintenance-start``
+command attempts to transition all of the relationships into the
+``partner-in-maintenance`` state by sending the ``ha-mainteance-notify`` to all
+partner servers. If this step fails for any server an error is returned.
+In that case, send the ``ha-maintenance-cancel`` command to resume normal
+operation and fix the issue.
+
+
+Upgrading From Older HA Versions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To upgrade from an older HA hook library to the current version, the
+administrator must shut down one of the servers and rely on the failover
+mechanism to force the online server to transition to the ``partner-down`` state,
+where it starts serving all DHCP clients. Once the hook library on the first
+server is upgraded to a current version, the :isccmd:`ha-maintenance-start` command
+can be used to upgrade the second server.
+
+In such a case, shut down the server running the old version. Next, send the
+:isccmd:`ha-maintenance-start` command to the server that has been upgraded. This
+server should immediately transition to the ``partner-down`` state as it cannot
+communicate with its offline partner. In the ``partner-down`` state the first
+(upgraded) server will respond to all DHCP requests, allowing the administrator
+to perform the upgrade on the second server.
+
+.. note::
+
+ Do not send the :isccmd:`ha-maintenance-start` command while the server running the
+ old hook library is still online. The server receiving this command will
+ return an error.
+
+
+.. _ha-control-commands:
+
+Control Commands for High Availability
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Even though the HA hook library is designed to automatically resolve issues with
+DHCP service interruptions by redirecting the DHCP traffic to a surviving server
+and synchronizing the lease database as needed, it may be useful for the
+administrator to have more control over both servers' behavior. In particular,
+it may be useful to be able to trigger lease-database synchronization on demand,
+or to manually set the HA scopes that are being served.
+
+The backup server can sometimes be used to handle DHCP traffic if both active
+servers are down. The backup server does not perform the failover function
+automatically; thus, in order to use the backup server to respond to DHCP
+queries, the server administrator must enable this function manually.
+
+The following sections describe commands supported by the HA hook library which
+are available for the administrator.
+
+.. isccmd:: ha-sync
+.. _command-ha-sync:
+
+The ``ha-sync`` Command
+-----------------------
+
+The :isccmd:`ha-sync` command instructs the server to synchronize its local lease
+database with the selected peer. The server fetches all leases from the peer and
+updates any locally stored leases which are older than those fetched. It also
+creates new leases when any of those fetched do not exist in the local database.
+All leases that are not returned by the peer but are in the local database are
+preserved. The database synchronization is unidirectional; only the database on
+the server to which the command has been sent is updated. To synchronize the
+peer's database, a separate :isccmd:`ha-sync` command must be issued to that peer.
+
+Database synchronization may be triggered for both active and backup server
+types. The :isccmd:`ha-sync` command has the following structure (in a DHCPv4 example):
+
+::
+
+ {
+ "command": "ha-sync",
+ "service": [ "dhcp4 "],
+ "arguments": {
+ "server-name": "server2",
+ "max-period": 60
+ }
+ }
+
+When the server receives this command it first disables the DHCP service of the
+server from which it will be fetching leases, by sending the :isccmd:`dhcp-disable`
+command to that server. The ``max-period`` parameter specifies the maximum
+duration (in seconds) for which the DHCP service should be disabled. If the DHCP
+service is successfully disabled, the synchronizing server fetches leases from
+the remote server by issuing one or more :isccmd:`lease4-get-page` commands. When the
+lease-database synchronization is complete, the synchronizing server sends the
+:isccmd:`dhcp-enable` command to the peer to re-enable its DHCP service.
+
+The ``max-period`` value should be sufficiently long to guarantee that it does
+not elapse before the synchronization is completed. Otherwise, the DHCP server
+will automatically enable its DHCP function while the synchronization is still
+in progress. If the DHCP server subsequently allocates any leases during the
+synchronization, those new (or updated) leases will not be fetched by the
+synchronizing server, leading to database inconsistencies.
+
+.. isccmd:: ha-scopes
+.. _command-ha-scopes:
+
+The ``ha-scopes`` Command
+-------------------------
+
+This command allows an administrator to modify the HA scopes being served.
+Consult :ref:`ha-load-balancing-config` and :ref:`ha-hot-standby-config` to
+learn which scopes are available for the different HA modes of operation. The
+:isccmd:`ha-scopes` command has the following structure (in a DHCPv4 example):
+
+::
+
+ {
+ "command": "ha-scopes",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "scopes": [ "HA_server1", "HA_server2" ],
+ "server-name": "server2"
+ }
+ }
+
+This command configures the server to handle traffic from both the "HA_server1"
+and "HA_server2" scopes. To disable all scopes specify an empty list:
+
+::
+
+ {
+ "command": "ha-scopes",
+ "service": [ "dhcp4 "],
+ "arguments": {
+ "scopes": [ ],
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+.. isccmd:: ha-continue
+.. _command-ha-continue:
+
+The ``ha-continue`` Command
+---------------------------
+
+This command is used to resume the operation of the paused HA state machine, as
+described in :ref:`ha-pause-state-machine`. It takes no arguments, so the
+command structure is simply:
+
+::
+
+ {
+ "command": "ha-continue",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "scopes": [ ],
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+.. isccmd:: ha-heartbeat
+.. _command-ha-heartbeat:
+
+The ``ha-heartbeat`` Command
+----------------------------
+
+The :ref:`ha-server-states` section describes how the :isccmd:`ha-heartbeat` command
+is used by a pair of active HA servers to detect one partner's failure. This
+command, however, can also be sent by the system administrator to one or both
+servers to check their HA state. This allows a monitoring system to be deployed
+on the HA enabled servers to periodically check whether they are operational or
+whether any manual intervention is required. The :isccmd:`ha-heartbeat` command takes
+no arguments:
+
+::
+
+ {
+ "command": "ha-heartbeat",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "scopes": [ ],
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+Upon successful communication with the server, a response similar to this should
+be returned:
+
+::
+
+ {
+ "result": 0,
+ "text": "HA peer status returned.",
+ "arguments":
+ {
+ "state": "partner-down",
+ "date-time": "Thu, 07 Nov 2019 08:49:37 GMT",
+ "scopes": [ "server1" ],
+ "unsent-update-count": 123
+ }
+ }
+
+The returned ``state`` value should be one of the values listed in
+:ref:`ha-server-states`. In the example above, the ``partner-down`` state is
+returned, which indicates that the server which responded to the command
+believes that its partner is offline; thus, it is serving all DHCP requests sent
+to the servers. To ensure that the partner is indeed offline, the administrator
+should send the :isccmd:`ha-heartbeat` command to the second server. If sending the
+command fails, e.g. due to an inability to establish a TCP connection to the
+Control Agent, or if the Control Agent reports issues with communication with
+the DHCP server, it is very likely that the server is not running.
+
+The ``date-time`` parameter conveys the server's notion of time.
+
+The ``unsent-update-count`` value is a cumulative count of all unsent lease
+updates since the server was booted; its value is set to 0 when the server is
+started. It is never reset to 0 during the server's operation, even after the
+partner synchronizes the database. It is incremented by the partner sending the
+heartbeat response when it cannot send the lease update. For example, suppose
+the failure is a result of a temporary communication interruption. In that case,
+the partner receiving the ``partner-down`` heartbeat response tracks the value
+changes and can determine, once communication is reestablished, whether there
+are any new lease updates that it did not receive. If the values on both servers
+do not match, it is an indication that the partner should synchronize its lease
+database. A non-zero value itself is not an indication of any present issues
+with lease updates, but a constantly incrementing value is.
+
+The typical response returned by one server when both are
+operational is:
+
+::
+
+ {
+ "result": 0,
+ "text": "HA peer status returned.",
+ "arguments":
+ {
+ "state": "load-balancing",
+ "date-time": "Thu, 07 Nov 2019 08:49:37 GMT",
+ "scopes": [ "server1" ],
+ "unsent-update-count": 0
+ }
+ }
+
+In most cases, the :isccmd:`ha-heartbeat` command should be sent to both HA-enabled
+servers to verify the state of the entire HA setup. In particular, if one of the
+servers indicates that it is in the ``load-balancing`` state, it means that this
+server is operating as if its partner is functional. When a partner goes down,
+it takes some time for the surviving server to realize it. The
+:ref:`ha-scope-transition` section describes the algorithm which the surviving
+server follows before it transitions to the ``partner-down`` state. If the
+:isccmd:`ha-heartbeat` command is sent during the time window between the failure of
+one of the servers and the transition of the surviving server to the
+``partner-down`` state, the response from the surviving server does not reflect
+the failure. Resending the command detects the failure once the surviving server
+has entered the ``partner-down`` state.
+
+.. note:
+
+ Always send the :isccmd:`ha-heartbeat` command to both active HA servers to check
+ the state of the entire HA setup. Sending it to only one of the servers may
+ not reflect issues that just began with one of the servers.
+
+.. isccmd:: ha-status-get
+.. _command-ha-status-get:
+
+The ``status-get`` Command
+--------------------------
+
+:isccmd:`status-get` is a general-purpose command supported by several Kea daemons,
+not only the DHCP servers. However, when sent to a DHCP server with HA enabled,
+it can be used to get insight into the details of the HA-specific server status.
+Not only does the response contain the status information of the server
+receiving this command, but also the information about its partner if it is
+available.
+
+The following is an example response to the :isccmd:`status-get` command, including
+the HA status of two ``load-balancing`` servers:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "",
+ "arguments": {
+ "pid": 1234,
+ "uptime": 3024,
+ "reload": 1111,
+ "high-availability": [
+ {
+ "ha-mode": "load-balancing",
+ "ha-servers": {
+ "local": {
+ "role": "primary",
+ "scopes": [ "server1" ],
+ "state": "load-balancing",
+ "server-name": "server1"
+ },
+ "remote": {
+ "age": 10,
+ "in-touch": true,
+ "role": "secondary",
+ "last-scopes": [ "server2" ],
+ "last-state": "load-balancing",
+ "communication-interrupted": true,
+ "connecting-clients": 2,
+ "unacked-clients": 1,
+ "unacked-clients-left": 2,
+ "analyzed-packets": 8,
+ "server-name": "server2"
+ }
+ }
+ }
+ ],
+ "multi-threading-enabled": true,
+ "thread-pool-size": 4,
+ "packet-queue-size": 64,
+ "packet-queue-statistics": [ 0.2, 0.1, 0.1 ],
+ "sockets": {
+ "status": "ready"
+ }
+ }
+ }
+
+The ``high-availability`` argument is a list which currently comprises only one
+element.
+
+The ``ha-servers`` map contains two structures: ``local`` and ``remote``. The
+former contains the status information of the server which received the command,
+while the latter contains the status information known to the local server about
+the partner. The ``role`` of the partner server is gathered from the local
+configuration file, and thus should always be available. The remaining status
+information, such as ``last-scopes`` and ``last-state``, is not available until
+the local server communicates with the remote by successfully sending the
+:isccmd:`ha-heartbeat` command. If at least one such communication has taken place,
+the returned value of the ``in-touch`` parameter is set to ``true``. By
+examining this value, the command's sender can determine whether the information
+about the remote server is reliable.
+
+The ``last-scopes`` and ``last-state`` parameters contain information about the
+HA scopes served by the partner and its state. This information is gathered
+during the :isccmd:`ha-heartbeat` command exchange, so it may not be accurate if a
+communication problem occurs between the partners and this status information is
+not refreshed. In such a case, it may be useful to send the :isccmd:`status-get`
+command to the partner server directly to check its current state. The ``age``
+parameter specifies the age of the information from the partner, in seconds.
+
+The ``communication-interrupted`` boolean value indicates whether the server
+receiving the :isccmd:`status-get` command (the local server) has been unable to
+communicate with the partner longer than the duration specified as
+``max-response-delay``. In such a situation, the active servers are considered
+to be in the ``communication-interrupted`` state. At this point, the local
+server may start monitoring the DHCP traffic directed to the partner to see if
+the partner is responding to this traffic. More about the failover procedure can
+be found in :ref:`ha-load-balancing-config`.
+
+The ``connecting-clients``, ``unacked-clients``, ``unacked-clients-left``, and
+``analyzed-packets`` parameters were introduced along with the
+``communication-interrupted`` parameter and they convey useful information about
+the state of the DHCP traffic monitoring in the ``communication-interrupted``
+state. Once the server leaves the ``communication-interrupted`` state, these
+parameters are all reset to 0.
+
+These parameters have the following meaning in the ``communication-interrupted``
+state:
+
+- ``connecting-clients`` - this is the number of different clients which have
+ attempted to get a lease from the remote server. These clients are
+ differentiated by their MAC address and client identifier (in DHCPv4) or DUID
+ (in DHCPv6). This number includes "unacked" clients (for which the "secs"
+ field or "elapsed time" value exceeded the ``max-response-delay``).
+
+- ``unacked-clients`` - this is the number of different clients which have been
+ considered "unacked", i.e. the clients which have been trying to get the
+ lease longer than the value of the "secs" field, or for which the
+ "elapsed time" exceeded the ``max-response-delay`` setting.
+
+- ``unacked-clients-left`` - this indicates the number of additional clients
+ which have to be considered "unacked" before the server enters the
+ ``partner-down`` state. This value decreases when the ``unacked-clients``
+ value increases. The local server enters the ``partner-down`` state when this
+ value decreases to 0.
+
+- ``analyzed-packets`` - this is the total number of packets directed to the
+ partner server and analyzed by the local server since entering the
+ communication interrupted state. It includes retransmissions from the same
+ clients.
+
+Monitoring these values helps to predict when the local server will enter the
+``partner-down`` state or to understand why the server has not yet entered this
+state.
+
+The ``ha-mode`` parameter returns the HA mode of operation selected using the
+``mode`` parameter in the configuration file. It can hold one of the following
+values: ``load-balancing``, ``hot-standby``, or ``passive-backup``.
+
+The :isccmd:`status-get` response has the format described above only in the
+``load-balancing`` and ``hot-standby`` modes. In the ``passive-backup`` mode the
+``remote`` map is not included in the response because in this mode there is
+only one active server (local). The response includes no information about the
+status of the backup servers.
+
+.. isccmd:: ha-maintenance-start
+.. _command-ha-maintenance-start:
+
+The ``ha-maintenance-start`` Command
+------------------------------------
+
+This command is used to initiate the transition of the server's partners into the
+``in-maintenance`` state and the transition of the server receiving the command
+into the ``partner-in-maintenance`` state in each HA relationship. See the
+:ref:`ha-maintenance` section for details.
+
+::
+
+ {
+ "command": "ha-maintenance-start",
+ "service": [ "dhcp4" ]
+ }
+
+.. isccmd:: ha-maintenance-cancel
+.. _command-ha-maintenance-cancel:
+
+The ``ha-maintenance-cancel`` Command
+-------------------------------------
+
+This command is used to cancel the maintenance previously initiated using the
+:isccmd:`ha-maintenance-start` command. The server receiving this command will first
+send :isccmd:`ha-maintenance-notify`, with the ``cancel`` flag set to ``true``, to its
+partners. Next, the server reverts from the ``partner-in-maintenance`` state to
+its previous state. See the :ref:`ha-maintenance` section for details.
+
+::
+
+ {
+ "command": "ha-maintenance-cancel",
+ "service": [ "dhcp4" ]
+ }
+
+.. isccmd:: ha-maintenance-notify
+.. _command-ha-maintenance-notify:
+
+The ``ha-maintenance-notify`` Command
+-------------------------------------
+
+This command is sent by the server receiving the :isccmd:`ha-maintenance-start` or the
+:isccmd:`ha-maintenance-cancel` command to its partner, to cause the partner to
+transition to the ``in-maintenance`` state or to revert from this state to a
+previous state. See the :ref:`ha-maintenance` section for details.
+
+::
+
+ {
+ "command": "ha-maintenance-notify",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "cancel": false,
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+.. warning::
+
+ The :isccmd:`ha-maintenance-notify` command is not meant to be used by system
+ administrators. It is used for internal communication between a pair of
+ HA-enabled DHCP servers. Direct use of this command is not supported and may
+ produce unintended consequences.
+
+.. isccmd:: ha-reset
+.. _command-ha-reset:
+
+The ``ha-reset`` Command
+------------------------
+
+This command causes the server to reset its High Availability state machine by
+transitioning it to the ``waiting`` state. A partner in the
+``communication-recovery`` state may send this command to cause the server
+to synchronize its lease database. Database synchronization is required when the
+partner has failed to send all lease database updates after re-establishing
+connection after a temporary connection failure. It is also required when the
+``delayed-updates-limit`` is exceeded, when the server is in the
+``communication-recovery`` state.
+
+A server administrator may send this command to reset a misbehaving state
+machine.
+
+::
+
+ {
+ "command": "ha-reset",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+It elicits the response:
+
+::
+
+ {
+ "result": 0,
+ "text": "HA state machine reset."
+ }
+
+If the server receiving this command is already in the ``waiting`` state, the
+command has no effect.
+
+.. isccmd:: ha-sync-complete-notify
+.. _command-ha-sync-complete-notify:
+
+The ``ha-sync-complete-notify`` Command
+---------------------------------------
+
+A server sends this command to its partner to signal that it has completed
+lease-database synchronization. The partner may enable its DHCP service if it
+can allocate new leases in its current state. The partner does not enable the
+DHCP service in the ``partner-down`` state until it sends a successful :isccmd:`ha-heartbeat`
+test to its partner server. If the connection is still unavailable, the server
+in the ``partner-down`` state enables its own DHCP service to continue
+responding to clients.
+
+::
+
+ {
+ "command": "ha-sync-complete-notify",
+ "service": [ "dhcp4" ],
+ "arguments": {
+ "origin": 2000,
+ "server-name": "server2"
+ }
+ }
+
+The optional ``server-name`` parameter specifies a name of one of the partners belonging
+to the HA relationship this command pertains to. This parameter can be omitted if the
+server receiving this command has only one HA relationship in the configuration.
+
+The ``origin`` parameter is used to select the HA service for which the receiving server should
+enable the DHCP service when it receives this notification. This is the same origin the
+sending server used previously to disable the DHCP service before synchronization.
+
+It elicits the response:
+
+::
+
+ {
+ "result": 0,
+ "text": "Server successfully notified about the synchronization completion."
+ }
+
+.. warning::
+
+ The :isccmd:`ha-sync-complete-notify` command is not meant to be used by system
+ administrators. It is used for internal communication between a pair of
+ HA-enabled DHCP servers. Direct use of this command is not supported and may
+ produce unintended consequences.
+
+
+.. _ha-hub-and-spoke:
+
+Hub and Spoke Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The hub-and-spoke is a common arrangement of the DHCP servers for resiliency. It contains
+one central server and multiple branch servers. The branch servers are the primary servers
+in the ``hot-standby`` mode and respond to the local DHCP traffic in their respective
+locations. The central server acts as a standby server for each branch server.
+It maintains independent state machines with the branch servers, called relationships.
+If one of the branch servers experiences a failure, the central server can take over its
+DHCP traffic. In this case, we say that one of the central server's relationships is in
+the ``partner-down`` state. The remaining relationships may still be in the ``hot-standby``
+state and not actively respond to DHCP traffic. When the branch server becomes active again,
+it synchronizes the lease database with the central server, and the central server becomes
+fully passive again. In rare cases, when multiple branch servers stop, the central server
+takes responsibility for all their traffic (possibly the entire DHCP traffic in the network
+when all branch servers are down). A simple hub-and-spoke arrangement consisting of two
+branch servers and one central server is shown below.
+
+::
+
+
+ +----- Central Server ------+
+ | |
+ +----------+ relationship 1 | +----------+----------+ | relationship 2 +----------+
+ | Server 1 |===================| Server 2 | Server 4 |===================| Server 3 |
+ +----------+ | +----------+----------+ | +----------+
+ | |
+ +---------------------------+
+
+Each branch server's configuration comprises a set of subnets appropriate for the branch
+server. Different branch servers serve different subnets. The central server's configuration
+comprises all subnets of the branch servers so that it can respond to the DHCP traffic
+directed to any of the failing branch servers. The subnets in the central server must be
+grouped into relationships like in the snippet below:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "enp0s8", "enp0s9" ]
+ },
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": {}
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [
+ {
+ "this-server-name": "server2",
+ "mode": "hot-standby",
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "http-dedicated-listener": true,
+ "http-listener-threads": 4,
+ "http-client-threads": 4
+ },
+ "peers": [
+ {
+ "name": "server1",
+ "url": "http://192.168.56.66:8000/",
+ "role": "primary",
+ "auto-failover": true
+ },
+ {
+ "name": "server2",
+ "url": "http://192.168.56.33:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }
+ ]
+ },
+ {
+ "this-server-name": "server4",
+ "mode": "hot-standby",
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "http-dedicated-listener": true,
+ "http-listener-threads": 4,
+ "http-client-threads": 4
+ },
+ "peers": [
+ {
+ "name": "server3",
+ "url": "http://192.168.57.99:8000/",
+ "role": "primary",
+ "auto-failover": true
+ },
+ {
+ "name": "server4",
+ "url": "http://192.168.57.33:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [ { "pool": "2001:db8:1::/80" } ],
+ "interface": "enp0s8",
+ "user-context": {
+ "ha-server-name": "server2"
+ }
+ },
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/64",
+ "pools": [ { "pool": "2001:db8:2::/80" } ],
+ "interface": "enp0s9",
+ "user-context": {
+ "ha-server-name": "server4"
+ }
+ }
+ ]
+ }
+ }
+
+
+
+
+The peer names in the relationships must be unique. The user context for each subnet contains
+the ``ha-server-name`` parameter associating a subnet with a relationship. The ``ha-server-name``
+can be any of the peer names in the relationship. Suppose a relationship contains peer names
+``server1`` and ``server2``. It doesn't matter whether the ``ha-server-name`` is ``server1`` or
+``server2``. In both cases, it associates a subnet with that relationship.
+
+It is not required to specify the ``ha-server-name`` in the branch servers, assuming that the
+branch servers only contain the subnets they serve. Consider the following configuration for
+branch ``server3``:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": [ "enp0s8" ]
+ },
+ "hooks-libraries": [
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
+ "parameters": {}
+ },
+ {
+ "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
+ "parameters": {
+ "high-availability": [
+ {
+ "this-server-name": "server3",
+ "mode": "hot-standby",
+ "multi-threading": {
+ "enable-multi-threading": true,
+ "http-dedicated-listener": true,
+ "http-listener-threads": 4,
+ "http-client-threads": 4
+ },
+ "peers": [
+ {
+ "name": "server3",
+ "url": "http://192.168.57.99:8000/",
+ "role": "primary",
+ "auto-failover": true
+ },
+ {
+ "name": "server4",
+ "url": "http://192.168.57.33:8000/",
+ "role": "standby",
+ "auto-failover": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 2,
+ "subnet": "2001:db8:2::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:2::/80"
+ }
+ ],
+ "interface": "enp0s8",
+ "user-context": {
+ "ha-server-name": "server3"
+ }
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ Even though it is not required to include the ``ha-server-name`` user context parameters in the
+ branch servers, we recommend including them. The servers fetch all leases from the
+ partners during the database synchronization. If the subnets are not explicitly associated with
+ the relationship, the branch server inserts all fetched leases from the central server (including
+ those from other relationships) into its database. Specifying ``ha-server-name`` parameter for
+ each configured subnet in the branch server guarantees that only the leases belonging to its
+ relationship are inserted into the branch server's database.
+
+.. note::
+
+ The peer names in the branch servers must match the peer names in the respective central
+ server's relationships because these names are used for signaling between the HA partners.
diff --git a/doc/sphinx/arm/hooks-host-cache.rst b/doc/sphinx/arm/hooks-host-cache.rst
new file mode 100644
index 0000000..ebf0cd9
--- /dev/null
+++ b/doc/sphinx/arm/hooks-host-cache.rst
@@ -0,0 +1,324 @@
+.. ischooklib:: libdhcp_host_cache.so
+.. _hooks-host-cache:
+
+``libdhcp_host_cache.so``: Host Cache Reservations for Improved Performance
+===========================================================================
+
+Some database backends, such as RADIUS, are slow and may take
+a long time to respond. Since Kea in general is synchronous, backend
+performance directly affects DHCP performance. To minimize the
+impact and improve performance, the Host Cache library provides a way to
+cache information from the database locally. This includes negative
+caching, i.e. the ability to remember that there is no client
+information in the database.
+
+.. note::
+
+ :ischooklib:`libdhcp_host_cache.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or
+ :iscman:`kea-dhcp6` process.
+
+In principle, this hook library can be used with any backend that may
+introduce performance degradation (MySQL, PostgreSQL or RADIUS). Host Cache
+must be loaded for the RADIUS accounting mechanism to work.
+
+The Host Cache hook library is very simple. It takes only one
+optional parameter (``maximum``), which defines the maximum number of hosts
+to be cached. If not specified, the default value of 0 is used, which
+means there is no limit. This hook library can be loaded the same way as
+any other hook library; for example, this configuration could be used:
+
+::
+
+ "Dhcp4": {
+
+ # Your regular DHCPv4 configuration parameters here.
+
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so",
+ "parameters": {
+
+ # Tells Kea to never cache more than 1000 hosts.
+ "maximum": 1000
+
+ }
+ } ],
+ ...
+ }
+
+Once loaded, the Host Cache hook library provides a number of new
+commands which can be used either over the control channel (see
+:ref:`ctrl-channel-client`) or the RESTful API (see
+:ref:`agent-overview`). An example RESTful API client is described in
+:ref:`shell-overview`. The following sections describe the commands
+available.
+
+.. isccmd:: cache-flush
+.. _command-cache-flush:
+
+The ``cache-flush`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command allows removal of a specified number of cached host
+entries. It takes one parameter, which defines the number of hosts to be
+removed. An example usage looks as follows:
+
+::
+
+ {
+ "command": "cache-flush",
+ "arguments": 1000
+ }
+
+This command removes 1000 hosts; to delete *all* cached
+hosts, use :isccmd:`cache-clear` instead. The hosts are stored in FIFO
+(first-in, first-out) order, so the oldest entries are always removed.
+
+.. isccmd:: cache-clear
+.. _command-cache-clear:
+
+The ``cache-clear`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command allows removal of all cached host entries. An example usage
+looks as follows:
+
+::
+
+ {
+ "command": "cache-clear"
+ }
+
+This command removes all hosts. To delete only a certain
+number of cached hosts, please use :isccmd:`cache-flush` instead.
+
+.. isccmd:: cache-size
+.. _command-cache-size:
+
+The ``cache-size`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command returns the number of host entries. An example usage looks
+as follows:
+
+::
+
+ {
+ "command": "cache-size"
+ }
+
+.. isccmd:: cache-write
+.. _command-cache-write:
+
+The ``cache-write`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In general, the cache content is considered a runtime state and the
+server can be shut down or restarted as usual; the cache is then
+repopulated after restart. However, there are some cases when it is
+useful to store the contents of the cache. One such case is RADIUS,
+where the cached hosts also retain additional cached RADIUS attributes;
+there is no easy way to obtain this information again, because renewing
+clients send their packet to the DHCP server directly. Another use case
+is when an administrator wants to restart the server and, for performance reasons,
+wants it to start with a hot (populated) cache.
+
+This command allows writing the contents of the in-memory cache to a
+file on disk. It takes one parameter, which defines the filename. An
+example usage looks as follows:
+
+::
+
+ {
+ "command": "cache-write",
+ "arguments": "/tmp/kea-host-cache.json"
+ }
+
+This causes the contents to be stored in the ``/tmp/kea-host-cache.json``
+file. That file can then be loaded with the :isccmd:`cache-load` command or
+processed by any other tool that is able to understand JSON format.
+
+.. isccmd:: cache-load
+.. _command-cache-load:
+
+The ``cache-load`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+See the previous section for a discussion of use cases where it may be
+useful to write and load contents of the host cache to disk.
+
+This command allows the contents of a file on disk to be loaded into an
+in-memory cache. It takes one parameter, which defines the filename. An
+example usage looks as follows:
+
+::
+
+ {
+ "command": "cache-load",
+ "arguments": "/tmp/kea-host-cache.json"
+ }
+
+This command stores the contents to the ``/tmp/kea-host-cache.json``
+file. That file can then be loaded with the :isccmd:`cache-load` command or
+processed by any other tool that is able to understand JSON format.
+
+.. isccmd:: cache-get
+.. _command-cache-get:
+
+The ``cache-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is similar to :isccmd:`cache-write`, but instead of writing the cache
+contents to disk, it returns the contents to whoever sent the command.
+
+This command allows the contents of a file on disk to be loaded into an
+in-memory cache. It takes one parameter, which defines the filename. An
+example usage looks as follows:
+
+::
+
+ {
+ "command": "cache-get"
+ }
+
+This command returns all the cached hosts; the response
+may be large.
+
+.. isccmd:: cache-get-by-id
+.. _command-cache-get-by-id:
+
+The ``cache-get-by-id`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is similar to :isccmd:`cache-get`, but instead of returning the whole
+content it returns only the entries matching the given identifier.
+
+It takes one parameter, which defines the identifier of wanted cached
+host reservations. An example usage looks as follows:
+
+::
+
+ {
+ "command": "cache-get-by-id",
+ "arguments": {
+ "hw-address": "01:02:03:04:05:06"
+ }
+ }
+
+This command returns all the cached hosts with the given hardware
+address.
+
+.. isccmd:: cache-insert
+.. _command-cache-insert:
+
+The ``cache-insert`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command may be used to manually insert a host into the cache; there
+are very few use cases when this command might be useful. This command
+expects its arguments to follow the usual syntax for specifying host
+reservations (see :ref:`host-reservation-v4` or
+:ref:`host-reservation-v6`), with one difference: the ``subnet-id``
+value must be explicitly specified.
+
+An example command to insert an IPv4 host into the host cache
+looks as follows:
+
+::
+
+ {
+ "command": "cache-insert",
+ "arguments": {
+ "hw-address": "01:02:03:04:05:06",
+ "subnet-id4": 4,
+ "subnet-id6": 0,
+ "ip-address": "192.0.2.100",
+ "hostname": "somehost.example.org",
+ "client-classes4": [ ],
+ "client-classes6": [ ],
+ "option-data4": [ ],
+ "option-data6": [ ],
+ "next-server": "192.0.0.2",
+ "server-hostname": "server-hostname.example.org",
+ "boot-file-name": "bootfile.efi",
+ "host-id": 0
+ }
+ }
+
+An example command to insert an IPv6 host into the host cache
+looks as follows:
+
+::
+
+ {
+ "command": "cache-insert",
+ "arguments": {
+ "hw-address": "01:02:03:04:05:06",
+ "subnet-id4": 0,
+ "subnet-id6": 6,
+ "ip-addresses": [ "2001:db8::cafe:babe" ],
+ "prefixes": [ "2001:db8:dead:beef::/64" ],
+ "hostname": "",
+ "client-classes4": [ ],
+ "client-classes6": [ ],
+ "option-data4": [ ],
+ "option-data6": [ ],
+ "next-server": "0.0.0.0",
+ "server-hostname": "",
+ "boot-file-name": "",
+ "host-id": 0
+ }
+ }
+
+.. isccmd:: cache-remove
+.. _command-cache-remove:
+
+The ``cache-remove`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes it is useful to remove a single entry from the host cache: for
+example, consider a situation where the device is active, Kea has already
+provided configuration, and the host entry is in cache. As a result of
+administrative action (e.g. the customer hasn't paid their bills or has
+been upgraded to better service), the information in the backend database
+(e.g. MySQL or RADIUS) is being updated. However, since the cache is in use,
+Kea does not notice the change as the cached values are used. The
+:isccmd:`cache-remove` command can solve this problem by removing a cached entry
+after administrative changes.
+
+The :isccmd:`cache-remove` command works similarly to the :isccmd:`reservation-get` command.
+It allows querying by two parameters: either ``subnet-id4`` or ``subnet-id6``;
+or ``ip-address`` (may be an IPv4 or IPv6 address), ``hw-address`` (specifies
+a hardware/MAC address), ``duid``, ``circuit-id``, ``client-id``, or ``flex-id``.
+
+An example command to remove an IPv4 host with reserved address
+192.0.2.1 from a subnet with a ``subnet-id`` 123 looks as follows:
+
+::
+
+ {
+ "command": "cache-remove",
+ "arguments": {
+ "ip-address": "192.0.2.1",
+ "subnet-id": 123
+ }
+ }
+
+Another example that removes an IPv6 host identifier by DUID and
+specific ``subnet-id`` is:
+
+::
+
+ {
+ "command": "cache-remove",
+ "arguments": {
+ "duid": "00:01:ab:cd:f0:a1:c2:d3:e4",
+ "subnet-id": 123
+ }
+ }
diff --git a/doc/sphinx/arm/hooks-host-cmds.rst b/doc/sphinx/arm/hooks-host-cmds.rst
new file mode 100644
index 0000000..bcfc54f
--- /dev/null
+++ b/doc/sphinx/arm/hooks-host-cmds.rst
@@ -0,0 +1,1212 @@
+.. ischooklib:: libdhcp_host_cmds.so
+.. _hooks-host-cmds:
+
+``libdhcp_host_cmds.so``: Host Commands
+=======================================
+
+Kea can store host reservations in a database; in many larger deployments,
+it is useful to be able to manage that information while the server is
+running. The Host Commands library provides management commands for adding, querying,
+and deleting host reservations in a safe way without restarting the
+server. In particular, it validates the parameters, so an attempt to
+insert incorrect data - such as adding a host with a conflicting identifier in the
+same subnet - is rejected. Those commands are exposed via the command
+channel (JSON over UNIX sockets) and the Control Agent (JSON over a RESTful
+interface).
+
+.. note::
+
+ :ischooklib:`libdhcp_host_cmds.so` is available as a premium
+ hook library from ISC. Please visit https://www.isc.org/shop/ to purchase
+ the premium hook libraries, or contact us at https://www.isc.org/contact for
+ more information.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6`
+ process.
+
+Currently, the following commands are supported:
+
+- :isccmd:`reservation-add`, which adds a new host reservation.
+
+- :isccmd:`reservation-get`, which returns an existing reservation if specified
+ criteria are matched.
+
+- :isccmd:`reservation-get-all`, which returns all reservations in a specified subnet.
+
+- :isccmd:`reservation-get-page`, a variant of :isccmd:`reservation-get-all` that returns
+ reservations by pages, either all or in a specified subnet.
+
+- :isccmd:`reservation-get-by-address`, which returns all reservations with a
+ specified IP address or a delegated prefix (without a prefix length), and optionally a subnet id.
+
+- :isccmd:`reservation-get-by-hostname`, which returns all reservations with a
+ specified hostname and optionally in a subnet.
+
+- :isccmd:`reservation-get-by-id`, which returns all reservations with a specified
+ identifier (since Kea version 1.9.0).
+
+- :isccmd:`reservation-del`, which attempts to delete a reservation matching specified
+ criteria.
+
+- :isccmd:`reservation-update`, which updates (replaces) an existing reservation
+ matching the given identifiers in a subnet.
+
+To use the commands that change reservation information
+(i.e. :isccmd:`reservation-add`, :isccmd:`reservation-del`, and :isccmd:`reservation-update`) to
+modify data stored in the host database, the hosts database must be specified
+and it must not operate in read-only mode (for details, see the
+``hosts-databases`` descriptions in :ref:`hosts-databases-configuration4` and
+:ref:`hosts-databases-configuration6`). If the ``hosts-databases`` are not
+specified or are running in read-only mode, :ischooklib:`libdhcp_host_cmds.so` will
+load, but any attempts to use :isccmd:`reservation-add`, :isccmd:`reservation-del`, and
+:isccmd:`reservation-update` to modify data in that database will fail.
+
+These commands can also modify hosts from the JSON configuration independently
+from the hosts database. The changes provided in the JSON configuration are
+volatile and can be made permanent by sending the :isccmd:`config-write` command.
+
+For a description of proposed future commands, see the `Control API
+Requirements <https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands>`__
+document.
+
+All host commands use JSON syntax. They can be issued either using the
+control channel (see :ref:`ctrl-channel`) or via the Control Agent (see
+:ref:`kea-ctrl-agent`).
+
+The library can be loaded similarly to other hook libraries. It
+does not take any parameters, and it supports both the DHCPv4 and DHCPv6
+servers.
+
+::
+
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_host_cmds.so"
+ },
+ ...
+ ]
+ }
+
+The ``subnet-id`` Parameter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before examining the individual commands, it is worth discussing the
+parameter ``subnet-id``. Currently this parameter is mandatory for all of the
+commands supplied by this library, with the exception of
+:isccmd:`reservation-get-by-hostname` and :isccmd:`reservation-get-by-address`,
+where it is optional. Since Kea 1.9.0,
+``subnet-id`` is also optional in :isccmd:`reservation-get-page`, and
+it is forbidden in :isccmd:`reservation-get-by-id`.
+
+Reservations can be specified globally, and are not necessarily specific to any
+subnet. When reservations are supplied via the configuration file, the
+ID of the containing subnet (or lack thereof) is implicit in the
+configuration structure. However, when managing reservations using
+host commands, it is necessary to explicitly identify the scope to which
+the reservation belongs. This is done via the ``subnet-id`` parameter.
+For global reservations, use a value of zero (0). For reservations
+scoped to a specific subnet, use that subnet's ID.
+
+On the other hand, when the ``subnet-id`` is not specified in the command
+parameters, it is added to each host in responses. If the ``subnet-id``
+has the unused special value, this means the host entry belongs only
+to the other IP version (i.e. IPv6 in DHCPv4 server or IPv4 in DHCPv6
+server) and this entry is ignored.
+
+The ``operation-target`` Parameter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Most host commands accept the ``operation-target`` parameter that selects
+the host data source. The commands may process data from the server
+configuration (i.e., memory operation target), a database (database target),
+or both of them (all sources). The operation target parameter is optional.
+By default, the commands that only read the data use all data sources
+(memory and database); the commands that modify the state (i.e., :isccmd:`reservation-add`,
+:isccmd:`reservation-del`, and :isccmd:`reservation-update`) only use the
+database target.
+
+The ``operation-target`` parameter accepts the following values:
+
+- ``memory`` - query or update the runtime server configuration.
+- ``database`` - query or update host database(s).
+- ``all`` - query or update both runtime configuration and host database(s).
+- ``default`` - query or update a default host data source - it is command specific.
+
+.. isccmd:: reservation-add
+.. _command-reservation-add:
+
+The ``reservation-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-add` allows for the insertion of a new host. It takes a
+set of arguments that vary depending on the nature of the host
+reservation. Any parameters allowed in the configuration file that
+pertain to host reservation are permitted here. For details regarding
+IPv4 reservations, see :ref:`host-reservation-v4`; for IPv6 reservations, see
+:ref:`host-reservation-v6`. The ``subnet-id`` is mandatory. Use a
+value of zero (0) to add a global reservation, or the ID of the subnet
+to which the reservation should be added. The command can be as simple as having
+only the two mandatory entries:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-add",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "hw-address": "1a:1b:1c:1d:1e:1f"
+ }
+ }
+ }
+
+In that case, however, it does not assign any resources to the host. An IPv4
+address can be assigned like so:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-add",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "ip-address": "192.0.2.202"
+ }
+ }
+ }
+
+It can also take many more parameters, for example:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-add",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "client-id": "01:0a:0b:0c:0d:0e:0f",
+ "ip-address": "192.0.2.205",
+ "next-server": "192.0.2.1",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "10.1.1.202,10.1.1.203"
+ }
+ ],
+ "client-classes": [ "special_snowflake", "office" ]
+ }
+ }
+ }
+
+Here is an example of a complex IPv6 reservation:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-add",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "duid": "01:02:03:04:05:06:07:08:09:0A",
+ "ip-addresses": [ "2001:db8:1:cafe::1" ],
+ "prefixes": [ "2001:db8:2:abcd::/64" ],
+ "hostname": "foo.example.com",
+ "option-data": [
+ {
+ "name": "vendor-opts",
+ "data": "4491"
+ },
+ {
+ "name": "tftp-servers",
+ "space": "vendor-4491",
+ "data": "3000:1::234"
+ }
+ ]
+ }
+ }
+ }
+
+The command accepts the ``operation-target`` argument. By default, it adds the
+reservation to the hosts database only.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-add",
+ "arguments": {
+ "reservation": {},
+ "operation-target": "all"
+ }
+ }
+
+The command returns a status that indicates either success (result 0)
+or failure (result 1). A failed command always includes a text parameter
+that explains the cause of the failure. Here's an example of a successful
+addition:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "Host added."
+ }
+
+And here's an example of a failure:
+
+.. code-block:: json
+
+ {
+ "result": 1,
+ "text": "Mandatory 'subnet-id' parameter missing."
+ }
+
+
+As :isccmd:`reservation-add` is expected to store the host, the ``hosts-databases``
+parameter must be specified in the configuration, and databases must not
+run in read-only mode.
+
+.. isccmd:: reservation-get
+.. _command-reservation-get:
+
+The ``reservation-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get` can be used to query the host database and retrieve
+existing reservations. This command supports two types of parameters:
+(``subnet-id``, ``address``) or (``subnet-id``, ``identifier-type``,
+``identifier``). The first type of query is used when the address (either
+IPv4 or IPv6) is known, but the details of the reservation are not. One
+common use for this type of query is to find out whether a given
+address is reserved. The second query uses identifiers. For
+maximum flexibility, Kea stores the host identifying information as a
+pair of values: the type and the actual identifier. Currently supported
+identifiers are ``"hw-address"``, ``"duid"``, ``"circuit-id"``, ``"client-id"``, and
+``"flex-id"``. The ``subnet-id`` is mandatory. Use a value
+of zero (0) to fetch a global reservation, or the ID of the subnet to
+which the reservation belongs.
+
+An example command for getting a host reservation by a (``subnet-id``,
+``address``) pair looks as follows:
+
+::
+
+ {
+ "command": "reservation-get",
+ "arguments": {
+ "subnet-id": 1,
+ "ip-address": "192.0.2.202"
+ }
+ }
+
+An example query by (``subnet-id``, ``identifier-type``, ``identifier``) looks as
+follows:
+
+::
+
+ {
+ "command": "reservation-get",
+ "arguments": {
+ "subnet-id": 4,
+ "identifier-type": "hw-address",
+ "identifier": "01:02:03:04:05:06"
+ }
+ }
+
+The command accepts the ``operation-target`` argument. By default, it gets the
+reservation from both JSON configuration and the hosts database.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-get",
+ "arguments": {
+ "subnet-id": 1,
+ "ip-address": "192.0.2.202",
+ "operation-target": "alternate"
+ }
+ }
+
+Command :isccmd:`reservation-get` typically returns the result 0 when a query was
+conducted properly. In particular, 0 is returned when the host was not
+found. If the query was successful, the host parameters are
+returned. An example of a query that did not find the host looks as
+follows:
+
+::
+
+ { "result": 0, "text": "Host not found." }
+
+Here's an example of a result returned when the host was found successfully:
+
+::
+
+ {
+ "arguments": {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [
+
+ ],
+ "hostname": "somehost.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.100",
+ "next-server": "192.0.0.2",
+ "option-data": [
+
+ ],
+ "server-hostname": "server-hostname.example.org",
+ "subnet-id": 4
+ },
+ "result": 0,
+ "text": "Host found."
+ }
+
+An example result returned when the query was malformed might look like this:
+
+::
+
+ { "result": 1, "text": "No 'ip-address' provided and 'identifier-type' is either missing or not a string." }
+
+.. isccmd:: reservation-get-all
+.. _command-reservation-get-all:
+
+The ``reservation-get-all`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get-all` can be used to query the host database and
+retrieve all reservations in a specified subnet. This command uses
+parameters providing the mandatory ``subnet-id``. Global host reservations
+can be retrieved by using a ``subnet-id`` value of zero (0).
+
+For instance, retrieving host reservations for the subnet 1:
+
+::
+
+ {
+ "command": "reservation-get-all",
+ "arguments": {
+ "subnet-id": 1
+ }
+ }
+
+returns some IPv4 hosts:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "somehost.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.100",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org",
+ "subnet-id": 1
+ },
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "otherhost.example.org",
+ "hw-address": "01:02:03:04:05:ff",
+ "ip-address": "192.0.2.200",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org",
+ "subnet-id": 1
+ },
+ ...
+ ]
+ },
+ "result": 0,
+ "text": "72 IPv4 host(s) found."
+ }
+
+The response returned by :isccmd:`reservation-get-all` can be very long. The
+DHCP server does not handle DHCP traffic while preparing a response to
+:isccmd:`reservation-get-all`, so if there are many reservations in a subnet, this
+may be disruptive; use with caution. For larger deployments, please
+consider using :isccmd:`reservation-get-page` instead.
+
+The command accepts the ``operation-target`` argument. By default, it gets the
+reservation from both JSON configuration and the hosts database.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-get-all",
+ "arguments": {
+ "subnet-id": 1,
+ "operation-target": "alternate"
+ }
+ }
+
+For more information, see :ref:`command-reservation-get-all`.
+
+.. isccmd:: reservation-get-page
+.. _command-reservation-get-page:
+
+The ``reservation-get-page`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get-page` can be used to query the host database and
+retrieve all reservations in a specified subnet, by pages. This command
+uses parameters providing the mandatory ``subnet-id``. Use a value of zero
+(0) to fetch global reservations. The second mandatory parameter is the
+page size limit. The optional ``source-index`` and ``from-host-id`` parameters, both
+of which default to 0, are used to chain page queries.
+Since Kea version 1.9.0, the ``subnet-id`` parameter is optional.
+
+The usage of the ``from`` and ``source-index`` parameters requires additional
+explanation. For the first call, those parameters should not be specified
+(or should be specified as zeros). For any follow-up calls, they should be set to
+the values returned in previous calls, in a next map holding ``from`` and
+``source-index`` values. Subsequent calls should be issued until all
+reservations are returned. The end is reached once the returned list is
+empty, the count is 0, no next map is present, and result status 3 (empty) is
+returned.
+
+.. note::
+
+ The ``from`` and ``source-index`` parameters reflect the internal state of
+ the search. There is no need to understand what they represent; it is
+ simply a value that should be copied from one response to the
+ next query. However, for those who are curious, the ``from`` field represents a
+ 64-bit representation of the host identifier used by a host backend. The
+ ``source-index`` is an internal representation of multiple host
+ backends: 0 is used to represent hosts defined in a configuration
+ file, and 1 represents the first database backend. In some uncommon cases
+ there may be more than one database backend configured, so
+ potentially there may be a 2. In any case, Kea iterates over all
+ backends configured.
+
+For instance, retrieving host reservations for the subnet 1 and
+requesting the first page can be done by:
+
+::
+
+ {
+ "command": "reservation-get-page",
+ "arguments": {
+ "subnet-id": 1,
+ "limit": 10
+ }
+ }
+
+Since this is the first call, ``source-index`` and ``from`` should not be
+specified. They are set to their zero default values.
+
+Some hosts are returned with information to get the next page:
+
+::
+
+ {
+ "arguments": {
+ "count": 72,
+ "hosts": [
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "somehost.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.100",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org"
+ },
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "otherhost.example.org",
+ "hw-address": "01:02:03:04:05:ff",
+ "ip-address": "192.0.2.200",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org"
+ },
+ ...
+ ],
+ "next": {
+ "from": 1234567,
+ "source-index": 1
+ }
+ },
+ "result": 0,
+ "text": "72 IPv4 host(s) found."
+ }
+
+Note that the ``from`` and ``source-index`` fields were specified in the response in
+the next map. Those two must be copied to the next command, so Kea
+continues from the place where the last command finished. To get the
+next page the following command can be sent:
+
+::
+
+ {
+ "command": "reservation-get-page",
+ "arguments": {
+ "subnet-id": 1,
+ "source-index": 1,
+ "from": 1234567,
+ "limit": 10
+ }
+ }
+
+The response will contain a list of hosts with updated ``source-index``
+and ``from`` fields. Continue calling the command until the last
+page is received. Its response will look like this:
+
+.. code-block:: json
+
+ {
+ "arguments": {
+ "count": 0,
+ "hosts": [ ]
+ },
+ "result": 3,
+ "text": "0 IPv4 host(s) found."
+ }
+
+The command doesn't accept the ``operation-target`` argument.
+
+This command is more complex than :isccmd:`reservation-get-all`, but lets
+users retrieve larger host reservations lists in smaller chunks. For
+small deployments with few reservations, it is easier to use
+:isccmd:`reservation-get-all`.
+
+.. isccmd:: reservation-get-by-address
+.. _command-reservation-get-by-address:
+
+The ``reservation-get-by-address`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get-by-address` can be used to query the host database and
+retrieve all reservations for given IP address or a delegated prefix (without
+a prefix length) in a specified subnet or in all subnets. This command uses
+parameters providing the mandatory ``ip-address`` and the optional ``subnet-id``
+and ``operation-target``.
+
+For instance, retrieving host reservations for the IPv4 address "192.0.200.181"
+in the subnet 1:
+
+::
+
+ {
+ "command": "reservation-get-by-address",
+ "arguments": {
+ "ip-address": "192.0.200.181",
+ "subnet-id": 1
+ },
+ "service": [
+ "dhcp4"
+ ]
+ }
+
+can return two IPv4 hosts:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": "",
+ "client-classes": [],
+ "hostname": "",
+ "hw-address": "99:99:99:99:99:01",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 1
+ },
+ {
+ "boot-file-name": "",
+ "circuit-id": "1234",
+ "client-classes": [],
+ "hostname": "",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 1
+ }
+ ]
+ },
+ "result": 0,
+ "text": "2 IPv4 host(s) found."
+ }
+
+To search for all reservations in all subnets simply skip the ``subnet-id`` parameter:
+
+::
+
+ {
+ "command": "reservation-get-by-address",
+ "arguments": {
+ "ip-address": "192.0.200.181"
+ },
+ "service": [
+ "dhcp4"
+ ]
+ }
+
+An example response can be:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": "",
+ "client-classes": [],
+ "hostname": "",
+ "hw-address": "99:99:99:99:99:01",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 1
+ },
+ {
+ "boot-file-name": "",
+ "circuit-id": "1234",
+ "client-classes": [],
+ "hostname": "",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 1
+ },
+ {
+ "boot-file-name": "",
+ "client-classes": [],
+ "hostname": "",
+ "hw-address": "99:99:99:99:99:02",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 0
+ },
+ {
+ "boot-file-name": "",
+ "client-classes": [],
+ "hostname": "",
+ "hw-address": "99:99:99:99:99:03",
+ "ip-address": "192.0.200.181",
+ "next-server": "0.0.0.0",
+ "option-data": [],
+ "server-hostname": "",
+ "subnet-id": 2
+ }
+ ]
+ },
+ "result": 0,
+ "text": "4 IPv4 host(s) found."
+ }
+
+When using the command for retrieving DHCP6 host reservations, one can provide
+either an IPv6 address or a delegated prefix as the ``ip-address`` parameter.
+Please notice that this command does not take prefix length as a parameter in the
+current implementation. That's why searching by an IP address ``2001:db8:2:cafe::``
+can return host reservations having delegated prefixes matching this search with
+different lengths. For example: ``2001:db8:2:cafe::/63``, ``2001:db8:2:cafe::/64`` etc.
+Please consider the example below:
+
+::
+
+ {
+ "command": "reservation-get-by-address",
+ "arguments": {
+ "ip-address": "2001:db8:2:cafa::"
+ },
+ "service": [
+ "dhcp6"
+ ]
+ }
+
+Response:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "client-classes": [],
+ "duid": "01:02:03:04:05:06:07:88:98:fa",
+ "hostname": "foo.example.com",
+ "ip-addresses": [
+ "2001:db8:1:cafe::2"
+ ],
+ "option-data": [],
+ "prefixes": [
+ "2001:db8:2:abcd::/64",
+ "2001:db8:2:cafa::/63"
+ ],
+ "subnet-id": 8
+ },
+ {
+ "client-classes": [],
+ "duid": "01:02:03:04:05:06:07:88:98:fb",
+ "hostname": "foo.example.com",
+ "ip-addresses": [
+ "2001:db8:1:cafe::2"
+ ],
+ "option-data": [],
+ "prefixes": [
+ "2001:db8:2:abcd::/64",
+ "2001:db8:2:cafa::/64"
+ ],
+ "subnet-id": 8
+ }
+ ]
+ },
+ "result": 0,
+ "text": "2 IPv6 host(s) found."
+ }
+
+The command accepts the ``operation-target`` argument. By default, it gets the
+reservation from both JSON configuration and the hosts database.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-get-by-address",
+ "arguments": {
+ "ip-address": "192.0.200.181",
+ "subnet-id": 1,
+ "operation-target": "alternate"
+ },
+ "service": [
+ "dhcp4"
+ ]
+ }
+
+.. note::
+
+ This command is useful in specific cases. By default, having more than
+ one host reservation for the same IP address in a given subnet is not allowed,
+ as explained in the
+ :ref:`Multiple Reservations for the Same IPv4 <multiple-reservations-same-ip4>`
+ or in the
+ :ref:`Multiple Reservations for the Same IPv6 <multiple-reservations-same-ip6>`.
+ That's why this command comes in handy
+ when the ``ip-reservations-unique`` boolean parameter is set to ``false``.
+ Other use case of this command is having overlapping subnets and having
+ the same IP address reservation (but with different identifier) in different
+ subnets.
+
+.. isccmd:: reservation-get-by-hostname
+.. _command-reservation-get-by-hostname:
+
+The ``reservation-get-by-hostname`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get-by-hostname` can be used to query the host database and
+retrieve all reservations with a specified hostname or in
+a specified subnet. This command uses parameters providing the mandatory
+``hostname`` and the optional ``subnet-id``. Global host reservations
+can be retrieved by using a ``subnet-id`` value of zero (0).
+Hostname matching is case-insensitive.
+
+For instance, retrieving host reservations for "foobar" in the subnet 1:
+
+::
+
+ {
+ "command": "reservation-get-by-hostname",
+ "arguments": {
+ "hostname": "foobar.example.org",
+ "subnet-id": 1
+ }
+ }
+
+returns some IPv4 hosts:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "foobar.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.100",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org"
+ },
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "foobar.example.org",
+ "hw-address": "01:02:03:04:05:ff",
+ "ip-address": "192.0.2.200",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org"
+ },
+ ...
+ ]
+ },
+ "result": 0,
+ "text": "5 IPv4 host(s) found."
+ }
+
+The response returned by :isccmd:`reservation-get-by-hostname` can be long,
+particularly when responses are not limited to a subnet.
+
+The command accepts the ``operation-target`` argument. By default, it gets the
+reservation from both JSON configuration and the hosts database.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-get-by-hostname",
+ "arguments": {
+ "hostname": "foobar.example.org",
+ "subnet-id": 1,
+ "operation-target": "alternate"
+ }
+ }
+
+For more information, see :ref:`command-reservation-get-by-hostname`.
+
+.. note::
+
+ When using MySQL as the host backend, this command relies on the fact
+ that the hostname column in the hosts table uses a case-insensitive
+ collation, as explained in the :ref:`mysql-database` section of
+ :ref:`admin`.
+
+.. isccmd:: reservation-get-by-id
+.. _command-reservation-get-by-id:
+
+The ``reservation-get-by-id`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-get-by-id` can be used to query the host database and
+retrieve all reservations with a specified identifier (``identifier-type``
+and ``identifier`` parameters), independently of subnets. The syntax for
+parameters is the same as for :isccmd:`reservation-get`.
+The ``subnet-id`` parameter cannot be used, to avoid confusion.
+This command is available since Kea version 1.9.0.
+
+For instance, retrieving host reservations for the 01:02:03:04:05:06 MAC
+address:
+
+::
+
+ {
+ "command": "reservation-get-by-id",
+ "arguments": {
+ "identifier-type": "hw-address",
+ "identifier": "01:02:03:04:05:06"
+ }
+ }
+
+returns some IPv4 hosts:
+
+::
+
+ {
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "foo.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.100",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org",
+ "subnet-id": 123
+ },
+ {
+ "boot-file-name": "bootfile.efi",
+ "client-classes": [ ],
+ "hostname": "bar.example.org",
+ "hw-address": "01:02:03:04:05:06",
+ "ip-address": "192.0.2.200",
+ "next-server": "192.0.0.2",
+ "option-data": [ ],
+ "server-hostname": "server-hostname.example.org",
+ "subnet-id": 345
+ },
+ ...
+ ]
+ },
+ "result": 0,
+ "text": "5 IPv4 host(s) found."
+ }
+
+The response returned by :isccmd:`reservation-get-by-id` can be long,
+particularly when responses are not limited to a subnet.
+
+The command accepts the ``operation-target`` argument. By default, it gets the
+reservation from both JSON configuration and the hosts database.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-get-by-id",
+ "arguments": {
+ "identifier-type": "hw-address",
+ "identifier": "01:02:03:04:05:06",
+ "operation-target": "alternate"
+ }
+ }
+
+For more information, see :ref:`command-reservation-get-by-id`.
+
+.. isccmd:: reservation-del
+.. _command-reservation-del:
+
+The ``reservation-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-del` can be used to delete a reservation from the host
+database and/or JSON configuration. This command supports two types of parameters:
+(``subnet-id``, ``address``) or (``subnet-id``, ``identifier-type``, ``identifier``). The
+first type of query is used when the address (either IPv4 or IPv6) is
+known, but the details of the reservation are not. One common use for
+this type of query is to remove a reservation (e.g. a specific
+address should no longer be reserved). The second query uses identifiers.
+For maximum flexibility, Kea stores the host identifying information as
+a pair of values: the type and the actual identifier. Currently supported
+identifiers are ``"hw-address"``, ``"duid"``, ``"circuit-id"``, ``"client-id"``, and
+``"flex-id"``. The ``subnet-id`` is mandatory. Use a value
+of zero (0) to delete a global reservation, or the ID of the subnet from
+which the reservation should be deleted.
+
+An example command for deleting a host reservation by (``subnet-id``,
+``address``) pair looks as follows:
+
+::
+
+ {
+ "command": "reservation-del",
+ "arguments": {
+ "subnet-id": 1,
+ "ip-address": "192.0.2.202"
+ }
+ }
+
+An example deletion by (``subnet-id``, ``identifier-type``, ``identifier``) looks as
+follows:
+
+::
+
+ {
+ "command": "reservation-del",
+ "arguments": {
+ "subnet-id": 4,
+ "identifier-type": "hw-address",
+ "identifier": "01:02:03:04:05:06"
+ }
+ }
+
+Command :isccmd:`reservation-del` returns a result of 0 when the host deletion was
+successful, or 1 if it failed. Descriptive text is provided in the event of
+an error. Here are some examples of possible results:
+
+::
+
+ {
+ "result": 1,
+ "text": "Host not deleted (not found)."
+ }
+
+or
+
+::
+
+ {
+ "result": 0,
+ "text": "Host deleted."
+ }
+
+or
+
+::
+
+ {
+ "result": 1,
+ "text": "Unable to delete a host because there is no hosts-database configured."
+ }
+
+The command accepts the ``operation-target`` argument. By default, it removes
+the reservation from the hosts database only.
+
+.. code-block:: json
+
+ {
+ "command": "reservation-del",
+ "arguments": {
+ "subnet-id": 4,
+ "identifier-type": "hw-address",
+ "identifier": "01:02:03:04:05:06",
+ "operation-target": "primary"
+ }
+ }
+
+.. isccmd:: reservation-update
+.. _command-reservation-update:
+
+The ``reservation-update`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`reservation-update` allows for the update of an existing host. It takes the
+same set of arguments as :isccmd:`reservation-add`, and just as well,
+requires a host identifier and a subnet ID to identify the host that is being
+updated. The command can be as simple as having only the two mandatory entries:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-update",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "hw-address": "1a:1b:1c:1d:1e:1f"
+ }
+ }
+ }
+
+In that case, however, it does not assign any resources to the host. An IPv4
+address can be assigned like so:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-update",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "ip-address": "192.0.2.202"
+ }
+ }
+ }
+
+It can also take many more parameters, for example:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-update",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "client-id": "01:0a:0b:0c:0d:0e:0f",
+ "ip-address": "192.0.2.205",
+ "next-server": "192.0.2.1",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null",
+ "option-data": [
+ {
+ "name": "domain-name-servers",
+ "data": "10.1.1.202,10.1.1.203"
+ }
+ ],
+ "client-classes": [
+ "office",
+ "special_snowflake"
+ ]
+ }
+ }
+ }
+
+Here is an example of a complex IPv6 reservation update:
+
+.. code-block:: json
+
+ {
+ "command": "reservation-update",
+ "arguments": {
+ "reservation": {
+ "subnet-id": 1,
+ "duid": "01:02:03:04:05:06:07:08:09:0A",
+ "ip-addresses": [
+ "2001:db8:1:cafe::1"
+ ],
+ "prefixes": [
+ "2001:db8:2:abcd::/64"
+ ],
+ "hostname": "foo.example.com",
+ "option-data": [
+ {
+ "name": "vendor-opts",
+ "data": "4491"
+ },
+ {
+ "name": "tftp-servers",
+ "space": "vendor-4491",
+ "data": "3000:1::234"
+ }
+ ]
+ }
+ }
+ }
+
+The command returns a status that indicates either success (result ``0``) or
+failure (result ``1``) and a text parameter that confirms success or explains
+the cause of the failure. Here's an example of a successful update:
+
+.. code-block:: json
+
+ {
+ "result": 0,
+ "text": "Host updated."
+ }
+
+And here's an example of a failure:
+
+.. code-block:: json
+
+ {
+ "result": 1,
+ "text": "Mandatory 'subnet-id' parameter missing."
+ }
+
+The command accepts the ``operation-target`` argument. By default, it adds the
+reservation to the hosts database only. As :isccmd:`reservation-update` is expected
+to store the host, the ``hosts-databases`` parameter must be specified in the
+configuration, and databases must not run in read-only mode if the operation
+target is not the JSON configuration.
+
+As with other update and set commands, this command overwrites all the contents
+of the entry. If the host previously had a resource assigned to it, and the
+:isccmd:`reservation-update` command is missing the resource, it is deleted from the
+database. If an incremental update of the host is desired, then this can be
+achieved by doing a :isccmd:`reservation-get-by-id` to get the current state of the
+host, picking the host out of the response, modifying it to the required
+outcome, and then issuing the :isccmd:`reservation-update` command with the resulting
+host attached.
+
+.. _hooks-host-cmds-general-mentions:
+
+General Mentions
+~~~~~~~~~~~~~~~~
+
+.. note::
+
+ The host cache and RADIUS hook libraries are two host backends that do not
+ respond to commands that return a collection of host reservations, such as
+ :isccmd:`reservation-get-all`. Commands returning one host entry or dedicated host
+ cache commands should be used instead.
diff --git a/doc/sphinx/arm/hooks-lease-cmds.rst b/doc/sphinx/arm/hooks-lease-cmds.rst
new file mode 100644
index 0000000..61ee755
--- /dev/null
+++ b/doc/sphinx/arm/hooks-lease-cmds.rst
@@ -0,0 +1,1073 @@
+.. ischooklib:: libdhcp_lease_cmds.so
+.. _hooks-lease-cmds:
+
+``libdhcp_lease_cmds.so``: Lease Commands for Easier Lease Management
+=====================================================================
+
+Kea allows users to store lease information in several
+backends (memfile, MySQL, and PostgreSQL), and the Lease Commands library provides an
+interface that can manipulate leases in a unified, safe way.
+In particular, it allows things that were previously impossible: lease
+manipulation in memfile while Kea is running, sanity check changes,
+lease existence checks, and removal of all leases belonging to a
+specific subnet. The hook library can also catch more obscure errors, like an attempt
+to add a lease with a ``subnet-id`` that does not exist in the
+configuration, or configuring a lease to use an address that is outside
+of the subnet to which it is supposed to belong. The library also
+provides a non-programmatic way to manage user contexts associated with
+leases.
+
+.. note::
+
+ :ischooklib:`libdhcp_lease_cmds.so` is part of the open source code and is
+ available to every Kea user.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or the
+ :iscman:`kea-dhcp6` process.
+
+There are many situations where an administrative command may be useful;
+for example, during migration between servers or different vendors, when
+a certain network is being retired, or when a device has been
+disconnected and the system administrator knows that it will not be coming
+back. The ``get`` queries may be useful for automating certain management
+and monitoring tasks, and they can also act as preparatory steps for lease
+updates and removals.
+
+This library provides the following commands:
+
+- :isccmd:`lease4-add` - adds a new IPv4 lease.
+
+- :isccmd:`lease6-add` - adds a new IPv6 lease.
+
+- :isccmd:`lease6-bulk-apply` - creates, updates, and/or deletes multiple
+ IPv6 leases in a single transaction.
+
+- :isccmd:`lease4-get` - checks whether an IPv4 lease with the specified
+ parameters exists and returns it if it does.
+
+- :isccmd:`lease6-get` - checks whether an IPv6 lease with the specified
+ parameters exists and returns it if it does.
+
+- :isccmd:`lease4-get-all` - returns all IPv4 leases or all IPv4 leases for
+ the specified subnets.
+
+- :isccmd:`lease6-get-all` - returns all IPv6 leases or all IPv6 leases for
+ the specified subnets.
+
+- :isccmd:`lease4-get-page` - returns a set ("page") of leases from the list
+ of all IPv4 leases in the database. By iterating through the pages it
+ is possible to retrieve all the leases.
+
+- :isccmd:`lease6-get-page` - returns a set ("page") of leases from the list
+ of all IPv6 leases in the database. By iterating through the pages it
+ is possible to retrieve all the leases.
+
+- :isccmd:`lease4-get-by-hw-address` - returns all IPv4 leases with the specified
+ hardware address.
+
+- :isccmd:`lease4-get-by-client-id` - returns all IPv4 leases with the specified
+ ``client-id``.
+
+- :isccmd:`lease6-get-by-duid` - returns all IPv6 leases with the specified DUID.
+
+- :isccmd:`lease4-get-by-hostname` - returns all IPv4 leases with the specified
+ hostname.
+
+- :isccmd:`lease6-get-by-hostname` - returns all IPv6 leases with the specified
+ hostname.
+
+- :isccmd:`lease4-del` - deletes an IPv4 lease with the specified parameters.
+
+- :isccmd:`lease6-del` - deletes an IPv6 lease with the specified parameters.
+
+- :isccmd:`lease4-update` - updates (replaces) an existing IPv4 lease.
+
+- :isccmd:`lease6-update` - updates (replaces) an existing IPv6 lease.
+
+- :isccmd:`lease4-wipe` - removes all leases from a specific IPv4 subnet or
+ from all subnets.
+
+- :isccmd:`lease6-wipe` - removes all leases from a specific IPv6 subnet or
+ from all subnets.
+
+- :isccmd:`lease4-resend-ddns` - resends a request to update DNS entries for
+ an existing lease.
+
+- :isccmd:`lease6-resend-ddns` - resends a request to update DNS entries for
+ an existing lease.
+
+- :isccmd:`lease4-write` - writes the IPv4 memfile lease database into a file.
+
+- :isccmd:`lease6-write` - writes the IPv6 memfile lease database into a file.
+
+All commands use JSON syntax and can be issued either using the control
+channel (see :ref:`ctrl-channel`) or Control Agent (see
+:ref:`kea-ctrl-agent`).
+
+The library can be loaded in the same way as other hook libraries, and
+it does not take any parameters. It supports both the DHCPv4 and DHCPv6
+servers.
+
+::
+
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_lease_cmds.so"
+ },
+ ...
+ ]
+ }
+
+.. isccmd:: lease4-add
+.. _command-lease4-add:
+
+.. isccmd:: lease6-add
+.. _command-lease6-add:
+
+The ``lease4-add``, ``lease6-add`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`lease4-add` and
+:isccmd:`lease6-add` commands allow a new lease
+to be created. Typically Kea creates a lease when it first sees a new
+device; however, sometimes it may be convenient to create the lease
+manually. The :isccmd:`lease4-add` command requires at least two parameters:
+an IPv4 address and an identifier, i.e. hardware (MAC) address. A third
+parameter, ``subnet-id``, is optional. If the ``subnet-id`` is not specified or
+the specified value is 0, Kea tries to determine the value by running
+a subnet-selection procedure. If specified, however, its value must
+match the existing subnet. The simplest successful call might look as
+follows:
+
+::
+
+ {
+ "command": "lease4-add",
+ "arguments": {
+ "ip-address": "192.0.2.202",
+ "hw-address": "1a:1b:1c:1d:1e:1f"
+ }
+ }
+
+The :isccmd:`lease6-add` command requires three parameters: an IPv6 address,
+an IAID value (identity association identifier, a value sent by
+clients), and a DUID. As with :isccmd:`lease4-add`, the ``subnet-id`` parameter is
+optional. If the ``subnet-id`` is not specified or the provided value is 0,
+Kea tries to determine the value by running a subnet-selection
+procedure. If specified, however, its value must match the existing
+subnet. For example:
+
+::
+
+ {
+ "command": "lease6-add",
+ "arguments": {
+ "subnet-id": 66,
+ "ip-address": "2001:db8::3",
+ "duid": "1a:1b:1c:1d:1e:1f:20:21:22:23:24",
+ "iaid": 1234
+ }
+ }
+
+The :isccmd:`lease6-add` command can also be used to add leases for IPv6 prefixes.
+In this case there are three additional parameters that must be specified:
+``subnet-id``, ``type`` (set to "IA_PD"), and prefix length. The actual
+prefix is set using the ``ip-address`` field. Note that Kea cannot guess
+``subnet-id`` values for prefixes; they must be specified explicitly. For
+example, to configure a lease for prefix 2001:db8:abcd::/48, the
+following command can be used:
+
+::
+
+ {
+ "command": "lease6-add",
+ "arguments": {
+ "subnet-id": 66,
+ "type": "IA_PD",
+ "ip-address": "2001:db8:abcd::",
+ "prefix-len": 48,
+ "duid": "1a:1b:1c:1d:1e:1f:20:21:22:23:24",
+ "iaid": 1234
+ }
+ }
+
+The commands can take several additional optional parameters:
+
+- ``valid-lft`` - specifies the lifetime of the lease, expressed in
+ seconds. If not specified, the value configured in the subnet related
+ to the specified ``subnet-id`` is used.
+
+- ``expire`` - creates a timestamp of the lease expiration time,
+ expressed in UNIX format (seconds since 1 Jan 1970). If not
+ specified, the default value is the current time plus the lease lifetime (the value
+ of ``valid-lft``).
+
+- ``fqdn-fwd`` - specifies whether the lease should be marked as if a
+ forward DNS update were conducted. This only affects the
+ data stored in the lease database, and no DNS update will be
+ performed. If configured, a DNS update to remove the A or AAAA
+ records will be conducted when the lease is removed due to expiration
+ or being released by a client. If not specified, the default value is
+ ``false``. The hostname parameter must be specified if ``fqdn-fwd`` is set to
+ ``true``.
+
+- ``fqdn-rev`` - specifies whether the lease should be marked as if
+ reverse DNS update were conducted. This only affects the
+ data stored in the lease database, and no DNS update will be
+ performed.. If configured, a DNS update to remove the PTR record will
+ be conducted when the lease is removed due to expiration or being
+ released by a client. If not specified, the default value is ``false``.
+ The hostname parameter must be specified if ``fqdn-fwd`` is set to ``true``.
+
+- ``hostname`` - specifies the hostname to be associated with this
+ lease. Its value must be non-empty if either ``fqdn-fwd`` or ``fqdn-rev`` are
+ set to ``true``. If not specified, the default value is an empty string.
+
+- ``hw-address`` - optionally specifies a hardware (MAC) address for an
+ IPv6 lease. It is a mandatory parameter for an IPv4 lease.
+
+- ``client-id`` - optionally specifies a client identifier for an IPv4
+ lease.
+
+- ``preferred-lft`` - optionally specifies a preferred lifetime for
+ IPv6 leases. If not specified, the value configured for the subnet
+ corresponding to the specified ``subnet-id`` is used. This parameter is
+ not used when adding an IPv4 lease.
+
+- ``state`` - specifies the state of an added lease, which can be 0 for ``default``,
+ 1 for ``declined``, and 2 for the ``expired-reclaimed`` state. Any other
+ value causes an error. Using 1 for a ``"IA_PD"`` lease type is
+ illegal and will be rejected.
+
+- ``user-context`` - specifies the user context to be associated with
+ this lease. It must be a JSON map.
+
+Here is an example of a fairly complex lease addition:
+
+::
+
+ {
+ "command": "lease6-add",
+ "arguments": {
+ "subnet-id": 66,
+ "ip-address": "2001:db8::3",
+ "duid": "01:02:03:04:05:06:07:08",
+ "iaid": 1234,
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "preferred-lft": 500,
+ "valid-lft": 1000,
+ "expire": 12345678,
+ "fqdn-fwd": true,
+ "fqdn-rev": true,
+ "state": 0,
+ "hostname": "urania.example.org",
+ "user-context": { "version": 1 }
+ }
+ }
+
+The command returns a status that indicates either success (result 0)
+or failure (result 1). A failed command always includes a text
+parameter that explains the cause of failure. For example:
+
+::
+
+ { "result": 0, "text": "Lease added." }
+
+Example failure:
+
+::
+
+ { "result": 1, "text": "missing parameter 'ip-address' (<string>:3:19)" }
+
+
+.. isccmd:: lease6-bulk-apply
+.. _command-lease6-bulk-apply:
+
+The ``lease6-bulk-apply`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`lease6-bulk-apply` was implemented to address
+the performance penalty in High-Availability mode when a single DHCPv6
+transaction resulted in multiple lease updates sent to the partner, if
+multiple address and/or prefix leases were allocated. Consider the case
+when a DHCPv6 client requests the assignment of two IPv6 addresses and two IPv6
+prefixes: it may result in the allocation of four leases. In addition,
+DHCPv6 may assign a different address than the one requested by the client during
+the renew or rebind stage, and delete the leases previously used by this client.
+There are six lease changes sent between the HA partners in this case.
+Sending these updates as individual commands, e.g. via :isccmd:`lease6-update`,
+is highly inefficient and produces unnecessary delays in communication,
+both between the HA partners and in sending the response to the DHCPv6 client.
+
+The :isccmd:`lease6-bulk-apply` command deals with this
+problem by aggregating all lease changes - both deleted leases and
+new or updated leases - in a single command.
+The receiving server iterates over the deleted leases and deletes them
+from its lease database. Next, it iterates over the new/updated leases
+and adds them to the database or updates them if they already exist.
+
+Even though High Availability is the major application for
+this command, it can be freely used in all cases when it is desirable to
+send multiple lease changes in a single command.
+
+In the following example, we delete two leases and add
+or update two other leases in the database:
+
+
+::
+
+ {
+ "command": "lease6-bulk-apply",
+ "arguments": {
+ "deleted-leases": [
+ {
+ "ip-address": "2001:db8:abcd::",
+ "type": "IA_PD",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:abcd::234",
+ "type": "IA_NA",
+ ...
+ }
+ ],
+ "leases": [
+ {
+ "subnet-id": 66,
+ "ip-address": "2001:db8:cafe::",
+ "type": "IA_PD",
+ ...
+ },
+ {
+ "subnet-id": 66,
+ "ip-address": "2001:db8:abcd::333",
+ "type": "IA_NA",
+ ...
+ }
+ ]
+ }
+ }
+
+If any of the leases are malformed, no lease changes are applied
+to the lease database. If the leases are well-formed but there is a
+failure to apply any of the lease changes to the database, the command
+continues to be processed for other leases. All the leases for which
+the command was unable to apply the changes in the database are
+listed in the response. For example:
+
+::
+
+ {
+ "result": 0,
+ "text": "Bulk apply of 2 IPv6 leases completed",
+ "arguments": {
+ "failed-deleted-leases": [
+ {
+ "ip-address": "2001:db8:abcd::",
+ "type": "IA_PD",
+ "result": 3,
+ "error-message": "no lease found"
+ }
+ ],
+ "failed-leases": [
+ {
+ "ip-address": "2001:db8:cafe::",
+ "type": "IA_PD",
+ "result": 1,
+ "error-message": "unable to communicate with the lease database"
+ }
+ ]
+ }
+ }
+
+The response above indicates that the hook library was unable to
+delete the lease for prefix "2001:db8:abcd::" and add or update the lease
+for prefix "2001:db8:cafe::". However, there are two other lease changes
+which have been applied as indicated by the text message. The
+``result`` is the status constant that indicates the type
+of the error experienced for the particular lease. The meanings of the
+returned codes are the same as the results returned for the commands.
+In particular, the result of 1 indicates an error while processing the
+lease, e.g. a communication error with the database. The result of 3
+indicates that an attempt to delete the lease was unsuccessful because
+such a lease doesn't exist (an empty result).
+
+.. isccmd:: lease4-get
+.. _command-lease4-get:
+
+.. isccmd:: lease6-get
+.. _command-lease6-get:
+
+The ``lease4-get``, ``lease6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-get` and :isccmd:`lease6-get` can be used to query the lease database
+and retrieve existing leases. There are two types of parameters the
+:isccmd:`lease4-get` command supports: (``address``) or (``subnet-id``,
+``identifier-type``, ``identifier``). There are also two types for
+:isccmd:`lease6-get`: (``address``, ``type``) or (``subnet-id``, ``identifier-type``,
+``identifier``, ``IAID``, ``type``). The first type of query is used when the
+address (either IPv4 or IPv6) is known, but the details of the lease are
+not; one common use case of this type of query is to find out whether a
+given address is being used. The second query uses identifiers;
+currently supported identifiers for leases are: ``"hw-address"`` (IPv4
+only), ``"client-id"`` (IPv4 only), and ``"duid"`` (IPv6 only).
+
+An example :isccmd:`lease4-get` command for getting a lease using an IPv4
+address is:
+
+::
+
+ {
+ "command": "lease4-get",
+ "arguments": {
+ "ip-address": "192.0.2.1"
+ }
+ }
+
+An example of the :isccmd:`lease6-get` query is:
+
+::
+
+ {
+ "command": "lease6-get",
+ "arguments": {
+ "ip-address": "2001:db8:1234:ab::",
+ "type": "IA_PD"
+ }
+ }
+
+An example query by ``"hw-address"`` for an IPv4 lease looks as follows:
+
+::
+
+ {
+ "command": "lease4-get",
+ "arguments": {
+ "identifier-type": "hw-address",
+ "identifier": "08:08:08:08:08:08",
+ "subnet-id": 44
+ }
+ }
+
+An example query by ``"client-id"`` for an IPv4 lease looks as follows:
+
+::
+
+ {
+ "command": "lease4-get",
+ "arguments": {
+ "identifier-type": "client-id",
+ "identifier": "01:01:02:03:04:05:06",
+ "subnet-id": 44
+ }
+ }
+
+An example query by (``subnet-id``, ``identifier-type``, ``identifier``, ``iaid``, ``type``)
+for an IPv6 lease is:
+
+::
+
+ {
+ "command": "lease4-get",
+ "arguments": {
+ "identifier-type": "duid",
+ "identifier": "08:08:08:08:08:08",
+ "iaid": 1234567,
+ "type": "IA_NA",
+ "subnet-id": 44
+ }
+ }
+
+The ``type`` is an optional parameter. Supported values are: ``IA_NA``
+(non-temporary address) and ``IA_PD`` (IPv6 prefix). If not specified, ``IA_NA``
+is assumed.
+
+:isccmd:`lease4-get` and :isccmd:`lease6-get` return an indication of the result of the operation
+and lease details, if found. The result has one of the following values: 0
+(success), 1 (error), or 3 (empty). An empty result means that a query
+has been completed properly, but the object (a lease in this case) has
+not been found.
+The lease parameters, if found, are returned as arguments.
+``client-id`` is not returned if empty.
+
+An example result returned when the host was found:
+
+::
+
+ {
+ "arguments": {
+ "client-id": "42:42:42:42:42:42:42:42",
+ "cltt": 12345678,
+ "fqdn-fwd": false,
+ "fqdn-rev": true,
+ "hostname": "myhost.example.com.",
+ "hw-address": "08:08:08:08:08:08",
+ "ip-address": "192.0.2.1",
+ "state": 0,
+ "subnet-id": 44,
+ "valid-lft": 3600
+ },
+ "result": 0,
+ "text": "IPv4 lease found."
+ }
+
+.. note::
+
+ The client last transaction time (``cltt`` field) is bound to the
+ valid lifetime (``valid-lft``) and to the expire date (not reported
+ here but stored in databases) by the equation
+ :math:`cltt + valid\_lft = expire`
+
+ at the exception of the infinite valid lifetime coded by the
+ 0xfffffff (4294967295) special value which makes the expire value
+ to overflow on MySQL and old PostgreSQL backends where timestamps
+ are 32 bit long. So in these lease databases the expire date is the
+ same as the cltt i.e.
+ :math:`cltt = expire` when :math:`valid\_lft = 4294967295` and the
+ lease backend is MySQL or PostgreSQL.
+
+.. isccmd:: lease4-get-all
+.. _command-lease4-get-all:
+
+.. isccmd:: lease6-get-all
+.. _command-lease6-get-all:
+
+The ``lease4-get-all``, ``lease6-get-all`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-get-all` and :isccmd:`lease6-get-all` are used to retrieve all IPv4
+or IPv6 leases, or all leases for the specified set of subnets. All
+leases are returned when there are no arguments specified with the
+command, as in the following example:
+
+::
+
+ {
+ "command": "lease4-get-all"
+ }
+
+If arguments are provided, it is expected that they contain the
+``"subnets"`` parameter, which is a list of subnet identifiers for which
+leases should be returned. For example, to retrieve all IPv6
+leases belonging to the subnets with identifiers 1, 2, 3, and 4:
+
+::
+
+ {
+ "command": "lease6-get-all",
+ "arguments": {
+ "subnets": [ 1, 2, 3, 4 ]
+ }
+ }
+
+The returned response contains a detailed list of leases in the
+following format:
+
+::
+
+ {
+ "arguments": {
+ "leases": [
+ {
+ "cltt": 12345678,
+ "duid": "42:42:42:42:42:42:42:42",
+ "fqdn-fwd": false,
+ "fqdn-rev": true,
+ "hostname": "myhost.example.com.",
+ "hw-address": "08:08:08:08:08:08",
+ "iaid": 1,
+ "ip-address": "2001:db8:2::1",
+ "preferred-lft": 500,
+ "state": 0,
+ "subnet-id": 44,
+ "type": "IA_NA",
+ "valid-lft": 3600
+ },
+ {
+ "cltt": 12345678,
+ "duid": "21:21:21:21:21:21:21:21",
+ "fqdn-fwd": false,
+ "fqdn-rev": true,
+ "hostname": "",
+ "iaid": 1,
+ "ip-address": "2001:db8:0:0:2::",
+ "preferred-lft": 500,
+ "prefix-len": 80,
+ "state": 0,
+ "subnet-id": 44,
+ "type": "IA_PD",
+ "valid-lft": 3600
+ }
+ ]
+ },
+ "result": 0,
+ "text": "2 IPv6 lease(s) found."
+ }
+
+.. warning::
+
+ The :isccmd:`lease4-get-all` and
+ :isccmd:`lease6-get-all` commands may result in
+ very large responses. This may have a negative impact on the DHCP
+ server's responsiveness while the response is generated and
+ transmitted over the control channel, as the server imposes no
+ restriction on the number of leases returned as a result of this
+ command.
+
+.. isccmd:: lease4-get-page
+.. _command-lease4-get-page:
+
+.. isccmd:: lease6-get-page
+.. _command-lease6-get-page:
+
+The ``lease4-get-page``, ``lease6-get-page`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`lease4-get-all` and
+:isccmd:`lease6-get-all` commands may result in
+very large responses; generating such a response may consume CPU
+bandwidth as well as memory. It may even cause the server to become
+unresponsive. In the case of large lease databases it is usually better to
+retrieve leases in chunks, using the paging mechanism.
+:isccmd:`lease4-get-page` and :isccmd:`lease6-get-page` implement a paging mechanism
+for DHCPv4 and DHCPv6 servers, respectively. The following command
+retrieves the first 1024 IPv4 leases:
+
+::
+
+ {
+ "command": "lease4-get-page",
+ "arguments": {
+ "from": "start",
+ "limit": 1024
+ }
+ }
+
+The keyword ``start`` denotes that the first page of leases should be
+retrieved. Alternatively, an IPv4 zero address can be specified to
+retrieve the first page:
+
+::
+
+ {
+ "command": "lease4-get-page",
+ "arguments": {
+ "from": "0.0.0.0",
+ "limit": 1024
+ }
+ }
+
+Similarly, the IPv6 zero address can be specified in the
+:isccmd:`lease6-get-page` command:
+
+::
+
+ {
+ "command": "lease6-get-page",
+ "arguments": {
+ "from": "::",
+ "limit": 6
+ }
+ }
+
+The response has the following structure:
+
+::
+
+ {
+ "arguments": {
+ "leases": [
+ {
+ "ip-address": "2001:db8:2::1",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:2::9",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:3::1",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:5::3",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:4::1",
+ ...
+ },
+ {
+ "ip-address": "2001:db8:2::7",
+ ...
+ },
+ ...
+ ],
+ "count": 6
+ },
+ "result": 0,
+ "text": "6 IPv6 lease(s) found."
+ }
+
+Note that the leases' details were excluded from the response above for
+brevity.
+
+Generally, the returned list is not sorted in any particular order. Some
+lease database backends may sort leases in ascending order of addresses,
+but the controlling client must not rely on this behavior.
+
+The ``count`` parameter contains the number of returned leases on the
+page.
+
+To fetch the next page, the client must use the last address of the
+current page as an input to the next :isccmd:`lease4-get-page` or
+:isccmd:`lease6-get-page` command call. In this example it is:
+
+::
+
+ {
+ "command": "lease6-get-page",
+ "arguments": {
+ "from": "2001:db8:2::7",
+ "count": 6
+ }
+ }
+
+because 2001:db8:2::7 is the last address on the current page.
+
+The client may assume that it has reached the last page when the
+``count`` value is lower than that specified in the command; this
+includes the case when the ``count`` is equal to 0, meaning that no
+leases were found.
+
+.. isccmd:: lease4-get-by-hw-address
+.. _command-lease4-get-by-hw-address:
+
+.. isccmd:: lease4-get-by-client-id
+.. _command-lease4-get-by-client-id:
+
+.. isccmd:: lease6-get-by-duid
+.. _command-lease6-get-by-duid:
+
+.. isccmd:: lease4-get-by-hostname
+.. _command-lease4-get-by-hostname:
+
+.. isccmd:: lease6-get-by-hostname
+.. _command-lease6-get-by-hostname:
+
+The ``lease4-get-by-*``, ``lease6-get-by-*`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``lease4-get-by-*`` and ``lease6-get-by-*`` can be used to query the lease database and
+retrieve all existing leases matching a given feature (denoted by the ``*``). These
+can include a specified hardware address (IPv4
+only), ``client-id`` IPv4 only), ``duid`` (IPv6 only) identifiers, or hostname.
+
+An example :isccmd:`lease4-get-by-hw-address` command for getting IPv4 leases
+with a given hardware address is:
+
+::
+
+ {
+ "command": "lease4-get-by-hw-address",
+ "arguments": {
+ "hw-address": "08:08:08:08:08:08"
+ }
+ }
+
+An example of the :isccmd:`lease6-get-by-hostname` is:
+
+::
+
+ {
+ "command": "lease6-get-by-hostname",
+ "arguments": {
+ "hostname": "myhost.example.org"
+ }
+ }
+
+The ``by`` key is the only parameter. The returned response contains a detailed
+list of leases in the same format as :isccmd:`lease4-get-all` or :isccmd:`lease6-get-all`. This list can be
+empty and is usually not large.
+
+.. isccmd:: lease4-del
+.. _command-lease4-del:
+
+.. isccmd:: lease6-del
+.. _command-lease6-del:
+
+The ``lease4-del``, ``lease6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-del` and :isccmd:`lease6-del` can be used to delete a lease from the lease database.
+There are two types of parameters these commands support, similar to the
+:isccmd:`lease4-get` and :isccmd:`lease6-get` commands: (``address``) for both v4 and v6, (``subnet-id``,
+``identifier-type``, ``identifier``) for v4, and (``subnet-id``, ``identifier-type``,
+``identifier``, ``type``, ``IAID``) for v6. The first type of query is used when the
+address (either IPv4 or IPv6) is known, but the details of the lease are
+not. One common use case is where an administrator wants a specified
+address to no longer be used. The second form of the command uses
+identifiers. For maximum flexibility, this interface uses identifiers as
+a pair of values: the type and the actual identifier. The currently
+supported identifiers are ``"hw-address"`` (IPv4 only), ``"client-id"`` (IPv4
+only), and ``"duid"`` (IPv6 only).
+
+An example command for deleting a lease by address is:
+
+::
+
+ {
+ "command": "lease4-del",
+ "arguments": {
+ "ip-address": "192.0.2.202"
+ }
+ }
+
+An example IPv4 lease deletion by ``"hw-address"`` is:
+
+::
+
+ {
+ "command": "lease4-del",
+ "arguments": {
+ "identifier": "08:08:08:08:08:08",
+ "identifier-type": "hw-address",
+ "subnet-id": 44
+ }
+ }
+
+
+Another parameter called ``update-ddns``, when ``true``, instructs the server to
+queue a request to :iscman:`kea-dhcp-ddns` to remove DNS entries after the lease is
+successfully deleted if:
+
+- DDNS updating is enabled (i.e. ``"dhcp-ddns":{ "enable-updates": true }``).
+- The lease's hostname is not empty.
+- At least one of the lease's DNS direction flags (``fqdn_fwd`` or ``fqdn_rev``) is true.
+
+This parameter defaults to ``false``. An example of its use is shown below:
+
+::
+
+ {
+ "command": "lease4-del",
+ "arguments": {
+ "ip-address": "192.0.2.202",
+ "update-ddns": true
+ }
+ }
+
+
+Commands :isccmd:`lease4-del` and :isccmd:`lease6-del` return a result that indicates the outcome
+of the operation. It has one of the following values: 0 (success), 1 (error),
+or 3 (empty). The empty result means that a query has been completed properly,
+but the object (a lease, in this case) has not been found.
+
+.. isccmd:: lease4-update
+.. _command-lease4-update:
+
+.. isccmd:: lease6-update
+.. _command-lease6-update:
+
+The ``lease4-update``, ``lease6-update`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`lease4-update` and
+:isccmd:`lease6-update` commands can be used to
+update existing leases. Since all lease database backends are indexed by
+IP addresses, it is not possible to update an address, but all other
+fields may be altered. If an address needs to be changed, please use
+:isccmd:`lease4-del` / :isccmd:`lease6-del` followed by :isccmd:`lease4-add` / :isccmd:`lease6-add`.
+
+The ``subnet-id`` parameter is optional. If not specified, or if the
+specified value is 0, Kea tries to determine its value by running a
+subnet-selection procedure. If specified, however, its value must match
+the existing subnet.
+
+The optional boolean parameter ``"force-create"`` specifies whether the
+lease should be created if it does not exist in the database. It defaults
+to ``false``, which indicates that the lease is not created if it does not
+exist. In such a case, an error is returned when trying to
+update a non-existing lease. If the ``"force-create"`` parameter is set to
+``true`` and the updated lease does not exist, the new lease is created as a
+result of receiving the :isccmd:`lease4-update` / :isccmd:`lease6-update` command.
+
+An example of a command to update an IPv4 lease is:
+
+::
+
+ {
+ "command": "lease4-update",
+ "arguments": {
+ "ip-address": "192.0.2.1",
+ "hostname": "newhostname.example.org",
+ "hw-address": "1a:1b:1c:1d:1e:1f",
+ "subnet-id": 44,
+ "force-create": true
+ }
+ }
+
+An example of a command to update an IPv6 lease is:
+
+::
+
+ {
+ "command": "lease6-update",
+ "arguments": {
+ "ip-address": "2001:db8::1",
+ "duid": "88:88:88:88:88:88:88:88",
+ "iaid": 7654321,
+ "hostname": "newhostname.example.org",
+ "subnet-id": 66,
+ "force-create": false
+ }
+ }
+
+As with other update commands, this command overwrites all the contents of the
+entry. If the lease previously had a resource assigned to it, and the
+:isccmd:`lease4-update` / :isccmd:`lease6-update` command is missing the resource, it is
+deleted from the lease database. If an incremental update of the lease is
+desired, then this can be achieved by doing a :isccmd:`lease4-get` / :isccmd:`lease6-get`
+command to get the current state of the lease, picking the lease out of the
+response, modifying it to the required outcome, and then issuing the
+:isccmd:`lease4-update` / :isccmd:`lease6-update` command with the resulting lease attached.
+
+.. isccmd:: lease4-wipe
+.. _command-lease4-wipe:
+
+.. isccmd:: lease6-wipe
+.. _command-lease6-wipe:
+
+The ``lease4-wipe``, ``lease6-wipe`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-wipe` and :isccmd:`lease6-wipe` are designed to remove all leases
+associated with a given subnet. This administrative task is expected to
+be used when an existing subnet is being retired. The leases
+are not properly expired; no DNS updates are carried out, no log
+messages are created, and hooks are not called for the leases being
+removed.
+
+An example of :isccmd:`lease4-wipe` is:
+
+::
+
+ {
+ "command": "lease4-wipe",
+ "arguments": {
+ "subnet-id": 44
+ }
+ }
+
+An example of :isccmd:`lease6-wipe` is:
+
+::
+
+ {
+ "command": "lease6-wipe",
+ "arguments": {
+ "subnet-id": 66
+ }
+ }
+
+The commands return a text description of the number of leases removed,
+plus the status code 0 (success) if any leases were removed or 3 (empty)
+if there were no leases. Status code 1 (error) may be returned if the
+parameters are incorrect or some other exception is encountered.
+
+``subnet-id`` 0 has a special meaning; it tells Kea to delete leases from
+all configured subnets. Also, the ``subnet-id`` parameter may be omitted. If
+not specified, leases from all subnets are wiped.
+
+Note: currently only memfile lease storage supports this command.
+
+.. isccmd:: lease4-resend-ddns
+.. _command-lease4-resend-ddns:
+
+.. isccmd:: lease6-resend-ddns
+.. _command-lease6-resend-ddns:
+
+The ``lease4-resend-ddns``, ``lease6-resend-ddns`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-resend-ddns` and :isccmd:`lease6-resend-ddns` can be used to generate
+a request to :iscman:`kea-dhcp-ddns` to update the DNS entries for an existing
+lease. The desired lease is selected by a single parameter, ``"ip-address"``.
+For an update request to be generated, DDNS updating must be enabled
+and DNS entries must have already been made (or attempted) for the lease.
+In other words, all of the following must be true:
+
+- DDNS updating must be enabled (i.e. ``"dhcp-ddns":{ "enable-updates": true"}``).
+- The lease's hostname must not be empty.
+- At least one of the lease's DNS direction flags (``fqdn_fwd`` or ``fqdn_rev``) must be true.
+
+An example :isccmd:`lease4-resend-ddns` command for getting a lease using an IPv4
+address is:
+
+::
+
+ {
+ "command": "lease4-resend-ddns",
+ "arguments": {
+ "ip-address": "192.0.2.1"
+ }
+ }
+
+An example of the :isccmd:`lease6-resend-ddns` query is:
+
+::
+
+ {
+ "command": "lease6-resend-ddns",
+ "arguments": {
+ "ip-address": "2001:db8:1::1"
+ }
+ }
+
+Commands :isccmd:`lease4-resend-ddns` and :isccmd:`lease6-resend-ddns` return an indication of the
+result of the operation. It has one of the following values: 0 (success), 1 (error),
+or 3 (empty). An empty result means that a query has been completed properly, but the
+object (a lease in this case) has not been found.
+
+A successful result does not mean that DNS has been successfully updated; it
+indicates that a request to update DNS has been successfully created and
+queued for transmission to :iscman:`kea-dhcp-ddns`.
+
+Here's an example of a result returned when the lease was found:
+
+::
+
+ {
+ "result": 0,
+ "text": "NCR generated for: 2001:db8:1::1, hostname: example.com."
+ }
+
+.. isccmd:: lease4-write
+.. _command-lease4-write:
+
+.. isccmd:: lease6-write
+.. _command-lease6-write:
+
+The ``lease4-write``, ``lease6-write`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:isccmd:`lease4-write` and :isccmd:`lease6-write` can be used for recovery in emergency
+situations where the memfile lease file is damaged, e.g. removed by
+accident or truncated by a full file system, but the in-memory database
+is still valid. These commands are supported only by the memfile database
+backend and write the lease database into a CSV file. They take the path
+of the file as the ``filename`` argument. If the specified output file
+is the same as the configured memfile one, the backend closes and reopens
+the file in an attempt to synchronize both the files and the in-memory images
+of the lease database. The extension ``.bak`` with server PID number is added
+to the previous filename. For example ``.bak14326``.
+
+.. note::
+
+ These commands do not replace the LFC mechanism; they should be used
+ only in exceptional circumstances, such as when recovering after
+ running out of disk space.
diff --git a/doc/sphinx/arm/hooks-lease-query.rst b/doc/sphinx/arm/hooks-lease-query.rst
new file mode 100644
index 0000000..046001f
--- /dev/null
+++ b/doc/sphinx/arm/hooks-lease-query.rst
@@ -0,0 +1,675 @@
+.. ischooklib:: libdhcp_lease_query.so
+.. _hooks-lease-query:
+
+``libdhcp_lease_query.so``: Leasequery Support
+==============================================
+
+This library provides support for DHCPv4 Leasequery as described in
+`RFC 4388 <https://tools.ietf.org/html/rfc4388>`__; and for DHCPv6
+Leasequery as described in (`RFC 5007 <https://tools.ietf.org/html/rfc5007>`__).
+
+.. note::
+
+ :ischooklib:`libdhcp_lease_query.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or
+ :iscman:`kea-dhcp6` process.
+
+Kea version 2.3.4 added support for DHCPv6 Bulk Leasequery
+(`RFC 5460 <https://tools.ietf.org/html/rfc5460>`__);
+Kea version 2.3.5 added support for DHCPv4 Bulk Leasequery
+(`RFC 6926 <https://tools.ietf.org/html/rfc6926>`__) using
+the memfile lease backend.
+
+.. _lease-query-dhcpv4:
+
+DHCPv4 Leasequery
+~~~~~~~~~~~~~~~~~
+
+DHCPv4 simple Leasequery provides a requester the ability to query for
+active lease information for either a single IP address or a single client.
+RFC 4388 calls for three such queries:
+
+- Query by IP address
+
+ The IP address of interest is contained within the ``ciaddr`` field of
+ the query.
+- Query by hardware address
+
+ The hardware address of interest is contained with the ``chaddr`` field
+ of the query.
+- Query by client identifier
+
+ The client identifier of interest is sent in the ``dhcp-client-identifier``
+ option (61) of the query.
+
+The inbound DHCPLEASEQUERY packet must supply only one of the three values
+above. Queries which supply more than one of these values are dropped.
+
+In addition, the query must contain the IP address of the requester in
+``giaddr``. This value is used not only as the destination for the
+query response but also to validate the requester against a known
+list of IP addresses which are permitted to query. This list of valid
+requester addresses is specified as part of the Leasequery hook library's
+configuration (see the section on configuration below).
+
+In response to a valid query, the server returns one of three message
+types:
+
+- DHCPLEASEUNKNOWN
+
+ Returned when the IP address of interest is not one the server knows
+ about (query by IP address); or there are no active leases for the
+ client of interest (query by hardware address or client ID).
+
+- DHCPLEASEUNASSIGNED
+
+ Returned when the IP address is one the server knows of but for which
+ there are no active leases (applies only to query by IP address).
+
+- DHCPLEASEACTIVE
+
+ Returned when there is at least one active lease found matching the
+ criteria.
+
+For both DHCPLEASEUNKNOWN and DHCPLEASEUNASSIGNED responses, the only
+information sent back to the requester in response is the query parameter
+itself (i.e. one of: IP address, hardware address, or client identifier).
+
+For DHCPLEASEACTIVE the server provides the following information
+for the newest active lease that matches the criteria, in the response:
+
+- ``ciaddr`` - set to the lease's IP address
+- ``chaddr`` - set to the lease's hardware address
+
+In addition, one or more of the following options are included:
+
+.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}|
+
+.. table:: DHCPLEASEACTIVE options
+ :class: longtable
+ :widths: 30 10 70
+
+ +------------------------------+-------+-----------------------------------------------+
+ | Option | Code | Content |
+ +==============================+=======+===============================================+
+ | dhcp-client-identifier | 61 | copied from the lease (if appropriate) |
+ +------------------------------+-------+-----------------------------------------------+
+ | client-last-transaction-time | 91 | the amount of time that has elapsed since the |
+ | | | lease's client-last-transaction-time (CLTT). |
+ | | | This value is also used by the server to |
+ | | | adjust lifetime and timer values. |
+ +------------------------------+-------+-----------------------------------------------+
+ | dhcp-lease-time | 51 | lease's lifetime reduced by CLTT |
+ +------------------------------+-------+-----------------------------------------------+
+ | dhcp-renewal-time | 58 | as controlled by kea-dhcp4 configuration and |
+ | | | then reduced by CLTT |
+ +------------------------------+-------+-----------------------------------------------+
+ | dhcp-rebind-time | 59 | as dictated by kea-dhcp4 configuration and |
+ | | | then reduced by CLTT |
+ +------------------------------+-------+-----------------------------------------------+
+ | dhcp-agent-options | 82 | if stored on the lease. (See |
+ | | | :ref:`dhcp4-store-extended-info`) |
+ +------------------------------+-------+-----------------------------------------------+
+ | associated-ip | 92 | a list of all other IP addresses for which |
+ | | | the client has active leases. (Does not apply |
+ | | | to query by IP address) |
+ +------------------------------+-------+-----------------------------------------------+
+
+The ``dhcp-server-identifier`` option (54) is returned in all responses in keeping with
+RFC 2131, section 4.3.1.
+
+RFC 4388 allows requesters to ask for specific options via the
+``dhcp-parameter-request-list`` (PRL, option 55). This is not currently supported in Kea.
+
+.. _lease-query-dhcpv4-config:
+
+DHCPv4 Leasequery Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configuring the Leasequery hook library for use is straightforward. It
+supports a single parameter, ``requesters``, which is a list of IP addresses from
+which DHCPLEASEQUERY packets are accepted. In other words, it is a list of
+known requesters. The following code shows an example configuration with two requester
+addresses:
+
+::
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "lib/kea/hooks/libdhcp_lease_query.so",
+ "parameters": {
+ "requesters": [ "192.0.1.1", "10.0.0.2" ]
+ }
+ }
+ ],
+ ...
+ }
+
+.. note::
+
+ For security purposes, there is no way to specify wildcards. Each requester address
+ must be explicitly listed.
+
+.. _lease-query-dhcpv6:
+
+DHCPv6 Leasequery
+~~~~~~~~~~~~~~~~~
+
+DHCPv6 simple Leasequery gives a requester the ability to query for
+active lease information for either a single IP address or a single client
+DUID. The query type and parameters are conveyed in an ``lq-query`` option (44)
+attached to a ``DHCPV6_LEASEQUERY`` message:
+
+- ``query-type``
+
+ This is either ``query-by-address`` (1) or ``query-by-clientid`` (2)
+
+- ``link-address``
+
+ The global link address, when not empty, instructs the query to be
+ limited to leases within that "link." Kea uses this value to
+ select only leases that belong to subnets whose prefix matches
+ this value. Active leases for prefix delegations for
+ a matched subnet are included in the query reply, even if the
+ delegated prefix itself falls outside the subnet prefix.
+
+- ``query-options``
+
+ A single ``iaaddr`` option (12) must be supplied when querying by address.
+ When querying by client ID, a single ``clientid`` option (1) must be
+ supplied. RFC 5007 also calls for an optional, ``oro`` option (6), to
+ request specific options be returned for matched leases. This is
+ not currently implemented.
+
+.. note::
+
+ `RFC 5007, Section 3.3 <https://tools.ietf.org/html/rfc5007#section-3.3>`__
+ states that querying by IP address should return either a lease (e.g.
+ binding) for the address itself or a lease for a delegated prefix that
+ contains the address. The latter case is not supported by releases
+ prior to Kea 2.3.7.
+
+``DHCPV6_LEASEQUERY`` queries are only honored if the source address of
+the query matches an entry in a list of known IP addresses which are
+permitted to query. This list of valid requester addresses is specified
+as part of the Leasequery hook library’s configuration (see the section
+on configuration below). Queries received from unknown requesters are
+logged and dropped.
+
+In response to a valid query, the server carries out the requisite
+activities and returns a ``DHCPV6_LEASEQUERY_REPLY``. All replies contain
+at least a ``status-code`` option (13) that indicates the outcome of the query
+as detailed in the following table:
+
+.. tabularcolumns:: |p{0.5\linewidth}|p{0.3\linewidth}|p{0.1\linewidth}|p{0.3\linewidth}|
+
+.. table:: DHCPV6_LEASEQUERY_REPLY status option values per query outcome
+ :class: longtable
+ :widths: 50 30 10 30
+
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | | Status | Status | Status |
+ | Query Outcome | Label | Code | Text |
+ +======================================+=========================+========+==============================+
+ | Invalid query type field | STATUS_UnknownQueryType | 7 | "unknown query-type" |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by IP address that does not | STATUS_Malformed | 10 | "missing D6O_IAADDR" |
+ | contain an address option | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by IP address for an address | STATUS_NotConfigured | 9 | "address not in a configured |
+ | that does fall within any configured | | | pool" |
+ | pools | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by IP address which found only | STATUS_Success | 0 | "inactive lease exists" |
+ | an inactive lease (e.g. expired, | | | |
+ | declined, reclaimed-expired) | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by IP address that found no | STATUS_Success | 0 | "no active lease" |
+ | leases (active or otherwise) | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by IP address that found an | STATUS_Success | 0 | "active lease found" |
+ | active lease for the address | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by Client ID that does not | STATUS_Malformed | 10 | "missing D6O_CLIENTID" |
+ | contain a client ID option | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by Client ID with a link | STATUS_NotConfigured | 9 | "not a configured link" |
+ | address that does not match any | | | |
+ | configured subnets | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by client ID which found no | STATUS_Success | 0 | "no active leases" |
+ | matching leases | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+ | Query by client ID which found one | STATUS_Success | 0 | "active lease(s) found" |
+ | or more active leases | | | |
+ +--------------------------------------+-------------------------+--------+------------------------------+
+
+For those scenarios where the query was either invalid or for which no matching active
+leases were found, the ``DHCPV6_LEASEQUERY_REPLY`` only contains the ``status-code``
+option (12) per the above table.
+
+When a query finds active leases in more than one subnet and the query's ``link-address``
+is empty, then, in addition to the status-code, the ``DHCPV6_LEASEQUERY_REPLY``
+contains an ``lq-client-link`` option (48). The ``lq-client-link`` contains a list of
+IPv6 addresses, one for each subnet in which a lease was found (see
+`RFC 5007, Section 4.1.2.5 <https://tools.ietf.org/html/rfc5007#section-4.1.2.5>`__)
+If, however, the query's ``link-address`` is not empty, the list of queries is
+pruned to contain only leases that belong to that subnet.
+
+When the query results in one or more active leases which all belong to a single
+subnet, in addition to the ``status-code``, the ``DHCPV6_LEASEQUERY_REPLY`` contains a
+``client-data`` option (45) (see
+`RFC 5007, Section 4.1.2.2 <https://tools.ietf.org/html/rfc5007#section-4.1.2.2>`__).
+The client-data option encapsulates the following options:
+
+.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}|
+
+.. table:: OPTION_CLIENT_DATA returned when active lease(s) are found
+ :class: longtable
+ :widths: 30 10 70
+
+ +------------------------------+-------+-----------------------------------------------+
+ | Option | Code | Content |
+ +==============================+=======+===============================================+
+ | clientid | 1 | copied from the lease (if one exists) |
+ +------------------------------+-------+-----------------------------------------------+
+ | clt-time | 46 | amount of time that has elapsed since the |
+ | | | lease's client-last-transaction-time (CLTT). |
+ | | | This value will also be used by the server to |
+ | | | adjust lifetime and timer values. |
+ +------------------------------+-------+-----------------------------------------------+
+ | iaaddr | 5 | One option per matched address. Fields in |
+ | | | each option: |
+ | | | - lease address |
+ | | | - valid lifetime reduced by CLTT |
+ | | | - preferred lifetime reduced by CLTT |
+ +------------------------------+-------+-----------------------------------------------+
+ | iaprefix | 26 | One option per matched prefix. Fields in |
+ | | | each option: |
+ | | | - prefix |
+ | | | - prefix length |
+ | | | - valid lifetime reduced by CLTT |
+ | | | - preferred lifetime reduced by CLTT |
+ +------------------------------+-------+-----------------------------------------------+
+
+If the lease with the most recent client-last-transaction-time (CLTT)
+value has relay information in its user-context (see
+:ref:`store-extended-info-v6`), then an ``OPTION_LQ_RELAY_DATA`` option is
+added to the reply (see
+`RFC 5007, Section 4.1.2.4 <https://tools.ietf.org/html/rfc5007#section-4.1.2.4>`__).
+
+The relay information on the lease is a list with an entry for each
+relay layer the client packet (e.g. ``DHCPV6_REQUEST``) traversed, with the
+first entry in the list being the outermost layer (closest to the server). The
+``peer-address`` field of the ``lq-rely-option`` is set to the peer address of this
+relay. The list of relays is then used to construct a ``DHCPV6_RELAY_FORW`` message
+equivalent to that which contained the client packet, minus the client packet.
+This message is stored in the ``DHCP-relay-message`` field of the ``lq-relay-data`` option.
+
+.. _lease-query-dhcpv6-config:
+
+DHCPv6 Leasequery Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configuring the Leasequery hook library for use is straightforward. It
+supports a single parameter, ``requesters``, which is a list of IP addresses from
+which DHCPV6_LEASEQUERY packets are accepted. In other words, it is a list of
+known requesters. The following code shows an example configuration with two requester
+addresses:
+
+::
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "lib/kea/hooks/libdhcp_lease_query.so",
+ "parameters": {
+ "requesters": [ "2001:db8:1::1", "2001:db8:2::1" ],
+ "prefix-lengths": [ 72 ]
+ }
+ }
+ ],
+ ...
+ }
+
+.. note::
+
+ For security purposes, there is no way to specify wildcards. Each requester address
+ must be explicitly listed.
+
+When a query by IP address does not match an existing address lease,
+a search for a matching delegated prefix is conducted. This is carried
+out by iterating over a list of prefix lengths, in descending order,
+extracting a prefix of that length from the query address and searching
+for a delegation matching the resulting prefix. This continues for each
+length in the list until a match is found or the list is exhausted.
+
+By default, the list of prefix lengths to use in the search is determined
+dynamically after (re)configuration events. This resulting list will
+contain unique values of ``delegated-len`` gleaned from the currently
+configured set of PD pools.
+
+There is an optional parameter, ``prefix-lengths``, shown above which
+provides the ability to explicitly configure the list rather than having
+it be determined dynamically. This provides tighter control over which
+prefix lengths are searched. In the above example, the prefix length
+search will be restricted to single pass, using a length of 72, regardless
+of whether or not there are pools using other values for ``delegated-len``.
+Specifying an empty list, as shown below:
+
+::
+
+ :
+ "prefix-lengths": [ ]
+ :
+
+disables the search for delegated prefixes for query by IP address.
+
+.. _bulk-lease-query-dhcpv4:
+
+DHCPv4 Bulk Leasequery
+~~~~~~~~~~~~~~~~~~~~~~
+
+DHCPv4 Bulk Leasequery gives a requester the ability to query for
+active lease information over a TCP connection. This allows the server
+to return all leases matching a given query.
+
+Two of the query types identified by RFC 4388 - Query by MAC address and
+Query by Client-identifier - are Bulk Leasequery types specified by RFC
+6926. That RFC also defines these new Bulk Leasequery types:
+
+- Query by Relay Identifier
+
+ The query carries an RAI (dhcp-agent-options (82)) option with
+ a relay-id (12) sub-option.
+
+- Query by Remote ID
+
+ The query carries an RAI (dhcp-agent-options (82) option) with
+ a remote-id (2) sub-option.
+
+- Query for All Configured IP Addresses
+
+ This query type is selected when no other query type is specified.
+
+RFC 6926 also defines new options for Bulk Leasequery:
+
+- status-code (151)
+
+ This reply option carries a status code such as MalformedQuery or
+ NotAllowed, with an optional text message.
+
+- base-time (152)
+
+ This reply option carries the absolute current time that the response
+ was created. All other time-based reply options are related to
+ this value.
+
+- start-time-of-state (153)
+
+ This reply option carries the time of the lease's transition into its
+ current state.
+
+- query-start-time (154)
+
+ This query option specifies a start query time; replies will only
+ contain leases that are older than this value.
+
+- query-end-time (155)
+
+ This query option specifies an end query time; replies will only
+ contain leases that are newer than this value.
+
+- dhcp-state (156)
+
+ This reply option carries the lease state.
+
+- data-source (157)
+
+ This reply option carries the source of the data as a remote flag.
+
+RFC 6926 reuses and extends the Virtual Subnet Selection option (221)
+defined in RFC 6607.
+
+.. note::
+
+ Kea does not yet support querying for all configured IP addresses,
+ so the dhcp-state option cannot be used, as only active leases can be
+ returned in replies. Kea does not keep the start time of the lease's state,
+ nor the local/remote information, so it cannot emit the corresponding
+ start-time-of-state and data-source options. Kea does not support VPNs
+ so the presence of option 221 in the query is considered a
+ (NotAllowed) error.
+
+.. note::
+
+ The new query types are only supported with the memfile lease backend.
+
+.. _bulk-lease-query-dhcpv6:
+
+DHCPv6 Bulk Leasequery
+~~~~~~~~~~~~~~~~~~~~~~
+
+DHCPv6 Bulk Leasequery gives a requester the ability to query for
+active lease information over a TCP connection. This allows the server
+to return all active leases matching a query.
+
+New query types are available: ``query-by-relay-id`` (3),
+``query-by-link-address`` (4), and ``query-by-remote-id`` (5).
+
+A new status code, ``STATUS_QueryTerminated`` (11), has been defined but it is
+not yet used by the hook library.
+
+.. note::
+
+ Kea attempts to map link address parameters to the prefixes of configured
+ subnets. If a given address falls outside all configured subnet prefixes,
+ the query fails with a status code of ``STATUS_NotConfigured``. If
+ the link address parameter for ``query-by-relay-id`` or ``query-by-remote-id``
+ is not ``::`` (i.e. not empty), only delegated prefixes that lie within matching
+ subnet prefixes are returned. Currently, ``query-by-address`` does not
+ support finding delegated prefixes by specifying an address that lies within
+ the prefix.
+
+.. note::
+
+ The new query types are only supported with the memfile lease backend.
+
+.. _bulk-lease-query-dhcpv6-config:
+
+Bulk Leasequery Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Bulk Leasequery configuration is done via a new map parameter, ``advanced``,
+with these possible entries:
+
+- ``bulk-query-enabled``
+
+ When ``true``, Kea accepts connections from IP addresses in the requesters
+ list and processes received Bulk Leasequeries. The default is ``false``.
+
+- ``active-query-enabled``
+
+ This is an anticipated parameter: if set, it must be ``false``.
+
+- ``extended-info-tables-enabled``
+
+ When ``true``, the lease backend manages DHCPv6 lease extended info
+ (relay info) in tables to support the new DHCPv6 Bulk Leasequery
+ by-relay-id and by-remote-id types. The default is to use the
+ same value as ``bulk-query-enabled``.
+
+- ``lease-query-ip``
+
+ This is the IP address upon which to listen for connections. The address must be
+ of the same family as the server, e.g. IPv6 for DHCPv6 server.
+
+- ``lease-query-port``
+
+ This is the port upon which to listen. The default is 67 for IPv4 and 547 for IPv6,
+ i.e. the same value as for the UDP DHCP service but for TCP.
+
+- ``max-bulk-query-threads``
+
+ This indicates the maximum number of threads that Bulk Leasequery processing
+ should use. A value of 0 instructs the server to use the same number of
+ threads that the Kea core is using for DHCP multi-threading.
+ The default is 0.
+
+- ``max-requester-connections``
+
+ This is the maximum number of concurrent requester connections. The default
+ is 10; the value must be greater than 0.
+
+- ``max-concurrent-queries``
+
+ This is the maximum number of concurrent queries per connection. The value 0
+ allows Kea to determine the number, and is the default.
+
+- ``max-requester-idle-time``
+
+ This is the amount of time that may elapse after receiving data from a requester
+ before its connection is closed as idle, in seconds. The default
+ is 300.
+
+- ``max-leases-per-fetch``
+
+ This is the maximum number of leases to return in a single fetch. The default is 100.
+
+Once TLS is supported, we expect to implement common TLS parameters.
+
+For instance, for DHCPv4:
+
+::
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "lib/kea/hooks/libdhcp_lease_query.so",
+ "parameters": {
+ "requesters": [ "192.0.2.1", "192.0.2.2" ],
+ "advanced" : {
+ "bulk-query-enabled": true,
+ "active-query-enabled": false,
+
+ "lease-query-ip": "127.0.0.1",
+ "lease-query-tcp-port": 67,
+
+ "max-bulk-query-threads": 0,
+ "max-requester-connections": 10,
+ "max-concurrent-queries": 4,
+ "max-requester-idle-time": 300,
+ "max-leases-per-fetch": 100
+ }
+ }
+ }
+ ],
+ ...
+ }
+
+or for DHCPv6:
+
+::
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "lib/kea/hooks/libdhcp_lease_query.so",
+ "parameters": {
+ "requesters": [ "2001:db8:1::1", "2001:db8:2::1" ],
+ "advanced" : {
+ "bulk-query-enabled": true,
+ "active-query-enabled": false,
+
+ "extended-info-tables-enabled": true,
+
+ "lease-query-ip": "::1",
+ "lease-query-tcp-port": 547,
+
+ "max-bulk-query-threads": 0,
+ "max-requester-connections": 10,
+ "max-concurrent-queries": 4,
+ "max-requester-idle-time": 300,
+ "max-leases-per-fetch": 100
+ }
+ }
+ }
+ ],
+ ...
+ }
+
+.. _updating-existing-leases:
+
+Updating Existing Leases in SQL Lease Backends
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Bulk Lease Query required additions to the lease data stored. With SQL lease
+backends, leases created prior to the server being configured for Bulk Lease
+Query will not contain the new data required. In order to populate this data
+it is necessary to run API commands:
+
+.. isccmd:: extended-info4-upgrade
+.. _command-extended-info4-upgrade:
+
+For DHCPv4 lease data, the command is:
+
+::
+
+ {
+ "command": "extended-info4-upgrade"
+ }
+
+For DHCPv6 lease data, the command is:
+
+.. isccmd:: extended-info6-upgrade
+.. _command-extended-info6-upgrade:
+
+for extended info used for by relay id and by remote id the command is:
+
+::
+
+ {
+ "command": "extended-info6-upgrade"
+ }
+
+
+In all cases the response will indicate whether it succeeded or failed
+and include either the count of leases updated or the nature of the failure:
+
+::
+
+ {
+ "result": 0,
+ "text": "Upgraded 1000 leases"
+ }
+
+
+This ``extended-info6-upgrade`` command must be called when:
+
+- the database schema was upgraded from a previous version
+
+- Bulk Lease Query was not enabled (tables are maintained only when v6 BLQ is
+ enabled)
+
+- data in tables do not seem to be consistent (tables are not maintained in
+ an atomic way so consistency is not guaranteed. For instance when a database
+ is shared between several servers races can happen between updates)
+
+The operation of extended info command is governed by ``extended-info-checks``
+parameter under the sanity-checks element. Please see :ref:`sanity-checks4`
+or :ref:`sanity-checks6`.
+
+For large numbers of leases this command may take some time to complete.
+
+.. note::
+
+ Existing leases must have been created by Kea with ``store-extended-info``
+ enabled in order for the new data from extended info to be extracted
+ and stored.
+
diff --git a/doc/sphinx/arm/hooks-legal-log.rst b/doc/sphinx/arm/hooks-legal-log.rst
new file mode 100644
index 0000000..be2a07c
--- /dev/null
+++ b/doc/sphinx/arm/hooks-legal-log.rst
@@ -0,0 +1,1094 @@
+.. ischooklib:: libdhcp_legal_log.so
+.. _hooks-legal-log:
+
+``libdhcp_legal_log.so``: Forensic Logging
+==========================================
+
+The Forensic Logging hook library provides
+hooks that record a detailed log of assignments, renewals, releases, and other
+lease events into a set of log files.
+
+.. note::
+
+ :ischooklib:`libdhcp_legal_log.so` is available as a premium
+ hook library from ISC. Please visit https://www.isc.org/shop/ to purchase
+ the premium hook libraries, or contact us at https://www.isc.org/contact for
+ more information.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6`
+ process.
+
+In many legal jurisdictions, companies - especially ISPs - must record
+information about the addresses they have leased to DHCP clients. This
+library is designed to help with that requirement. If the information
+that it records is sufficient, it may be used directly.
+
+If a jurisdiction requires that different information be saved, users
+may use the custom formatting capability to extract information from the inbound
+request packet, or from the outbound response packet. Administrators are advised
+to use this feature with caution, as it may affect server performance.
+The custom format cannot be used for control channel commands.
+
+Alternatively, this library may be used as a template or an example for the
+user's own custom logging hook. The logging is done as a set of hooks to allow
+it to be customized to any particular need; modifying a hook library is easier
+and safer than updating the core code. In addition, by using the hooks features,
+users who do not need to log this information can leave it out and avoid
+any performance penalties.
+
+Log File Naming
+~~~~~~~~~~~~~~~
+
+The names of the log files follow a set pattern.
+
+If using ``day``, ``month``, or ``year`` as the time unit, the file name follows
+the format:
+
+::
+
+ path/base-name.CCYYMMDD.txt
+
+where ``CC`` represents the century, ``YY`` represents the year,
+``MM`` represents the month, and ``DD`` represents the day.
+
+If using ``second`` as the time unit the file name follows the format:
+
+::
+
+ path/base-name.TXXXXXXXXXXXXXXXXXXXX.txt
+
+where ``XXXXXXXXXXXXXXXXXXXX`` represents the time in seconds since the beginning
+of the UNIX epoch.
+
+When using ``second`` as the time unit, the file is rotated when
+the ``count`` number of seconds pass. In contrast, when using ``day``, ``month``,
+or ``year`` as the time unit, the file is rotated whenever the ``count`` of day,
+month, or year starts, as applicable.
+
+The ``"path"`` and ``"base-name"`` are supplied in the configuration as
+described below; see :ref:`forensic-log-configuration`.
+
+.. note::
+
+ When running Kea servers for both DHCPv4 and DHCPv6, the log names
+ must be distinct. See the examples in :ref:`forensic-log-configuration`.
+
+.. _forensic-log-configuration:
+
+Configuring the Forensic Logging Hooks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To use this functionality, the hook library must be included in the
+configuration of the desired DHCP server modules. :ischooklib:`libdhcp_legal_log.so`
+can save logs to a text file or to a database (created using
+:iscman:`kea-admin`; see :ref:`mysql-database-create` and :ref:`pgsql-database-create`).
+The library is installed alongside the Kea libraries in
+``[kea-install-dir]/var/lib/kea``, where ``kea-install-dir`` is determined
+by the ``--prefix`` option of the configure script; it defaults to
+``/usr/local``. Assuming the default value, :iscman:`kea-dhcp4` can be configured to load
+:ischooklib:`libdhcp_legal_log.so` like this:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "path": "/var/lib/kea/log",
+ "base-name": "kea-forensic4"
+ }
+ }
+ ]
+ }
+ }
+
+For :iscman:`kea-dhcp6`, the configuration is:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "path": "/var/lib/kea/log",
+ "base-name": "kea-forensic6"
+ }
+ }
+ ]
+ }
+ }
+
+The hook library parameters for the text file configuration are:
+
+- ``path`` - the directory in which the forensic file(s) will be written.
+ The default value is ``[prefix]/var/lib/kea``. The directory must exist.
+
+- ``base-name`` - an arbitrary value which is used in conjunction with the
+ current system date to form the current forensic file name. It
+ defaults to ``kea-legal``.
+
+- ``time-unit`` - configures the time unit used to rotate the log file. Valid
+ values are ``second``, ``day``, ``month``, or ``year``. It defaults to
+ ``day``.
+
+- ``count`` - configures the number of time units that need to pass until the
+ log file is rotated. It can be any positive number, or 0, which disables log
+ rotation. It defaults to 1.
+
+If log rotation is disabled, a new file is created when the library is
+loaded; the new file name is different from any previous file name.
+
+Additional actions can be performed just before closing the old file and after
+opening the new file. These actions must point to an external executable or
+script and are configured with the following settings:
+
+- ``prerotate`` - an external executable or script called with the name of the
+ file that will be closed. Kea does not wait for the process to finish.
+
+- ``postrotate`` - an external executable or script called with the name of the
+ file that was opened. Kea does not wait for the process to finish.
+
+Custom formatting can be enabled for logging information that can be extracted
+either from the client's request packet or from the server's response packet.
+Use with caution as this might affect server performance.
+The custom format cannot be used for control channel commands.
+Two parameters can be used towards this goal, either together or separately:
+
+- ``request-parser-format`` - an evaluated parsed expression used to extract and
+ log data from the incoming packet.
+
+- ``response-parser-format`` - an evaluated parsed expression used to extract and
+ log data from the server response packet.
+
+See :ref:`classification-using-expressions` for a list of expressions.
+If either ``request-parser-format`` or ``response-parser-format`` is
+configured, the default logging format is not used. If both of them are
+configured, the resulting log message is constructed by concatenating the
+data extracted from the request and the data extracted from the response.
+
+The custom formatting permits logging on multiple lines using the hexstring 0x0a
+(ASCII code for new line). In the log file, each line is prepended
+with the log timestamp. For the database backend, the data is stored
+(including the newline character) in the same entry.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "path": "/var/lib/kea/log",
+ "base-name": "kea-forensic6",
+ "request-parser-format": "'first line' + 0x0a + 'second line'",
+ "response-parser-format": "'also second line' + 0x0a + 'third line'"
+ }
+ }
+ ]
+ }
+ }
+
+Some data might be available in the request or only in the response; the
+data in the request packet might differ from that in the response packet.
+
+The lease-client context can only be printed using the default format, as this
+information is not directly stored in the request packet or in the response
+packet.
+
+The ``timestamp-format`` parameter can be used to change the timestamp logged
+at the beginning of each line. Permissible formatting is the one supported by
+strftime plus the '%Q' extra format which adds the microseconds subunits. The
+default is: "%Y-%m-%d %H:%M:%S %Z". This parameter has no effect for the
+database backends, where the timestamp is defined at the schema level.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "path": "/var/lib/kea/log",
+ "base-name": "kea-forensic6",
+ "timestamp-format": "%H%t%w %F%%"
+ }
+ }
+ ]
+ }
+ }
+
+Additional parameters for the database connection can be specified, e.g:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "name": "database-name",
+ "password": "passwd",
+ "type": "mysql",
+ "user": "user-name"
+ }
+ }
+ ]
+ }
+ }
+
+For more specific information about database-related parameters, please refer to
+:ref:`database-configuration4` and :ref:`database-configuration6`.
+
+If it is desired to restrict forensic logging to certain subnets, the
+``"legal-logging"`` boolean parameter can be specified within a user context
+of these subnets. For example:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "subnet4": [
+ {
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [
+ {
+ "pool": "192.0.2.1 - 192.0.2.200"
+ }
+ ],
+ "user-context": {
+ "legal-logging": false
+ }
+ }
+ ]
+ }
+ }
+
+This configuration disables legal logging for the subnet "192.0.2.0/24". If the
+``"legal-logging"`` parameter is not specified, it defaults to ``true``, which
+enables legal logging for the subnet.
+
+The following example demonstrates how to selectively disable legal
+logging for an IPv6 subnet:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8:1::/64",
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::ffff"
+ }
+ ],
+ "user-context": {
+ "legal-logging": false
+ }
+ }
+ ]
+ }
+ }
+
+See :ref:`dhcp4-user-contexts` and :ref:`dhcp6-user-contexts` to
+learn more about user contexts in Kea configuration.
+
+DHCPv4 Log Entries
+~~~~~~~~~~~~~~~~~~
+
+For DHCPv4, the library creates entries based on DHCPREQUEST, DHCPDECLINE,
+and DHCPRELEASE messages, et al., and their responses. The resulting packets and
+leases are taken into account, intercepted through the following hook points:
+
+* ``pkt4_receive``
+* ``leases4_committed``
+* ``pkt4_send``
+* ``lease4_release``
+* ``lease4_decline``
+
+An entry is a single string with no embedded end-of-line markers and a
+prepended timestamp, and has the following sections:
+
+::
+
+ timestamp address duration device-id {client-info} {relay-info} {user-context}
+
+Where:
+
+- ``timestamp`` - the date and time the log entry was written, in
+ "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name).
+
+- ``address`` - the leased IPv4 address given out, and whether it was
+ assigned, renewed, or released.
+
+- ``duration`` - the lease lifetime expressed in days (if present), hours,
+ minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted
+ with the text "infinite duration." This information is not given
+ when the lease is released.
+
+- ``device-id`` - the client's hardware address shown as a numerical type and
+ hex-digit string.
+
+- ``client-info`` - the DHCP client id option (61) if present, shown as a
+ hex string. When its content is printable it is displayed.
+
+- ``relay-info`` - for relayed packets, the ``giaddr`` and the RAI ``circuit-id``,
+ ``remote-id``, and ``subscriber-id`` options (option 82 sub options: 1, 2 and 6),
+ if present. The ``circuit-id`` and ``remote-id`` are presented as hex
+ strings. When their content is printable it is displayed.
+
+- ``user-context`` - the optional user context associated with the lease.
+
+For instance (line breaks are added here for readability; they are not
+present in the log file):
+
+::
+
+ 2018-01-06 01:02:03 CET Address: 192.2.1.100 has been renewed for 1 hrs 52 min 15 secs to a device with hardware address:
+ hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33,
+ identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef
+
+or for a release:
+
+::
+
+ 2018-01-06 01:02:03 CET Address: 192.2.1.100 has been released from a device with hardware address:
+ hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33,
+ identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef
+
+In addition to logging lease activity driven by DHCPv4 client traffic,
+the hook library also logs entries for the following lease management control
+channel commands: :isccmd:`lease4-add`, :isccmd:`lease4-update`, and :isccmd:`lease4-del`. These cannot have
+custom formatting. Each entry is a single string with no embedded end-of-line
+markers, and it will typically have the following form:
+
+``lease4-add:``
+
+::
+
+ *timestamp* Administrator added a lease of address: *address* to a device with hardware address: *device-id*
+
+Depending on the arguments of the add command, it may also include the
+client-id and duration.
+
+Example:
+
+::
+
+ 2018-01-06 01:02:03 CET Administrator added a lease of address: 192.0.2.202 to a device with hardware address:
+ 1a:1b:1c:1d:1e:1f for 1 days 0 hrs 0 mins 0 secs
+
+``lease4-update:``
+
+::
+
+ *timestamp* Administrator updated information on the lease of address: *address* to a device with hardware address: *device-id*
+
+Depending on the arguments of the update command, it may also include
+the client-id and lease duration.
+
+Example:
+
+::
+
+ 2018-01-06 01:02:03 CET Administrator updated information on the lease of address: 192.0.2.202 to a device
+ with hardware address: 1a:1b:1c:1d:1e:1f, client-id: 1234567890
+
+``lease4-del:`` deletes have two forms, one by address and one by
+identifier and identifier type:
+
+::
+
+ *timestamp* Administrator deleted the lease for address: *address*
+
+or
+
+::
+
+ *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier*
+
+Currently only a type of ``@b hw-address`` (hardware address) is supported.
+
+Examples:
+
+::
+
+ 2018-01-06 01:02:03 CET Administrator deleted the lease for address: 192.0.2.202
+
+ 2018-01-06 01:02:12 CET Administrator deleted a lease for a device identified by: hw-address of 1a:1b:1c:1d:1e:1f
+
+If High availability module is enabled, the partner will periodically send lease
+commands which have a similar format, the only difference is that the issuer of
+the command is 'HA partner' instead of 'Administrator'.
+
+::
+
+ *timestamp* HA partner added ...
+
+or
+
+::
+
+ *timestamp* HA partner updated ...
+
+or
+
+::
+
+ *timestamp* HA partner deleted ...
+
+The ``request-parser-format`` and ``response-parser-format`` options can be used to
+extract and log data from the incoming packet and server response packet,
+respectively. The configured value is an evaluated parsed expression returning a
+string. A list of tokens is described in the server classification process.
+Use with caution as this might affect server performance.
+If either of them is configured, the default logging format is not used.
+If both of them are configured, the resulting log message is constructed by
+concatenating the logged data extracted from the request and the logged data
+extracted from the response.
+
+The custom formatting permits logging on multiple lines using the hexstring 0x0a
+(ASCII code for new line). In the case of the log file, each line is prepended
+with the log timestamp. For the database backend, the data is stored
+(including the newline character) in the same entry.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "name": "database-name",
+ "password": "passwd",
+ "type": "mysql",
+ "user": "user-name",
+ "request-parser-format": "'log entry' + 0x0a + 'same log entry'",
+ "response-parser-format": "'also same log entry' + 0x0a + 'again same log entry'"
+ }
+ }
+ ]
+ }
+ }
+
+Some data might be available in the request or in the response only, and some
+data might differ in the incoming packet from the one in the response packet.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "request-parser-format": "ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), '')",
+ "response-parser-format": "ifelse(pkt4.msgtype == 5, 'Address: ' + addrtotext(pkt4.yiaddr) + ' has been assigned for ' + uint32totext(option[51].hex) + ' seconds to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), '')"
+ }
+
+Details:
+
+.. raw:: html
+
+ <details><summary>Expand here!</summary>
+ <pre>{
+ "request-parser-format":
+ "ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7,
+ 'Address: ' +
+ ifelse(option[50].exists,
+ addrtotext(option[50].hex),
+ addrtotext(pkt4.ciaddr)) +
+ ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
+ ifelse(option[61].exists,
+ ', client-id: ' + hexstring(option[61].hex, ':'),
+ '') +
+ ifelse(pkt4.giaddr == 0.0.0.0,
+ '',
+ ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
+ ifelse(option[82].option[1].exists,
+ ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
+ '') +
+ ifelse(option[82].option[2].exists,
+ ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
+ '') +
+ ifelse(option[82].option[6].exists,
+ ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
+ '')),
+ '')",
+ "response-parser-format":
+ "ifelse(pkt4.msgtype == 5,
+ 'Address: ' + addrtotext(pkt4.yiaddr) + ' has been assigned for ' + uint32totext(option[51].hex) + ' seconds to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
+ ifelse(option[61].exists,
+ ', client-id: ' + hexstring(option[61].hex, ':'),
+ '') +
+ ifelse(pkt4.giaddr == 0.0.0.0,
+ '',
+ ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
+ ifelse(option[82].option[1].exists,
+ ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
+ '') +
+ ifelse(option[82].option[2].exists,
+ ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
+ '') +
+ ifelse(option[82].option[6].exists,
+ ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
+ '')),
+ '')"
+ }</pre>
+ </details><br>
+
+This will log the following data on request and renew:
+
+::
+
+ Address: 192.2.1.100 has been assigned for 6735 seconds to a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, circuit-id: 68:6f:77:64:79, remote-id: 87:f6:79:77:ef, subscriber-id: 1a:2b:3c:4d:5e:6f
+
+This will log the following data on release and decline:
+
+::
+
+ Address: 192.2.1.100 has been released from a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, circuit-id: 68:6f:77:64:79, remote-id: 87:f6:79:77:ef, subscriber-id: 1a:2b:3c:4d:5e:6f
+
+A similar result can be obtained by configuring only ``request-parser-format``.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "request-parser-format": "ifelse(pkt4.msgtype == 3, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been assigned' + ifelse(option[51].exists, ' for ' + uint32totext(option[51].hex) + ' seconds', '') + ' to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), ''))"
+ }
+
+Details:
+
+.. raw:: html
+
+ <details><summary>Expand here!</summary>
+ <pre>{
+ "request-parser-format":
+ "ifelse(pkt4.msgtype == 3,
+ 'Address: ' +
+ ifelse(option[50].exists,
+ addrtotext(option[50].hex),
+ addrtotext(pkt4.ciaddr)) +
+ ' has been assigned' +
+ ifelse(option[51].exists,
+ ' for ' + uint32totext(option[51].hex) + ' seconds',
+ '') +
+ ' to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
+ ifelse(option[61].exists,
+ ', client-id: ' + hexstring(option[61].hex, ':'),
+ '') +
+ ifelse(pkt4.giaddr == 0.0.0.0,
+ '',
+ ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
+ ifelse(option[82].option[1].exists,
+ ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
+ '') +
+ ifelse(option[82].option[2].exists,
+ ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
+ '') +
+ ifelse(option[82].option[6].exists,
+ ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
+ '')),
+ ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7,
+ 'Address: ' +
+ ifelse(option[50].exists,
+ addrtotext(option[50].hex),
+ addrtotext(pkt4.ciaddr)) +
+ ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
+ ifelse(option[61].exists,
+ ', client-id: ' + hexstring(option[61].hex, ':'),
+ '') +
+ ifelse(pkt4.giaddr == 0.0.0.0,
+ '',
+ ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
+ ifelse(option[82].option[1].exists,
+ ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
+ '') +
+ ifelse(option[82].option[2].exists,
+ ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
+ '') +
+ ifelse(option[82].option[6].exists,
+ ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
+ '')),
+ ''))"
+ }</pre>
+ </details><br>
+
+DHCPv6 Log Entries
+~~~~~~~~~~~~~~~~~~
+
+For DHCPv6, the library creates entries based on REQUEST, RENEW, RELEASE,
+and DECLINE messages, et al. and their responses. The resulting packets and leases
+are taken into account, intercepted through the following hook points:
+
+* ``pkt6_receive``
+* ``leases6_committed``
+* ``pkt6_send``
+* ``lease6_release``
+* ``lease6_decline``
+
+An entry is a single string with no embedded end-of-line markers and a
+prepended timestamp, and has the following sections:
+
+::
+
+ timestamp address duration device-id {relay-info}* {user-context}
+
+Where:
+
+- ``timestamp`` - the date and time the log entry was written, in
+ "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name).
+
+- ``address`` - the leased IPv6 address or prefix given out, and whether it
+ was assigned, renewed, or released.
+
+- ``duration`` - the lease lifetime expressed in days (if present), hours,
+ minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted
+ with the text "infinite duration." This information is not given
+ when the lease is released.
+
+- ``device-id`` - the client's DUID and hardware address (if present).
+
+- ``relay-info`` - for relayed packets the content of relay agent messages, and the
+ ``remote-id`` (code 37), ``subscriber-id`` (code 38), and ``interface-id`` (code 18)
+ options, if present. Note that the ``interface-id`` option, if present,
+ identifies the whole interface on which the relay agent received the message.
+ This typically translates to a single link in the network, but
+ it depends on the specific network topology. Nevertheless, this is
+ useful information to better pinpoint the location of the device,
+ so it is recorded, if present.
+
+- ``user-context`` - the optional user context associated with the lease.
+
+For instance (line breaks are added here for readability; they are not
+present in the log file):
+
+::
+
+ 2018-01-06 01:02:03 PST Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs
+ to a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e
+ (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1,
+ hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f
+
+or for a release:
+
+::
+
+ 2018-01-06 01:02:03 PST Address:2001:db8:1:: has been released
+ from a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e
+ (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1,
+ hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f
+
+In addition to logging lease activity driven by DHCPv6 client traffic,
+the hook library also logs entries for the following lease management control channel
+commands: :isccmd:`lease6-add`, :isccmd:`lease6-update`, and :isccmd:`lease6-del`. Each entry is a
+single string with no embedded end-of-line markers, and it will
+typically have the following form:
+
+``lease6-add:``
+
+::
+
+ *timestamp* Administrator added a lease of address: *address* to a device with DUID: *DUID*
+
+Depending on the arguments of the add command, it may also include the
+hardware address and duration.
+
+Example:
+
+::
+
+ 2018-01-06 01:02:03 PST Administrator added a lease of address: 2001:db8::3 to a device with DUID:
+ 1a:1b:1c:1d:1e:1f:20:21:22:23:24 for 1 days 0 hrs 0 mins 0 secs
+
+``lease6-update:``
+
+::
+
+ *timestamp* Administrator updated information on the lease of address: *address* to a device with DUID: *DUID*
+
+Depending on the arguments of the update command, it may also include
+the hardware address and lease duration.
+
+Example:
+
+::
+
+ 2018-01-06 01:02:03 PST Administrator updated information on the lease of address: 2001:db8::3 to a device with
+ DUID: 1a:1b:1c:1d:1e:1f:20:21:22:23:24, hardware address: 1a:1b:1c:1d:1e:1f
+
+``lease6-del:`` deletes have two forms, one by address and one by
+identifier and identifier type:
+
+::
+
+ *timestamp* Administrator deleted the lease for address: *address*
+
+or
+
+::
+
+ *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier*
+
+Currently only a type of ``DUID`` is supported.
+
+Examples:
+
+::
+
+ 2018-01-06 01:02:03 PST Administrator deleted the lease for address: 2001:db8::3
+
+ 2018-01-06 01:02:11 PST Administrator deleted a lease for a device identified by: duid of 1a:1b:1c:1d:1e:1f:20:21:22:23:24
+
+If High availability module is enabled, the partner will periodically send lease
+commands which have a similar format, the only difference is that the issuer of
+the command is 'HA partner' instead of 'Administrator'.
+
+::
+
+ *timestamp* HA partner added ...
+
+or
+
+::
+
+ *timestamp* HA partner updated ...
+
+or
+
+::
+
+ *timestamp* HA partner deleted ...
+
+The ``request-parser-format`` and ``response-parser-format`` options can be used to
+extract and log data from the incoming packet and server response packet,
+respectively. The configured value is an evaluated parsed expression returning a
+string. A list of tokens is described in the server classification process.
+Use with caution as this might affect server performance.
+If either of them is configured, the default logging format is not used.
+If both of them are configured, the resulting log message is constructed by
+concatenating the logged data extracted from the request and the logged data
+extracted from the response.
+
+The custom formatting permits logging on multiple lines using the hexstring 0x0a
+(ASCII code for new line). In the case of the log file, each line is prepended
+with the log timestamp. For the database backend, the data is stored
+(including the newline character) in the same entry.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
+ "parameters": {
+ "name": "database-name",
+ "password": "passwd",
+ "type": "mysql",
+ "user": "user-name",
+ "request-parser-format": "'log entry' + 0x0a + 'same log entry'",
+ "response-parser-format": "'also same log entry' + 0x0a + 'again same log entry'"
+ }
+ }
+ ]
+ }
+ }
+
+Some data might be available in the request or in the response only, and some
+data might differ in the incoming packet from the one in the response packet.
+
+Notes:
+
+In the case of IPv6, the packets can contain multiple IA_NA (3) or IA_PD (25)
+options, each containing multiple options, including OPTION_IAADDR (5) or
+OPTION_IAPREFIX (25) suboptions.
+To be able to print the current lease associated with the log entry, the
+forensic log hook library internally isolates the corresponding IA_NA or IA_PD
+option and respective suboption matching the current lease.
+The hook library will iterate over all new allocated addresses and all deleted
+addresses, making each address available for logging as the current lease for
+the respective logged entry.
+
+They are accessible using the following parser expressions:
+
+Current lease associated with OPTION_IAADDR:
+
+::
+
+ addrtotext(substring(option[3].option[5].hex, 0, 16))
+
+Current lease associated with OPTION_IAPREFIX:
+
+::
+
+ addrtotext(substring(option[25].option[26].hex, 9, 16))
+
+All other parameters of the options are available at their respective offsets
+in the option. Please read RFC8415 for more details.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "request-parser-format": "ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), '')",
+ "response-parser-format": "ifelse(pkt6.msgtype == 7, ifelse(option[3].option[5].exists and not (substring(option[3].option[5].hex, 20, 4) == 0), 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists and not (substring(option[25].option[26].hex, 4, 4) == 0), 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), '')"
+ }
+
+Details:
+
+.. raw:: html
+
+ <details><summary>Expand here!</summary>
+ <pre>{
+ "request-parser-format":
+ "ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9,
+ ifelse(option[3].option[5].exists,
+ 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ '') +
+ ifelse(option[25].option[26].exists,
+ 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ ''),
+ '')",
+ "response-parser-format":
+ "ifelse(pkt6.msgtype == 7,
+ ifelse(option[3].option[5].exists and not (substring(option[3].option[5].hex, 20, 4) == 0),
+ 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ '') +
+ ifelse(option[25].option[26].exists and not (substring(option[25].option[26].hex, 4, 4) == 0),
+ 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ ''),
+ '')"
+ }</pre>
+ </details><br>
+
+This will log the following data on request, renew, and rebind for NA:
+
+::
+
+ Address: 2001:db8:1:: has been assigned for 713 seconds to a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30
+
+This will log the following data on request, renew and rebind for PD:
+
+::
+
+ Prefix: 2001:db8:1::/64 has been assigned for 713 seconds to a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30
+
+This will log the following data on release and decline for NA:
+
+::
+
+ Address: 2001:db8:1:: has been released from a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30
+
+This will log the following data on release and decline for PD:
+
+::
+
+ Prefix: 2001:db8:1::/64 has been released from a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30
+
+A similar result can be obtained by configuring only ``request-parser-format``.
+
+Examples:
+
+.. code-block:: json
+
+ {
+ "request-parser-format": "ifelse(pkt6.msgtype == 3 or pkt6.msgtype == 5 or pkt6.msgtype == 6, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), ''))"
+ }
+
+Details:
+
+.. raw:: html
+
+ <details><summary>Expand here!</summary>
+ <pre>{
+ "request-parser-format":
+ "ifelse(pkt6.msgtype == 3 or pkt6.msgtype == 5 or pkt6.msgtype == 6,
+ ifelse(option[3].option[5].exists,
+ 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ '') +
+ ifelse(option[25].option[26].exists,
+ 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ ''),
+ ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9,
+ ifelse(option[3].option[5].exists,
+ 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ '') +
+ ifelse(option[25].option[26].exists,
+ 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
+ ifelse(relay6[0].peeraddr == '',
+ '',
+ ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
+ ifelse(relay6[0].option[37].exists,
+ ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[38].exists,
+ ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
+ '') +
+ ifelse(relay6[0].option[18].exists,
+ ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
+ '')),
+ ''),
+ ''))"
+ }</pre>
+ </details><br>
+
+.. _forensic-log-database:
+
+Database Backend
+~~~~~~~~~~~~~~~~
+
+Log entries can be inserted into a database when Kea is configured with
+database backend support. Kea uses a table named ``logs``, that includes a
+timestamp generated by the database software, and a text log with the same
+format as files without the timestamp.
+
+Please refer to :ref:`mysql-database` for information on using a MySQL database;
+or to :ref:`pgsql-database` for PostgreSQL database information. The ``logs``
+table is part of the Kea database schemas.
+
+Configuration parameters are extended by standard lease database
+parameters as defined in :ref:`database-configuration4`. The ``type``
+parameter should be ``mysql``, ``postgresql`` or ``logfile``; when
+it is absent or set to ``logfile``, files are used.
+
+This database feature is experimental. No specific tools are provided
+to operate the database, but standard tools may be used, for example,
+to dump the logs table from a MYSQL database:
+
+::
+
+ $ mysql --user keatest --password keatest -e "select * from logs;"
+ +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+
+ | timestamp | address | log | id |
+ +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+
+ | 2022-03-30 17:38:41 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 31 |
+ | 2022-03-30 17:38:43 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 32 |
+ | 2022-03-30 17:38:45 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 33 |
+ +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+
+
+Like all the other database-centric features, forensic logging supports database
+connection recovery, which can be enabled by setting the ``on-fail`` parameter.
+If not specified, the ``on-fail`` parameter in forensic logging defaults to
+``serve-retry-continue``. This is different than for
+:ischooklib:`libdhcp_lease_cmds.so`, :ischooklib:`libdhcp_host_cmds.so`, and
+:ischooklib:`libdhcp_cb_cmds.so`, where
+``on-fail`` defaults to ``stop-retry-exit``. In this case, the server continues
+serving clients and does not shut down even if the recovery mechanism fails.
+If ``on-fail`` is set to ``serve-retry-exit``, the server will shut down if
+the connection to the database backend is not restored according to the
+``max-reconnect-tries`` and ``reconnect-wait-time`` parameters, but it
+continues serving clients while this mechanism is activated.
+
+During server startup, the inability to connect to any of the configured
+backends is considered fatal only if ``retry-on-startup`` is set to ``false``
+(the default). A fatal error is logged and the server exits, based on the idea
+that the configuration should be valid at startup. Exiting to the operating
+system allows nanny scripts to detect the problem.
+If ``retry-on-startup`` is set to ``true``, the server will start reconnection
+attempts even at server startup or on reconfigure events, and will honor the
+action specified in the ``on-fail`` parameter.
diff --git a/doc/sphinx/arm/hooks-limits.rst b/doc/sphinx/arm/hooks-limits.rst
new file mode 100644
index 0000000..42bb39a
--- /dev/null
+++ b/doc/sphinx/arm/hooks-limits.rst
@@ -0,0 +1,211 @@
+.. ischooklib:: libdhcp_limits.so
+.. _hooks-limits:
+
+``libdhcp_limits.so``: Limits to Manage Lease Allocation and Packet Processing
+==============================================================================
+
+This hook library enables two types of limits:
+
+1. Lease limiting: allow a maximum of ``n`` leases assigned at any one time.
+2. Rate limiting: allow a maximum of ``n`` packets per ``time_unit`` to receive a response.
+
+.. note::
+
+ :ischooklib:`libdhcp_limits.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. _hooks-limits-configuration:
+
+Configuration
+~~~~~~~~~~~~~
+
+The following examples are for :iscman:`kea-dhcp6`, but they apply equally to
+:iscman:`kea-dhcp4`. The wildcards ``"<limit-type>"`` and ``"<limit-value>"`` need to be replaced
+with the respective keys and values for each limit type described in the sections following this
+one.
+
+The library can be loaded by both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` servers by adding its path in the
+``"hooks-libraries"`` element of the server's configuration.
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_limits.so"
+ }
+ ]
+ }
+ }
+
+This alone does not limit anything. The desired limits are added to the user context in the
+configuration portion of the element that identifies the clients to be limited: a client class or a
+subnet. Upon reconfiguration, if Kea picked up on the configured limits, it logs one line for
+each configured limit. The log message contains ``LIMITS_CONFIGURED`` in its identifier.
+
+This is how a lease limit is defined for a client class:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "cable-modem-1",
+ "test": "option[123].hex == 0x000C4B1E",
+ "user-context": {
+ "limits": {
+ "<limit>": "<limit-value>"
+ }
+ }
+ }
+ ]
+ }
+ }
+
+This is how a lease limit is defined for a global subnet:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "user-context": {
+ "limits": {
+ "<limit>": "<limit-value>"
+ }
+ }
+ }
+ ]
+ }
+ }
+
+This is how a lease limit is defined for a subnet inside a shared network:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "shared-networks": [
+ {
+ "subnet6": [
+ {
+ "id": 1,
+ "subnet": "2001:db8::/64",
+ "user-context": {
+ "limits": {
+ "<limit>": "<limit-value>"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. note::
+
+ The Limits hook library uses the class name to identify a client class and the subnet ID to
+ identify a subnet. Changing a test expression in a client class or the network range of a
+ subnet while leaving the name or ID unchanged does not reset the lease count for the
+ respective client class or subnet. To reset the lease count, change the client class name
+ or the subnet ID.
+
+.. note::
+
+ Database connection retries are not attempted on startup if the
+ :ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a
+ valid connection to the database to check if JSON format is supported and to
+ recount class limits.
+
+.. _hooks-limits-lease-limiting:
+
+Lease Limiting
+~~~~~~~~~~~~~~
+
+It is possible to limit the number of leases that a group of clients can get from a Kea DHCP server
+or from a set of collaborating Kea DHCP servers.
+
+The value of a lease limit can be specified as an unsigned integer in 32 bits, i.e. between ``0`` and
+``4,294,967,295``. Each lease type can be limited individually. IPv4 leases and IPv6 IA_NA leases
+are limited through the ``"address-limit"`` configuration entry. IPv6 IA_PD leases are limited
+through the ``"prefix-limit"`` configuration entry. Here are some examples:
+
+* ``"address-limit": 4``
+* ``"prefix-limit": 2``
+
+For lease limiting, client classes and the associated lease counts - which are
+checked against the configured limits - are updated for each lease in the following hook callouts:
+
+* ``lease4_select``
+* ``lease4_renew``
+* ``lease6_select``
+* ``lease6_renew``
+* ``lease6_rebind``
+
+As a result, classes for which ``"only-if-required"`` is "true" cannot be lease-limited.
+Please refer to :ref:`the classification steps <classify-classification-steps>` for more information on which
+client classes can be used to limit the number of leases.
+
+.. note::
+
+ Under load, a Kea DHCP server may allocate more leases than the limit strictly allows. This only has a chance of
+ happening during high traffic surges, coming from clients belonging to the same class or the
+ same subnet, depending on what is limited. Users may be interested in following the development of
+ `atomic lease limits <https://gitlab.isc.org/isc-projects/kea/-/issues/2449>`__ in ISC's GitLab instance.
+
+.. _hooks-limits-rate-limiting:
+
+Rate Limiting
+~~~~~~~~~~~~~
+
+It is possible to limit the frequency or rate at which inbound packets receive a response.
+
+The value of a rate limit can be specified in the format ``"<p> packets per <time-unit>"``. ``<p>``
+is any number that can be represented by an unsigned integer in 32 bits, i.e. between ``0`` and
+``4,294,967,295``. ``<time-unit>`` can be any of ``second``, ``minute``, ``hour``, ``day``,
+``week``, ``month``, or ``year``. A ``month`` is considered to be 30 days for
+simplicity; similarly, a ``year`` is 365 days for limiting purposes. This syntax
+covers a wide range of rates, from one lease per year to four billion leases per
+second. This value is assigned to the ``"rate-limit"`` configuration entry.
+Here are some examples:
+
+* ``"rate-limit": 1 packet per second``
+* ``"rate-limit": 4 packets per minute``
+* ``"rate-limit": 16 packets per hour``
+
+The configured value of ``0`` packets is a convenient way of disabling packet processing for certain
+clients entirely. As such, it means its literal value and is not a special value for disabling
+limiting altogether, as might be imagined. Disabling limiting entirely is achieved by removing
+the ``"rate-limit"`` leaf configuration entry, the ``"limits"`` map or user context
+around it, or the hook library configuration. The same applies to the value of ``0`` in lease
+limiting. However, that use case is best achieved with rate limiting; it puts less computational
+strain on Kea, since the action of dropping the request or sending a NAK is decided earlier.
+
+In terms of rate limiting, client classes are evaluated at the ``pkt4_receive`` and the
+``pkt6_receive`` callout, respectively, so that rate limits are checked as early as possible in the
+packet-processing cycle. Thus, only those classes which are assigned to the packet solely via an
+independent test expression can be used. Classes that depend on host reservations or the special
+``BOOTP`` or ``KNOWN`` classes, and classes that are marked with ``"only-if-required": true``,
+cannot be rate limited. See :ref:`the classification steps <classify-classification-steps>` for
+more details on which client classes can be used to limit the packet rate.
+
+Rate limits based on subnet are enforced only on the initially selected subnet for a given packet.
+If the selected subnet is subsequently changed, as may be the case for subnets in a
+shared network or when reselection is enabled in libraries such as the RADIUS hook, rate
+limits on the newly selected subnet are ignored. In other words, packets are gated only by
+the rate limit on the original subnet.
+
+.. note::
+
+ It may seem logical to think that assigning a rate limit of ``n`` packets per time unit results
+ in ``n`` DORA or ``n`` SARR exchanges. However, by default, all inbound packets are counted - meaning
+ that a full message exchange accounts for two packets. To achieve the effect of counting an
+ exchange only once, use client-class rate-limiting with a test expression that binds
+ ``pkt4.msgtype`` to DHCPDISCOVER messages or ``pkt6.msgtype`` to SOLICIT messages.
diff --git a/doc/sphinx/arm/hooks-perfmon.rst b/doc/sphinx/arm/hooks-perfmon.rst
new file mode 100644
index 0000000..3c039dc
--- /dev/null
+++ b/doc/sphinx/arm/hooks-perfmon.rst
@@ -0,0 +1,39 @@
+.. ischooklib:: libdhcp_perfmon.so
+.. _hooks-perfmon:
+
+``libdhcp_perfmon.so``: PerfMon
+===============================
+
+This hook library can be loaded by either kea-dhcp4 or kea-dhcp6 servers
+to extend them with the ability to track and report performance related data.
+
+.. note::
+
+ This library is currently under development and not yet functional.
+
+Overview
+~~~~~~~~
+
+The library, added in Kea 2.5.6, can be loaded by the :iscman:`kea-dhcp4` or
+:iscman:`kea-dhcp6` daemon by adding it to the ``hooks-libraries`` element of
+the server's configuration:
+
+.. code-block:: javascript
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_perfmon.so",
+ "parameters": {
+ ...
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+Configuration
+~~~~~~~~~~~~~
+
+ TBD
diff --git a/doc/sphinx/arm/hooks-ping-check.rst b/doc/sphinx/arm/hooks-ping-check.rst
new file mode 100644
index 0000000..efa2fef
--- /dev/null
+++ b/doc/sphinx/arm/hooks-ping-check.rst
@@ -0,0 +1,169 @@
+.. ischooklib:: libdhcp_ping_check.so
+.. _hooks-ping-check:
+
+``libdhcp_ping_check.so``: Ping Check
+=====================================
+
+This hook library adds the ability to perform a "ping check" of a candidate
+IPv4 address prior to offering it to a DHCP client. This feature is similar
+to a behavior available in ISC DHCP and one suggested in `RFC
+2131 <https://tools.ietf.org/html/rfc2131>`__ , see section 3.1, item 2.
+
+.. note::
+
+ :ischooklib:`libdhcp_ping_check.so` is available only to ISC customers
+ with a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+Overview
+~~~~~~~~
+
+The library, added in Kea 2.5.4, can be loaded by the :iscman:`kea-dhcp4` daemon
+by adding it to the ``hooks-libraries`` element of the server's configuration:
+
+.. code-block:: javascript
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_ping_check.so",
+ "parameters": {
+ ...
+ }
+ },
+ ...
+ ],
+ ...
+ }
+
+When the library is loaded :iscman:`kea-dhcp4` will conduct a ping-check prior to
+offering a lease to client if all of the following conditions are true:
+
+1. Ping check hook library is loaded.
+
+2. Ping checking is enabled.
+
+3. The server is responding to a DHCPDISCOVER.
+
+4. The candidate lease is neither active nor reserved.
+
+5. Any of the following are true:
+
+ a. This is the first offer of this lease to this client. This check
+ can only be done if `offer-lifetime` is greater than zero (i.e. temporary
+ allocation on DHCPDISCOVER is enabled). If `offer-lifetime` is zero
+ ping checks are done for every DHCPOFFER as the server has no way to
+ know it has made prior offers.
+
+ b. The lease is being offered to a client other than its previous owner.
+
+ c. The lease is being offered to its previous owner and more than a
+ configurable number of seconds, `ping-cltt-secs`, have elapsed since
+ CLTT of the original lease.
+
+When the ping check library is loaded, in response to a DHCPDISCOVER the
+:iscman:`kea-dhcp4` will:
+
+1. Select a candidate IPv4 address through normal processes and use it to
+construct a DHCPOFFER.
+
+2. Park the DHCPOFFER and request a ping-check from the ping-check hook
+library via its `lease4_offer` callout.
+
+3. The callout will test conditions described above. If they are not
+satisfied it will return without conducting a check, and the server
+will send the DHCPOFFER to the client. Otherwise the callout will
+initiate a ping-check for the lease address.
+
+4. Upon conclusion of the ping-check, the server will either send the DHCPOFFER
+to the client if the check concluded that the address is available, or discard
+the DHCPFOFFER and create a DECLINED lease for the address.
+
+Each ping-check consists of the following steps:
+
+1. If the number of ECHO REPLYs sent is less than the configured
+minimum number to send, send an ICMP ECHO REQUEST to the lease address.
+Otherwise, conclude that the address is available.
+
+2. If no ECHO REPLY is received within a configurable amount of time
+return to step 1.
+
+3. Upon receipt of an ICMP ECHO REPLY, conclude that the lease is NOT available.
+
+4. Any of the following occur:
+
+ a. Receipt of an ICMP DESTINATION UNREACHABLE message
+ b. Send fail of an ICMP ECHO REQUEST due to a network error (e.g. network is unreachable)
+ c. Send fail of an ICMP ECHO REQUEST due to a permissions error (e.g. lease address is a broadcast address)
+ d. Send fail of an ICMP ECHO REQUEST with socket buffer full error
+
+ In each of these instances the address could not be checked and is treated as
+ available.
+
+.. note::
+
+ Socket buffer full of errors indicates that the OS rate limits on ICMP are
+ being exceeded. The server will not retry them as this would likely only
+ exacerbate the situation. If this occurs continuously then the client load
+ on the server may be too high to accommodate ping checking. Ping checking is
+ not recommended for systems with high throughput demands.
+
+Configuration
+~~~~~~~~~~~~~
+
+The ping-check hook library currently supports the following configuration parameters
+that may be set at the global and subnet levels. Subnet values override global values.
+
+- `enable-ping-check` - Enables or disables ping checking at a given scope.
+
+- `min-ping-requests` - The minimum number of ECHO REQUESTs sent without receiving a reply needed to declare an address available. The default is 1, it must be greater than zero.
+
+- `reply-timeout` - The maximum amount of time to wait for a reply to a single ECHO REQUEST. Specified in milliseconds, it must be greater than zero, it defaults to 100.
+
+- `ping-cltt-secs` - The number of seconds that must elapse after the lease's CLTT before a ping check will be conducted when the client is the lease's previous owner. The default value is sixty seconds.
+
+The following parameter is only supported at the global level:
+
+- `ping-channel-threads` - In multi-threaded mode, this is the number of threads in the channel's thread pool. The default is 0 which instructs the library to use the same number of threads as Kea core. The value is ignored if given when Kea is in single-threaded mode.
+
+The following configuration excerpt illustrates global level configuration:
+
+.. code-block:: javascript
+
+ {
+ "hooks-libraries": [{
+ "library": "lib/kea/hooks/libdhcp_ping_check.so",
+ "parameters": {
+ "enable-ping-check" : true,
+ "min-ping-requests" : 1,
+ "reply-timeout" : 100,
+ "ping-cltt-secs" : 60,
+ "ping-channel-threads" : 0
+ }
+ }]
+ }
+
+The following excerpt demonstrates subnet level configuration:
+
+.. code-block:: javascript
+
+ {
+ "subnet4": [{
+ "subnet": "192.0.2.0/24",
+ "pools": [{
+ "pool": "192.0.2.10 - 192.0.2.20"
+ }],
+
+ "user-context": {
+ "enable-ping-check" : true,
+ "min-ping-requests" : 2,
+ "reply-timeout" : 250,
+ "ping-cltt-secs" : 120
+ }
+ }]
+ }
+
+.. note::
+
+ Ping checking is an experimental feature. It is not currently recommended for
+ production environments.
diff --git a/doc/sphinx/arm/hooks-radius.rst b/doc/sphinx/arm/hooks-radius.rst
new file mode 100644
index 0000000..8f1336d
--- /dev/null
+++ b/doc/sphinx/arm/hooks-radius.rst
@@ -0,0 +1,16 @@
+.. ischooklib:: libdhcp_radius.so
+.. _hooks-radius:
+
+``libdhcp_radius.so``: RADIUS Server Support
+============================================
+
+This hook library allows the Kea DHCP servers to use the RADIUS protocol to
+authorize DHCP clients through the access service or for DHCP lease journaling
+through the accounting service. For details on RADIUS in Kea, please see
+:ref:`radius`.
+
+.. note::
+
+ :ischooklib:`libdhcp_radius.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
diff --git a/doc/sphinx/arm/hooks-rbac.rst b/doc/sphinx/arm/hooks-rbac.rst
new file mode 100644
index 0000000..1df4dd5
--- /dev/null
+++ b/doc/sphinx/arm/hooks-rbac.rst
@@ -0,0 +1,587 @@
+.. ischooklib:: libca_rbac.so
+.. _hooks-RBAC:
+
+``libca_rbac.so``: Role-Based Access Control
+============================================
+
+.. _hooks-RBAC-overview:
+
+Role-Based Access Control (RBAC) Overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before the processing of commands in received HTTP requests, :ischooklib:`libca_rbac.so`
+takes specific parameters, e.g. the common-name part of the client
+certificate subject name, to assign a role to the request.
+The configuration associated with this role is used to accept or reject
+the command. After processing, the response can be rewritten, e.g.
+parts can be removed.
+
+Here is a summary of the steps in processing a request:
+ - The HTTP library records some information to be used later, e.g.
+ the remote address.
+ - When TLS is required but the request was not protected by TLS,
+ the request is rejected by sending an "unauthorized" response.
+ - The command is extracted from the request.
+ - A role is assigned using recorded information in the request.
+ - The role is used to accept (pass through) or reject (send
+ a forbidden response to) the command.
+
+Here is a summary of the steps in processing a response:
+ - The information attached to the request is retrieved during the
+ request processing (when the request was accepted).
+ - Request filters are applied to the response.
+
+.. note::
+
+ :ischooklib:`libca_rbac.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. _hooks-RBAC-config:
+
+Role-Based Access Control Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Role Assignment
+---------------
+
+Role assignment is governed by the configured role-assignment method.
+
+.. table:: Role assignment methods
+
+ +----------------------+---------------------------------------------------------+
+ | Name | Description |
+ +----------------------+---------------------------------------------------------+
+ | remote-address | remote/client IP address |
+ +----------------------+---------------------------------------------------------+
+ | cert-subject | common-name part of the client certificate subject name |
+ +----------------------+---------------------------------------------------------+
+ | cert-issuer | common-name part of the client certificate issuer name |
+ +----------------------+---------------------------------------------------------+
+ | basic-authentication | user ID of basic HTTP authentication |
+ +----------------------+---------------------------------------------------------+
+ | custom-value | another role can be designed in external hooks |
+ +----------------------+---------------------------------------------------------+
+
+Role Configuration
+------------------
+
+.. table:: Role configuration parameters
+
+ +------------------+----------------------------------------------------+
+ | Name | Description |
+ +------------------+----------------------------------------------------+
+ | name | the role name (with the exception of the default |
+ | | and unknown roles) |
+ +------------------+----------------------------------------------------+
+ | accept-commands | the accept access list |
+ +------------------+----------------------------------------------------+
+ | reject-commands | the reject access list |
+ +------------------+----------------------------------------------------+
+ | other-commands | specifies what to do for commands not matching |
+ | | accept and reject lists (default: reject) |
+ +------------------+----------------------------------------------------+
+ | list-match-first | specifies what to do for commands matching both |
+ | | the accept and reject list by giving the list to |
+ | | check and apply first (default: accept) |
+ +------------------+----------------------------------------------------+
+ | response-filters | the filters to apply to responses |
+ +------------------+----------------------------------------------------+
+
+.. note::
+
+ The role assignment may fail, for instance with ``cert-subject`` when
+ the client certificate was not required, or it may have no subject common
+ name and instead have a DNS alternative subject name. In this case, the role
+ assignment returns the empty role and the ``default-role`` entry is used.
+
+ The role assignment can return an unexpected value, e.g. with an
+ unregistered role name or a typing error. In this case the ``unknown-role``
+ entry is used.
+
+ The default for both ``default-role`` and ``unknown-role`` is to reject all commands.
+
+API Commands
+------------
+
+All commands of the REST API are described in files in the source directory
+``src/share/api``, or in installed Kea
+in ``.../share/kea/api``. :ischooklib:`libca_rbac.so` reads these files to take the name,
+the access right (i.e. ``read`` or ``write``), and the hook name. The access right
+can be modified in the file but changes are only applied after the Control Agent
+restarts. Removing command definitions from ``.../share/kea/api`` has
+consequences: if the access control list is based on ``read`` or ``write`` and
+the definition file is missing, the Control Agent always rejects such
+a command. If the access controls list is using ``commands`` to specify the
+name of a command and the definition file from ``.../share/kea/api`` of this
+particular command is missing, the Control Agent logs an error on startup
+and exit.
+
+
+.. table:: Extra command-definition parameters
+
+ +--------+---------------------------------------------------------+
+ | Name | Description |
+ +--------+---------------------------------------------------------+
+ | name | (mandatory) the command name |
+ +--------+---------------------------------------------------------+
+ | access | (mandatory) the access right i.e. ``read`` or ``write`` |
+ +--------+---------------------------------------------------------+
+ | hook | (optional) the hook name (empty or not-present for |
+ | | commands of servers or agents) |
+ +--------+---------------------------------------------------------+
+
+.. note::
+
+ These command description files are security-sensitive, e.g. with
+ too-permissive access rights a local attacker may modify them and
+ defeat the RBAC goal.
+
+Access Control Lists
+--------------------
+
+Access control lists can be specified using a name (string) or a
+single entry map.
+
+.. table:: Predefined named access list
+
+ +-------+----------------------------------------------+
+ | Name | Description |
+ +-------+----------------------------------------------+
+ | ALL | matches everything |
+ +-------+----------------------------------------------+
+ | NONE | matches nothing |
+ +-------+----------------------------------------------+
+ | READ | matches commands with the read-access right |
+ +-------+----------------------------------------------+
+ | WRITE | matches commands with the write-access right |
+ +-------+----------------------------------------------+
+
+Map access list specifications use a list type in the name of the single entry
+and parameter in the value.
+
+.. table:: Access list types
+
+ +---------+-----------------+--------------------------------------+
+ | Name | Description | Parameter |
+ +---------+-----------------+--------------------------------------+
+ | not | logical not | access list |
+ +---------+-----------------+--------------------------------------+
+ | and | logical and | list of access lists |
+ +---------+-----------------+--------------------------------------+
+ | or | logical or | list of access lists |
+ +---------+-----------------+--------------------------------------+
+ | command | explicit list | list of command names |
+ +---------+-----------------+--------------------------------------+
+ | access | by access right | access right (``read`` or ``write``) |
+ +---------+-----------------+--------------------------------------+
+ | hook | by hook | hook name (can be empty) |
+ +---------+-----------------+--------------------------------------+
+
+Response Filters
+----------------
+
+.. table:: Predefined response filters
+
+ +---------------+---------------------------------------+
+ | Name | Description |
+ +---------------+---------------------------------------+
+ | list-commands | Removes not-allowed commands from the |
+ | | list-commands response |
+ +---------------+---------------------------------------+
+
+Global Parameters
+-----------------
+
+The global parameters are:
+
+- ``assign-role-method``: the name of the method
+ which is used for role assignment. This parameter is mandatory.
+
+- ``api-files``: the path of the directory where
+ the API files describing commands can be found. This parameter is mandatory.
+
+- ``require-tls``: the specification of whether received requests on HTTP (vs HTTPS) are
+ rejected. It defaults to ``false`` when the role-assignment method is not
+ based on certificates.
+
+- ``commands``: the list of extra command configurations.
+
+- ``access-control-lists``: the named access control list definitions
+ (each definition is a single entry map; the name of the entry is
+ the name of the access list, and the value is the specification).
+ The name is used in other parts of the configuration, such as "accept-commands".
+
+- ``roles``: the role configurations.
+
+- ``default-role``: the configuration of the default role (used
+ when "" is assigned).
+
+- ``unknown-role``: the configuration of the unknown role
+ (used when the not-empty assigned role has no configuration).
+
+Sample Configuration
+~~~~~~~~~~~~~~~~~~~~
+
+A sample configuration is available in ``doc/examples/agent/rbac.json``
+in the Kea source and is copied below.
+
+.. code-block:: javascript
+ :linenos:
+ :emphasize-lines: 31-85
+
+ {
+ "Control-agent": {
+ // We need to specify where the agent should listen to incoming HTTP
+ // queries.
+ "http-host": "127.0.0.1",
+
+ // If enabling HA and multi-threading, the 8000 port is used by the HA
+ // hook library http listener. When using HA hook library with
+ // multi-threading to function, make sure the port used by dedicated
+ // listener is different (e.g. 8001) than the one used by CA. Note
+ // the commands should still be sent via CA. The dedicated listener
+ // is specifically for HA updates only.
+ "http-port": 8000,
+
+ // TLS trust anchor (Certificate Authority). This is a file name or
+ // (for OpenSSL only) a directory path.
+ "trust-anchor": "my-ca",
+
+ // TLS server certificate file name.
+ "cert-file": "my-cert",
+
+ // TLS server private key file name.
+ "key-file": "my-key",
+
+ // TLS require client certificates flag. Default is true and means
+ // require client certificates. False means they are optional.
+ "cert-required": true,
+
+ // Add hooks here.
+ "hooks-libraries": [
+ {
+ "library": "/opt/lib/libca_rbac.so",
+ "parameters": {
+ // This section configures the RBAC hook library.
+ // Mandatory parameters.
+ "assign-role-method": "cert-subject",
+ "api-files": "/opt/share/kea/api",
+ // Optional parameters.
+ "require-tls": true,
+ "commands": [
+ {
+ "name": "my-command",
+ "access": "read",
+ "hook": "my-hook"
+ } ],
+ "access-control-lists": [
+ {
+ "my-none": { "not": "ALL" }
+ },{
+ "another-none": { "and": [ "ALL", "NONE" ] }
+ },{
+ "my-read": { "access": "read" }
+ } ],
+ "roles": [
+ {
+ "name": "kea-client",
+ "accept-commands":
+ {
+ "commands": [ "list-commands", "status-get" ]
+ },
+ "reject-commands": "NONE",
+ "other-commands": "reject",
+ "list-match-first": "accept",
+ "response-filters": [ "list-commands" ]
+ },{
+ "name": "admin",
+ "accept-commands": "ALL",
+ "reject-commands":
+ {
+ "hook": "cb_cmds"
+ },
+ "list-match-first": "reject"
+ } ],
+ "default-role":
+ {
+ "accept-commands": "NONE",
+ "reject-commands": "ALL"
+ },
+ "unknown-role":
+ {
+ "accept-commands": "READ",
+ "reject-commands": "WRITE"
+ }
+ }
+ } ]
+
+ // Additional parameters, such as logging and others
+ // omitted for clarity.
+
+ }
+ }
+
+Accept/Reject Algorithm
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the pseudo-code of the accept/reject decision algorithm which returns
+``true`` (accept) or ``false`` (reject).
+
+.. code-block:: c
+
+ bool match(command) {
+ if (list-match-first == accept) {
+ if (accept_list && accept_list->match(command)) {
+ return (true);
+ }
+ if (reject_list && reject_list->match(command)) {
+ return (false);
+ }
+ } else {
+ if (reject_list && reject_list->match(command)) {
+ return (false);
+ }
+ if (accept_list && accept_list->match(command)) {
+ return (true);
+ }
+ }
+ if (others == reject) {
+ return (false);
+ } else {
+ return (true);
+ }
+ }
+
+Custom Hook Commands and Command Redefinition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It is possible to have a custom hook with new commands. In this case,
+Role Based Access Control can be used to manage a new command in two ways.
+
+The ``command`` global parameter can be used to define its name, access type,
+and hook name:
+
+.. code-block:: javascript
+
+ {
+ "commands": [
+ {
+ "name": "my-new-command",
+ "access": "write",
+ "hook": "my-custom-hook"
+ }
+ ],
+ ...
+ }
+
+The new command can then be specified in ``roles``:
+
+.. code-block:: javascript
+
+ {
+ "roles": [
+ {
+ "name": "user1",
+ "accept-commands": {
+ "commands": [ "my-new-command" ] },
+ "reject-commands": "WRITE",
+ "list-match-first": "accept"
+ },
+ {
+ "name": "user2",
+ "accept-commands": { "hook": "my-custom-hook" },
+ "reject-commands": "ALL",
+ "list-match-first": "accept"
+ }
+ ],
+ ...
+ }
+
+The second method is to create a custom file in ``.../share/kea/api`` and define
+the access type of the custom command(s).
+
+It is also possible to redefine an existing command by removing its definition
+file from ``.../share/kea/api`` and defining it in the ``commands`` global parameter:
+
+.. code-block:: javascript
+
+ {
+ "commands": [
+ {
+ "name": "dhcp-disable",
+ "access": "read",
+ "hook": "my-custom-hook-3"
+ }
+ ]
+ }
+
+With this approach, an administrator can put the configurations of all existing
+commands inside the Control Agent's configuration file.
+
+Extensive Example
+~~~~~~~~~~~~~~~~~
+
+Here is an extensive example for a role accepting all read commands, with
+the exception of :isccmd:`config-get`, e.g. for hiding passwords. For any remote
+user who is not recognized as "user1", all commands should be rejected.
+
+The first option is to put the allowed commands in the "accept-commands"
+list and to reject anything else:
+
+.. code-block:: javascript
+
+ {
+ "roles": [
+ {
+ "name": "user1",
+ "accept-commands":
+ {
+ "and": [
+ "READ",
+ { "not":
+ { "commands": [ "config-get" ] }
+ }
+ ]
+ },
+ "reject-commands": "ALL",
+ // This is the default but as the config relies on it
+ // it is explicitly set.
+ "list-match-first": "accept"
+ },
+ ...
+ ],
+ ...
+ }
+
+A common alternative is not to set the "reject-commands" list, i.e. leave
+it empty and rely on "other-commands" to reject anything else.
+
+.. code-block:: javascript
+
+ {
+ "roles": [
+ {
+ "name": "user2",
+ "accept-commands":
+ {
+ "and": [
+ "READ",
+ { "not":
+ { "commands": [ "config-get" ] }
+ }
+ ]
+ },
+ // This is the default but as the config relies on it
+ // it is explicitly set.
+ "other-commands": "reject"
+ },
+ ...
+ ],
+ ...
+ }
+
+It is also possible to do the opposite, i.e. to set only the "reject-commands" list:
+
+.. code-block:: javascript
+
+ {
+ "roles": [
+ {
+ "name": "user3",
+ "reject-commands":
+ {
+ "or": [
+ "WRITE",
+ { "commands": [ "config-get" ] }
+ ]
+ },
+ "other-commands": "accept"
+ },
+ ...
+ ],
+ ...
+ }
+
+Or use both lists with the exception in the "reject-commands" list,
+which must be checked first as "config-get" has the read-access right.
+
+.. code-block:: javascript
+
+ {
+ "roles": [
+ {
+ "name": "user4",
+ "accept-commands": "READ",
+ "reject-commands": { "commands": [ "config-get" ] },
+ "list-match-first": "reject"
+ },
+ ...
+ ],
+ ...
+ }
+
+To check any configuration, it is a good idea to use the "list-commands"
+response filter, which shows errors such as missing (rejected) commands
+and extra (accepted) commands.
+
+``access-control-lists`` can be used for definitions of access control lists
+and later reused in ``roles``:
+
+ .. code-block:: javascript
+
+ {
+ "access-control-lists":[
+ {
+ "my-list-one":{
+ "or":[
+ {
+ "hook": "subnet_cmds"
+ },
+ {
+ "commands":[ "list-commands" ]
+ }
+ ]
+ }
+ },
+ {
+ "my-list-two":{
+ "and":[
+ "READ",
+ {
+ "not":{
+ "commands":[ "config-get" ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "my-list-three":{
+ "or":[
+ { "hook":"subnet_cmds" },
+ { "hook":"class_cmds" },
+ { "hook":"lease_cmds" }
+ ]
+ }
+ }
+ ],
+ "roles":[
+ {
+ "name":"admin",
+ "accept-commands":"my-list-one",
+ "reject-commands":"ALL",
+ "list-match-first":"accept"
+ },
+ {
+ "name":"admin2",
+ "accept-commands":"my-list-two",
+ "reject-commands":"ALL",
+ "list-match-first":"accept"
+ }
+ ],
+ "unknown-role":{
+ "accept-commands":"my-list-three",
+ "reject-commands":"ALL"
+ },
+ ...
+ }
diff --git a/doc/sphinx/arm/hooks-run-script.rst b/doc/sphinx/arm/hooks-run-script.rst
new file mode 100644
index 0000000..3d11724
--- /dev/null
+++ b/doc/sphinx/arm/hooks-run-script.rst
@@ -0,0 +1,626 @@
+.. ischooklib:: libdhcp_run_script.so
+.. _hooks-run-script:
+
+``libdhcp_run_script.so``: Run Script Support for External Hook Scripts
+=======================================================================
+
+The Run Script hook library adds support for calling an external script for specific
+packet-processing hook points.
+
+.. note::
+
+ :ischooklib:`libdhcp_run_script.so` is part of the open source code and is
+ available to every Kea user.
+
+The library, which was added in Kea 1.9.5, can be loaded in a
+similar way to other hook libraries by the :iscman:`kea-dhcp4` and
+:iscman:`kea-dhcp6` processes.
+
+.. code-block:: json
+
+ {
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_run_script.so",
+ "parameters": {
+ "name": "/full_path_to/script_name.sh",
+ "sync": false
+ }
+ }
+ ]
+ }
+
+The parameters contain the ``name``, which indicates the full path to the external
+script to be called on each hook point, and also the ``sync`` option, to be able
+to wait synchronously for the script to finish execution.
+If the ``sync`` parameter is ``false``, then the script will launch and Kea
+will not wait for the execution to finish, causing all the OUT parameters of
+the script (including the next step) to be ignored.
+
+.. note::
+
+ The script inherits all privileges from the server which calls it.
+
+.. note::
+
+ Currently, enabling synchronous calls to external scripts is not supported.
+
+.. _hooks-run-script-hook-points:
+
+This library has several hook-point functions implemented, which are
+called at the specific packet-processing stage.
+
+The dhcpv4 hook points:
+
+::
+
+ lease4_renew
+ lease4_expire
+ lease4_recover
+ leases4_committed
+ lease4_release
+ lease4_decline
+
+
+The dhcpv6 hook points:
+
+::
+
+ lease6_renew
+ lease6_rebind
+ lease6_expire
+ lease6_recover
+ leases6_committed
+ lease6_release
+ lease6_decline
+
+Each hook point extracts the Kea internal data and exports it as string
+environment variables. These parameters are shared with the target script
+using the child process environment.
+The only parameter passed to the call of the target script is the name of
+the hook point.
+
+An example of a script implementing all hook points is presented below:
+
+::
+
+ #!/bin/bash
+
+ unknown_handle() {
+ echo "Unhandled function call ${*}"
+ exit 123
+ }
+
+
+ lease4_renew () {
+ ...
+ }
+
+ lease4_expire () {
+ ...
+ }
+
+ lease4_recover () {
+ ...
+ }
+
+ leases4_committed () {
+ ...
+ }
+
+ lease4_release () {
+ ...
+ }
+
+ lease4_decline () {
+ ...
+ }
+
+ lease6_renew () {
+ ...
+ }
+
+ lease6_rebind () {
+ ...
+ }
+
+ lease6_expire () {
+ ...
+ }
+
+ lease6_recover () {
+ ...
+ }
+
+ leases6_committed () {
+ ...
+ }
+
+ lease6_release () {
+ ...
+ }
+
+ lease6_decline () {
+ ...
+ }
+
+ case "$1" in
+ "lease4_renew")
+ lease4_renew
+ ;;
+ "lease4_expire")
+ lease4_expire
+ ;;
+ "lease4_recover")
+ lease4_recover
+ ;;
+ "leases4_committed")
+ leases4_committed
+ ;;
+ "lease4_release")
+ lease4_release
+ ;;
+ "lease4_decline")
+ lease4_decline
+ ;;
+ "lease6_renew")
+ lease6_renew
+ ;;
+ "lease6_rebind")
+ lease6_rebind
+ ;;
+ "lease6_expire")
+ lease6_expire
+ ;;
+ "lease6_recover")
+ lease6_recover
+ ;;
+ "leases6_committed")
+ leases6_committed
+ ;;
+ "lease6_release")
+ lease6_release
+ ;;
+ "lease6_decline")
+ lease6_decline
+ ;;
+ *)
+ unknown_handle "${@}"
+ ;;
+ esac
+
+
+.. _hooks-run-script-exported-environment-variables:
+
+Available parameters for each hook point are presented below.
+
+DHCPv4:
+
+``lease4_renew``
+
+::
+
+ QUERY4_TYPE
+ QUERY4_TXID
+ QUERY4_LOCAL_ADDR
+ QUERY4_LOCAL_PORT
+ QUERY4_REMOTE_ADDR
+ QUERY4_REMOTE_PORT
+ QUERY4_IFACE_INDEX
+ QUERY4_IFACE_NAME
+ QUERY4_HOPS
+ QUERY4_SECS
+ QUERY4_FLAGS
+ QUERY4_CIADDR
+ QUERY4_SIADDR
+ QUERY4_YIADDR
+ QUERY4_GIADDR
+ QUERY4_RELAYED
+ QUERY4_HWADDR
+ QUERY4_HWADDR_TYPE
+ QUERY4_LOCAL_HWADDR
+ QUERY4_LOCAL_HWADDR_TYPE
+ QUERY4_REMOTE_HWADDR
+ QUERY4_REMOTE_HWADDR_TYPE
+ QUERY4_OPTION_82
+ QUERY4_OPTION_82_SUB_OPTION_1
+ QUERY4_OPTION_82_SUB_OPTION_2
+ SUBNET4_ID
+ SUBNET4_NAME
+ SUBNET4_PREFIX
+ SUBNET4_PREFIX_LEN
+ PKT4_CLIENT_ID
+ PKT4_HWADDR
+ PKT4_HWADDR_TYPE
+ LEASE4_ADDRESS
+ LEASE4_CLTT
+ LEASE4_HOSTNAME
+ LEASE4_HWADDR
+ LEASE4_HWADDR_TYPE
+ LEASE4_STATE
+ LEASE4_SUBNET_ID
+ LEASE4_VALID_LIFETIME
+ LEASE4_CLIENT_ID
+
+``lease4_expire``
+
+::
+
+ LEASE4_ADDRESS
+ LEASE4_CLTT
+ LEASE4_HOSTNAME
+ LEASE4_HWADDR
+ LEASE4_HWADDR_TYPE
+ LEASE4_STATE
+ LEASE4_SUBNET_ID
+ LEASE4_VALID_LIFETIME
+ LEASE4_CLIENT_ID
+ REMOVE_LEASE
+
+``lease4_recover``
+
+::
+
+ LEASE4_ADDRESS
+ LEASE4_CLTT
+ LEASE4_HOSTNAME
+ LEASE4_HWADDR
+ LEASE4_HWADDR_TYPE
+ LEASE4_STATE
+ LEASE4_SUBNET_ID
+ LEASE4_VALID_LIFETIME
+ LEASE4_CLIENT_ID
+
+``leases4_committed``
+
+::
+
+ QUERY4_TYPE
+ QUERY4_TXID
+ QUERY4_LOCAL_ADDR
+ QUERY4_LOCAL_PORT
+ QUERY4_REMOTE_ADDR
+ QUERY4_REMOTE_PORT
+ QUERY4_IFACE_INDEX
+ QUERY4_IFACE_NAME
+ QUERY4_HOPS
+ QUERY4_SECS
+ QUERY4_FLAGS
+ QUERY4_CIADDR
+ QUERY4_SIADDR
+ QUERY4_YIADDR
+ QUERY4_GIADDR
+ QUERY4_RELAYED
+ QUERY4_HWADDR
+ QUERY4_HWADDR_TYPE
+ QUERY4_LOCAL_HWADDR
+ QUERY4_LOCAL_HWADDR_TYPE
+ QUERY4_REMOTE_HWADDR
+ QUERY4_REMOTE_HWADDR_TYPE
+ QUERY4_OPTION_82
+ QUERY4_OPTION_82_SUB_OPTION_1
+ QUERY4_OPTION_82_SUB_OPTION_2
+ LEASES4_SIZE
+ DELETED_LEASES4_SIZE
+
+If ``LEASES4_SIZE`` or ``DELETED_LEASES4_SIZE`` is non-zero, then each lease
+has its own unique identifier, as shown below. The first index starts
+at 0.
+
+::
+
+ LEASES4_AT0_ADDRESS
+ LEASES4_AT0_CLTT
+ LEASES4_AT0_HOSTNAME
+ LEASES4_AT0_HWADDR
+ LEASES4_AT0_HWADDR_TYPE
+ LEASES4_AT0_STATE
+ LEASES4_AT0_SUBNET_ID
+ LEASES4_AT0_VALID_LIFETIME
+ LEASES4_AT0_CLIENT_ID
+ DELETED_LEASES4_AT0_ADDRESS
+ DELETED_LEASES4_AT0_CLTT
+ DELETED_LEASES4_AT0_HOSTNAME
+ DELETED_LEASES4_AT0_HWADDR
+ DELETED_LEASES4_AT0_HWADDR_TYPE
+ DELETED_LEASES4_AT0_STATE
+ DELETED_LEASES4_AT0_SUBNET_ID
+ DELETED_LEASES4_AT0_VALID_LIFETIME
+ DELETED_LEASES4_AT0_CLIENT_ID
+
+``lease4_release``
+
+::
+
+ QUERY4_TYPE
+ QUERY4_TXID
+ QUERY4_LOCAL_ADDR
+ QUERY4_LOCAL_PORT
+ QUERY4_REMOTE_ADDR
+ QUERY4_REMOTE_PORT
+ QUERY4_IFACE_INDEX
+ QUERY4_IFACE_NAME
+ QUERY4_HOPS
+ QUERY4_SECS
+ QUERY4_FLAGS
+ QUERY4_CIADDR
+ QUERY4_SIADDR
+ QUERY4_YIADDR
+ QUERY4_GIADDR
+ QUERY4_RELAYED
+ QUERY4_HWADDR
+ QUERY4_HWADDR_TYPE
+ QUERY4_LOCAL_HWADDR
+ QUERY4_LOCAL_HWADDR_TYPE
+ QUERY4_REMOTE_HWADDR
+ QUERY4_REMOTE_HWADDR_TYPE
+ QUERY4_OPTION_82
+ QUERY4_OPTION_82_SUB_OPTION_1
+ QUERY4_OPTION_82_SUB_OPTION_2
+ LEASE4_ADDRESS
+ LEASE4_CLTT
+ LEASE4_HOSTNAME
+ LEASE4_HWADDR
+ LEASE4_HWADDR_TYPE
+ LEASE4_STATE
+ LEASE4_SUBNET_ID
+ LEASE4_VALID_LIFETIME
+ LEASE4_CLIENT_ID
+
+``lease4_decline``
+
+::
+
+ QUERY4_TYPE
+ QUERY4_TXID
+ QUERY4_LOCAL_ADDR
+ QUERY4_LOCAL_PORT
+ QUERY4_REMOTE_ADDR
+ QUERY4_REMOTE_PORT
+ QUERY4_IFACE_INDEX
+ QUERY4_IFACE_NAME
+ QUERY4_HOPS
+ QUERY4_SECS
+ QUERY4_FLAGS
+ QUERY4_CIADDR
+ QUERY4_SIADDR
+ QUERY4_YIADDR
+ QUERY4_GIADDR
+ QUERY4_RELAYED
+ QUERY4_HWADDR
+ QUERY4_HWADDR_TYPE
+ QUERY4_LOCAL_HWADDR
+ QUERY4_LOCAL_HWADDR_TYPE
+ QUERY4_REMOTE_HWADDR
+ QUERY4_REMOTE_HWADDR_TYPE
+ QUERY4_OPTION_82
+ QUERY4_OPTION_82_SUB_OPTION_1
+ QUERY4_OPTION_82_SUB_OPTION_2
+ LEASE4_ADDRESS
+ LEASE4_CLTT
+ LEASE4_HOSTNAME
+ LEASE4_HWADDR
+ LEASE4_HWADDR_TYPE
+ LEASE4_STATE
+ LEASE4_SUBNET_ID
+ LEASE4_VALID_LIFETIME
+ LEASE4_CLIENT_ID
+
+DHCPv6:
+
+``lease6_renew``
+
+::
+
+ 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
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
+ PKT6_IA_IAID
+ PKT6_IA_IA_TYPE
+ PKT6_IA_IA_T1
+ PKT6_IA_IA_T2
+
+``lease6_rebind``
+
+::
+
+ 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
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
+ PKT6_IA_IAID
+ PKT6_IA_IA_TYPE
+ PKT6_IA_IA_T1
+ PKT6_IA_IA_T2
+
+``lease6_expire``
+
+::
+
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
+ REMOVE_LEASE
+
+``lease6_recover``
+
+::
+
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
+
+``leases6_committed``
+
+::
+
+ 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
+ LEASES6_SIZE
+ DELETED_LEASES6_SIZE
+
+If ``LEASES6_SIZE`` or ``DELETED_LEASES6_SIZE`` is non-zero, then each lease
+has its own unique identifier, as shown below. The first index starts
+at 0.
+
+::
+
+ LEASES6_AT0_ADDRESS
+ LEASES6_AT0_CLTT
+ LEASES6_AT0_HOSTNAME
+ LEASES6_AT0_HWADDR
+ LEASES6_AT0_HWADDR_TYPE
+ LEASES6_AT0_STATE
+ LEASES6_AT0_SUBNET_ID
+ LEASES6_AT0_VALID_LIFETIME
+ LEASES6_AT0_DUID
+ LEASES6_AT0_IAID
+ LEASES6_AT0_PREFERRED_LIFETIME
+ LEASES6_AT0_PREFIX_LEN
+ LEASES6_AT0_TYPE
+ DELETED_LEASES6_AT0_ADDRESS
+ DELETED_LEASES6_AT0_CLTT
+ DELETED_LEASES6_AT0_HOSTNAME
+ DELETED_LEASES6_AT0_HWADDR
+ DELETED_LEASES6_AT0_HWADDR_TYPE
+ DELETED_LEASES6_AT0_STATE
+ DELETED_LEASES6_AT0_SUBNET_ID
+ DELETED_LEASES6_AT0_VALID_LIFETIME
+ DELETED_LEASES6_AT0_DUID
+ DELETED_LEASES6_AT0_IAID
+ DELETED_LEASES6_AT0_PREFERRED_LIFETIME
+ DELETED_LEASES6_AT0_PREFIX_LEN
+ DELETED_LEASES6_AT0_TYPE
+
+``lease6_release``
+
+::
+
+ 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
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
+
+``lease6_decline``
+
+::
+
+ 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
+ LEASE6_ADDRESS
+ LEASE6_CLTT
+ LEASE6_HOSTNAME
+ LEASE6_HWADDR
+ LEASE6_HWADDR_TYPE
+ LEASE6_STATE
+ LEASE6_SUBNET_ID
+ LEASE6_VALID_LIFETIME
+ LEASE6_DUID
+ LEASE6_IAID
+ LEASE6_PREFERRED_LIFETIME
+ LEASE6_PREFIX_LEN
+ LEASE6_TYPE
diff --git a/doc/sphinx/arm/hooks-stat-cmds.rst b/doc/sphinx/arm/hooks-stat-cmds.rst
new file mode 100644
index 0000000..fce8cfa
--- /dev/null
+++ b/doc/sphinx/arm/hooks-stat-cmds.rst
@@ -0,0 +1,252 @@
+.. ischooklib:: libdhcp_stat_cmds.so
+.. _hooks-stat-cmds:
+
+``libdhcp_stat_cmds.so``: Statistics Commands for Supplemental Lease Statistics
+===============================================================================
+
+This library provides additional commands for retrieving lease
+statistics from Kea DHCP servers. These commands were added to address
+an issue with obtaining accurate lease statistics in deployments running
+multiple Kea servers that use a shared lease backend. The in-memory
+statistics kept by individual servers only track lease changes made by
+that server; thus, in a deployment with multiple servers (e.g. two
+:iscman:`kea-dhcp6` servers using the same PostgreSQL database for lease storage),
+these statistics are incomplete. The MySQL and PostgreSQL backends in
+Kea track lease allocation changes as they occur via database triggers.
+Additionally, all the lease backends were extended to support
+retrieving lease statistics for a single subnet, a range
+of subnets, or all subnets. Finally, this library provides commands
+for retrieving these statistics.
+
+.. note::
+
+ :ischooklib:`libdhcp_stat_cmds.so` is part of the open source code and is
+ available to every Kea user.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or
+ :iscman:`kea-dhcp6` process.
+
+The commands provided by this library are:
+
+- :isccmd:`stat-lease4-get` - fetches DHCPv4 lease statistics.
+
+- :isccmd:`stat-lease6-get` - fetches DHCPv6 lease statistics.
+
+The Statistics Commands library is part of the open source code and is
+available to every Kea user.
+
+All commands use JSON syntax and can be issued directly to the servers
+via either the control channel (see :ref:`ctrl-channel`) or the
+Control Agent (see :ref:`kea-ctrl-agent`).
+
+This library is loaded in the same way as other libraries and currently has no
+parameters:
+
+::
+
+ "Dhcp6": {
+ "hooks-libraries": [
+ {
+ "library": "/path/libdhcp_stat_cmds.so"
+ },
+ ...
+ ]
+ }
+
+In a deployment with multiple Kea DHCP servers sharing a common lease
+storage, this hook library can be loaded by any or all of the servers. However,
+a server's response to a :isccmd:`stat-lease4-get` / :isccmd:`stat-lease6-get`
+command will only contain data for subnets known to
+that server. In other words, if a subnet does not appear in a server's
+configuration, Kea will not retrieve statistics for it.
+
+.. isccmd:: stat-lease4-get
+.. _command-stat-lease4-get:
+
+.. isccmd:: stat-lease6-get
+.. _command-stat-lease6-get:
+
+The ``stat-lease4-get``, ``stat-lease6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :isccmd:`stat-lease4-get` and
+:isccmd:`stat-lease6-get` commands fetch lease
+statistics for a range of known subnets. The range of subnets is
+determined through the use of optional command input parameters:
+
+- ``subnet-id`` - the ID of the subnet for which lease statistics
+ should be fetched; used to get statistics for a single subnet. If
+ the subnet does not exist, the command result code is 3 (i.e.
+ ``CONTROL_RESULT_EMPTY``).
+
+- ``subnet-range`` - a pair of subnet IDs which describe an inclusive
+ range of subnets for which statistics should be retrieved. The range
+ may include one or more IDs that correspond to no subnet; in this
+ case, the command only outputs lease statistics for those that
+ exist. However, if the range does not include any known subnets, the
+ command result code is 3 (i.e. ``CONTROL_RESULT_EMPTY``).
+
+ - ``first-subnet-id`` - the ID of the first subnet in the range.
+
+ - ``last-subnet-id`` - the ID of the last subnet in the range.
+
+The use of ``subnet-id`` and ``subnet-range`` are mutually exclusive. If no
+parameters are given, the result will contain data for all known
+subnets. Note that in configurations with many subnets, this
+can result in a large response.
+
+The following command fetches lease statistics for all known subnets
+from a :iscman:`kea-dhcp4` server:
+
+::
+
+ {
+ "command": "stat-lease4-get"
+ }
+
+The following command fetches lease statistics for subnet ID 10 from a
+:iscman:`kea-dhcp6` server:
+
+::
+
+ {
+ "command": "stat-lease6-get",
+ "arguments": {
+ "subnet-id" : 10
+ }
+ }
+
+The following command fetches lease statistics for all subnets with IDs
+in the range 10 through 50 from a :iscman:`kea-dhcp4` server:
+
+.. code-block:: json
+
+ {
+ "command": "stat-lease4-get",
+ "arguments": {
+ "subnet-range": {
+ "first-subnet-id": 10,
+ "last-subnet-id": 50
+ }
+ }
+ }
+
+The response to either command will contain three elements:
+
+- ``result`` - a numeric value indicating the outcome of the command
+ where:
+
+ - ``0`` - the command was successful;
+
+ - ``1`` - an error occurred, and an explanation is the "text"
+ element; or
+
+ - ``2`` - the fetch found no matching data.
+
+- ``text`` - an explanation of the command outcome. When the command
+ succeeds, it contains the command name along with the number of
+ rows returned.
+
+- ``arguments`` - a map containing the data returned by the command as
+ the element "result-set", which is patterned after SQL statement
+ responses:
+
+ - ``columns`` - a list of text column labels.
+
+ The columns returned for DHCPv4 are:
+
+ - ``subnet-id`` - the ID of the subnet.
+
+ - ``total-addresses`` - the total number of addresses available for
+ DHCPv4 management in the subnet. In other words, this is the
+ count of all addresses in all the configured pools in the subnet.
+
+ - ``cumulative-assigned-addresses`` - the cumulative number of addresses
+ in the subnet that have been assigned to a client by the server
+ since it started.
+
+ - ``assigned-addresses`` - the number of addresses in the subnet that
+ are currently assigned to a client.
+
+ - ``declined-addresses`` - the number of addresses in the subnet that
+ are currently declined and are thus unavailable for assignment.
+
+ The columns returned for DHCPv6 are:
+
+ - ``subnet-id`` - the ID of the subnet.
+
+ - ``total-nas`` - the number of NA addresses available for DHCPv6
+ management in the subnet. In other words, this is the count of
+ all the NA addresses in all the configured NA pools in the
+ subnet.
+
+ - ``cumulative-assigned-nas`` - the cumulative number of NA addresses
+ in the subnet that have been assigned to a client by the server
+ since it started.
+
+ - ``assigned-nas`` - the number of NA addresses in the subnet that
+ are currently assigned to a client.
+
+ - ``declined-addresses`` - the number of NA addresses that are currently
+ declined and are thus unavailable for assignment.
+
+ - ``total-pds`` - the total number of PD prefixes available of DHCPv6
+ management in the subnet. In other words, this is the count of
+ all prefixes in all the configured prefix pools in the subnet.
+
+ - ``cumulative-assigned-pds`` - the cumulative number of PD prefixes
+ in the subnet that have been assigned to a client by the server
+ since it started.
+
+ - ``assigned-pds`` - the number of PD prefixes in the subnet that are
+ currently assigned to a client.
+
+ - ``rows`` - a list of rows, one per subnet ID. Each row contains a
+ data value corresponding to and in the same order as each column
+ listed in "columns" for a given subnet.
+
+ - ``timestamp`` - the textual date and time the data were fetched,
+ expressed as GMT.
+
+The response to a DHCPv4 command might look as follows:
+
+::
+
+ {
+ "result": 0,
+ "text": "stat-lease4-get: 2 rows found",
+ "arguments": {
+ "result-set": {
+ "columns": [ "subnet-id", "total-addresses", "cumulative-assigned-addresses", "assigned-addresses", "declined-addresses" ],
+ "rows": [
+ [ 10, 256, 300, 111, 0 ],
+ [ 20, 4098, 2034, 2034, 4 ]
+ ],
+ "timestamp": "2018-05-04 15:03:37.000000"
+ }
+ }
+ }
+
+The response to a DHCPv6 command might look as follows, assuming subnet 10 has no
+prefix pools, subnet 20 has no NA pools, and subnet 30 has both NA and
+PD pools:
+
+::
+
+ {
+ "result": 0,
+ "text": "stat-lease6-get: 2 rows found",
+ "arguments": {
+ "result-set": {
+ "columns": [ "subnet-id", "total-nas", "cumulative-assigned-nas", "assigned-nas", "declined-addresses", "total-pds", "cumulative-assigned-pds", "assigned-pds" ],
+ "rows": [
+ [ 10, 4096, 5000, 2400, 3, 0, 0, 0],
+ [ 20, 0, 0, 0, 0, 1048, 300, 233 ],
+ [ 30, 256, 60, 60, 0, 1048, 15, 15 ]
+ ],
+ "timestamp": "2018-05-04 15:03:37.000000"
+ }
+ }
+ }
diff --git a/doc/sphinx/arm/hooks-subnet-cmds.rst b/doc/sphinx/arm/hooks-subnet-cmds.rst
new file mode 100644
index 0000000..63cedfe
--- /dev/null
+++ b/doc/sphinx/arm/hooks-subnet-cmds.rst
@@ -0,0 +1,1326 @@
+.. ischooklib:: libdhcp_subnet_cmds.so
+.. _hooks-subnet-cmds:
+
+``libdhcp_subnet_cmds.so``: Subnet Commands to Manage Subnets and Shared Networks
+=================================================================================
+
+This library offers commands used to query and manipulate subnet and shared network
+configurations in Kea. These can be very useful in deployments
+with a large number of subnets being managed by the DHCP servers,
+when those subnets are frequently updated. The commands offer a lightweight
+approach for manipulating subnets without needing to fully reconfigure
+the server, and without affecting existing servers' configurations. An
+ability to manage shared networks (listing, retrieving details, adding
+new ones, removing existing ones, and adding subnets to and removing them from
+shared networks) is also provided.
+
+.. note::
+
+ :ischooklib:`libdhcp_subnet_cmds.so` is available only to ISC customers with
+ a paid support contract. For more information on subscription options,
+ please complete the form at https://www.isc.org/contact.
+
+.. note::
+
+ This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6`
+ process.
+
+The following commands are currently supported:
+
+- :isccmd:`subnet4-list` / :isccmd:`subnet6-list` - lists all configured subnets.
+
+- :isccmd:`subnet4-get` / :isccmd:`subnet6-get` - retrieves detailed information about a
+ specified subnet.
+
+- :isccmd:`subnet4-add` / :isccmd:`subnet6-add` - adds a new subnet into the server's
+ configuration.
+
+- :isccmd:`subnet4-update` / :isccmd:`subnet6-update` - updates (replaces) a single subnet in
+ the server's configuration.
+
+- :isccmd:`subnet4-del` / :isccmd:`subnet6-del` - removes a subnet from the server's
+ configuration.
+
+- :isccmd:`subnet4-delta-add` / :isccmd:`subnet6-delta-add` - updates (replaces) parts of a
+ single subnet in the server's configuration.
+
+- :isccmd:`subnet4-delta-del` / :isccmd:`subnet6-delta-del` - removes parts of a single subnet in
+ the server's configuration.
+
+- :isccmd:`network4-list` / :isccmd:`network6-list` - lists all configured shared networks.
+
+- :isccmd:`network4-get` / :isccmd:`network6-get` - retrieves detailed information about a
+ specified shared network.
+
+- :isccmd:`network4-add` / :isccmd:`network6-add` - adds a new shared network to the
+ server's configuration.
+
+- :isccmd:`network4-del` / :isccmd:`network6-del` - removes a shared network from the
+ server's configuration.
+
+- :isccmd:`network4-subnet-add` / :isccmd:`network6-subnet-add` - adds an existing subnet to
+ an existing shared network.
+
+- :isccmd:`network4-subnet-del` / :isccmd:`network6-subnet-del` - removes a subnet from
+ an existing shared network and demotes it to a plain subnet.
+
+.. isccmd:: subnet4-list
+.. _command-subnet4-list:
+
+The ``subnet4-list`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to list all currently configured subnets. Each
+subnet is returned with a subnet identifier and
+subnet prefix. To retrieve
+detailed information about the subnet, use the :isccmd:`subnet4-get` command.
+
+This command has a simple structure:
+
+::
+
+ {
+ "command": "subnet4-list"
+ }
+
+The list of subnets is returned in the following format:
+
+::
+
+ {
+ "result": 0,
+ "text": "2 IPv4 subnets found",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 10,
+ "subnet": "10.0.0.0/8"
+ },
+ {
+ "id": 100,
+ "subnet": "192.0.2.0/24"
+ }
+ ]
+ }
+ }
+
+If no IPv4 subnets are found, an error code is returned along with the
+error description.
+
+.. isccmd:: subnet6-list
+.. _command-subnet6-list:
+
+The ``subnet6-list`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to list all currently configured subnets. Each
+subnet is returned with a subnet identifier and
+subnet prefix. To retrieve
+detailed information about the subnet, use the :isccmd:`subnet6-get` command.
+
+This command has a simple structure:
+
+::
+
+ {
+ "command": "subnet6-list"
+ }
+
+The list of subnets is returned in the following format:
+
+::
+
+ {
+ "result": 0,
+ "text": "2 IPv6 subnets found",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 11,
+ "subnet": "2001:db8:1::/64"
+ },
+ {
+ "id": 233,
+ "subnet": "3000::/16"
+ }
+ ]
+ }
+ }
+
+If no IPv6 subnets are found, an error code is returned along with the
+error description.
+
+.. isccmd:: subnet4-get
+.. _command-subnet4-get:
+
+The ``subnet4-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to retrieve detailed information about the
+specified subnet. This command usually follows :isccmd:`subnet4-list`,
+which is used to discover available subnets with their respective subnet
+identifiers and prefixes. Any of those parameters can then be used in
+:isccmd:`subnet4-get` to fetch subnet information:
+
+::
+
+ {
+ "command": "subnet4-get",
+ "arguments": {
+ "id": 10
+ }
+ }
+
+or
+
+::
+
+ {
+ "command": "subnet4-get",
+ "arguments": {
+ "subnet": "10.0.0.0/8"
+ }
+ }
+
+If the subnet exists, the response will be similar to this:
+
+::
+
+ {
+ "result": 0,
+ "text": "Info about IPv4 subnet 10.0.0.0/8 (id 10) returned",
+ "arguments": {
+ "subnets": [
+ {
+ "subnet": "10.0.0.0/8",
+ "id": 1,
+ "option-data": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+ ]
+ }
+ }
+
+.. isccmd:: subnet6-get
+.. _command-subnet6-get:
+
+The ``subnet6-get`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to retrieve detailed information about the
+specified subnet. This command usually follows :isccmd:`subnet6-list`,
+which is used to discover available subnets with their respective subnet
+identifiers and prefixes. Any of those parameters can be then used in
+:isccmd:`subnet6-get` to fetch subnet information:
+
+::
+
+ {
+ "command": "subnet6-get",
+ "arguments": {
+ "id": 11
+ }
+ }
+
+or
+
+::
+
+ {
+ "command": "subnet6-get",
+ "arguments": {
+ "subnet": "2001:db8:1::/64"
+ }
+ }
+
+If the subnet exists, the response will be similar to this:
+
+::
+
+ {
+ "result": 0,
+ "text": "Info about IPv6 subnet 2001:db8:1::/64 (id 11) returned",
+ "arguments": {
+ "subnets": [
+ {
+ "subnet": "2001:db8:1::/64",
+ "id": 1,
+ "option-data": [
+ {
+ ...
+ },
+ ...
+ ],
+ ...
+ }
+ ]
+ }
+ }
+
+.. isccmd:: subnet4-add
+.. _command-subnet4-add:
+
+The ``subnet4-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to create and add a new subnet to the existing server
+configuration. This operation has no impact on other subnets. The subnet
+identifier must be specified and must be unique among all subnets. If
+the identifier or a subnet prefix is not unique, an error is reported and
+the subnet is not added.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet4-add`. The commands described in :ref:`hooks-host-cmds` should be used to
+add, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet4-add",
+ "arguments": {
+ "subnet4": [ {
+ "id": 123,
+ "subnet": "10.20.30.0/24",
+ ...
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet added",
+ "arguments": {
+ "subnet4": [
+ {
+ "id": 123,
+ "subnet": "10.20.30.0/24"
+ }
+ ]
+ }
+ }
+
+.. isccmd:: subnet6-add
+.. _command-subnet6-add:
+
+The ``subnet6-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to create and add a new subnet to the existing server
+configuration. This operation has no impact on other subnets. The subnet
+identifier must be specified and must be unique among all subnets. If
+the identifier or a subnet prefix is not unique, an error is reported and
+the subnet is not added.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet6-add`. The commands described in :ref:`hooks-host-cmds` should be used
+to add, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet6-add",
+ "arguments": {
+ "subnet6": [ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64",
+ ...
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv6 subnet added",
+ "arguments": {
+ "subnet6": [
+ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+It is recommended, but not mandatory, to specify the subnet ID. If not
+specified, Kea will try to assign the next ``subnet-id`` value. This
+automatic ID value generator is simple; it returns the previous
+automatically assigned value, increased by 1. This works well, unless
+a subnet is manually created with a larger value than one previously used. For
+example, if :isccmd:`subnet4-add` is called five times, each without an ID, Kea will
+assign IDs 1, 2, 3, 4, and 5 and it will work just fine. However, if
+:isccmd:`subnet4-add` is called five times, with the first subnet having the
+``subnet-id`` of value 3 and the remaining ones having no ``subnet-id``, the operation will
+fail. The first command (with the explicit value) will use ``subnet-id`` 3; the
+second command will create a subnet with and ID of 1; the third will use a
+value of 2; and finally the fourth will have its ``subnet-id`` value
+auto-generated as 3. However, since there is already a subnet with that
+ID, the process will fail.
+
+The general recommendation is either never to use explicit values, so
+that auto-generated values will always work; or always use explicit
+values, so that auto-generation is never used. The two
+approaches can be mixed only if the administrator understands how internal
+automatic ``subnet-id`` generation works in Kea.
+
+.. note::
+
+ Subnet IDs must be greater than zero and less than 4294967295.
+
+.. isccmd:: subnet4-update
+.. _command-subnet4-update:
+
+The ``subnet4-update`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update (overwrite) a single subnet in the existing
+server configuration. This operation has no impact on other subnets. The
+subnet identifier is used to identify the subnet to replace; it must be
+specified and must be unique among all subnets. The subnet prefix should
+not be updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet4-update`. The commands described in :ref:`hooks-host-cmds` should be
+used to update, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet4-update",
+ "arguments": {
+ "subnet4": [ {
+ "id": 123,
+ "subnet": "10.20.30.0/24",
+ ...
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet updated",
+ "arguments": {
+ "subnet4": [
+ {
+ "id": 123,
+ "subnet": "10.20.30.0/24"
+ }
+ ]
+ }
+ }
+
+As with other update commands, this command overwrites all the contents of the
+entry. If the IPv4 subnet previously had a resource assigned to it, and the
+:isccmd:`subnet4-update` command is missing the resource, it is deleted from the
+server configuration. If an incremental update of the subnet is desired, then
+this can be achieved with :isccmd:`subnet4-delta-add`.
+
+.. isccmd:: subnet6-update
+.. _command-subnet6-update:
+
+The ``subnet6-update`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update (overwrite) a single subnet in the existing
+server configuration. This operation has no impact on other subnets. The
+subnet identifier is used to identify the subnet to replace; it must be
+specified and must be unique among all subnets. The subnet prefix should
+not be updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet6-update`. The commands described in :ref:`hooks-host-cmds` should be
+used to update, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet6-update",
+ "arguments": {
+ "subnet6": [ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64",
+ ...
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv6 subnet updated",
+ "arguments": {
+ "subnet6": [
+ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+As with other update commands, this command overwrites all the contents of the
+entry. If the IPv6 subnet previously had a resource assigned to it, and the
+:isccmd:`subnet6-update` command is missing the resource, it is deleted from the
+server configuration. If an incremental update of the subnet is desired, then
+this can be achieved with :isccmd:`subnet6-delta-add`.
+
+.. isccmd:: subnet4-del
+.. _command-subnet4-del:
+
+The ``subnet4-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to remove a subnet from the server's configuration.
+This command has no effect on other configured subnets, but removing a
+subnet does have certain implications.
+
+In most cases the server has assigned some leases to the clients
+belonging to the subnet. The server may also be configured with static
+host reservations which are associated with this subnet. The current
+implementation of the :isccmd:`subnet4-del` command removes neither the leases nor
+the host reservations associated with a subnet. This is the safest approach
+because the server does not lose track of leases assigned to clients
+from this subnet. However, removal of the subnet may still cause
+configuration errors and conflicts. For example: after removal of the
+subnet, the server administrator may update a new subnet with the ID
+used previously for the removed subnet. This means that the existing
+leases and static reservations will be in conflict with this new subnet.
+Thus, we recommend that this command be used with extreme caution.
+
+This command can also be used to completely delete an IPv4 subnet that
+is part of a shared network. To simply remove the subnet
+from a shared network and keep the subnet configuration, use the
+:isccmd:`network4-subnet-del` command instead.
+
+The command has the following structure:
+
+::
+
+ {
+ "command": "subnet4-del",
+ "arguments": {
+ "id": 123
+ }
+ }
+
+A successful response may look like this:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet 192.0.2.0/24 (id 123) deleted",
+ "arguments": {
+ "subnets": [
+ {
+ "id": 123,
+ "subnet": "192.0.2.0/24"
+ }
+ ]
+ }
+ }
+
+.. isccmd:: subnet6-del
+.. _command-subnet6-del:
+
+The ``subnet6-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to remove a subnet from the server's configuration.
+This command has no effect on other configured subnets, but removing a
+subnet does have certain implications.
+
+In most cases the server has assigned some leases to the clients
+belonging to the subnet. The server may also be configured with static
+host reservations which are associated with this subnet. The current
+implementation of the :isccmd:`subnet6-del` command removes neither the leases nor
+the host reservations associated with a subnet. This is the safest approach
+because the server does not lose track of leases assigned to clients
+from this subnet. However, removal of the subnet may still cause
+configuration errors and conflicts. For example: after removal of the
+subnet, the server administrator may add a new subnet with the ID used
+previously for the removed subnet. This means that the existing leases
+and static reservations will be in conflict with this new subnet. Thus,
+we recommend that this command be used with extreme caution.
+
+This command can also be used to completely delete an IPv6 subnet that
+is part of a shared network. To simply remove the subnet
+from a shared network and keep the subnet configuration, use the
+:isccmd:`network6-subnet-del` command instead.
+
+The command has the following structure:
+
+::
+
+ {
+ "command": "subnet6-del",
+ "arguments": {
+ "id": 234
+ }
+ }
+
+A successful response may look like this:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv6 subnet 2001:db8:1::/64 (id 234) deleted",
+ "subnets": [
+ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+
+.. isccmd:: subnet4-delta-add
+.. _command-subnet4-delta-add:
+
+The ``subnet4-delta-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update a subnet by adding or overwriting its parts in
+the existing server configuration. This operation has no impact on other
+subnets. The subnet identifier is used to identify the subnet to update; it must
+be specified and must be unique among all subnets. The subnet prefix should not
+be updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet4-delta-add`. The commands described in :ref:`hooks-host-cmds` should
+be used to update, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet4-delta-add",
+ "arguments": {
+ "subnet4": [ {
+ "valid-lifetime": 120,
+ "id": 123,
+ "subnet": "10.20.30.0/24",
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 3,
+ "csv-format": true,
+ "data": "192.0.3.1",
+ "name": "routers",
+ "space": "dhcp4"
+ }
+ ],
+ "pools": [
+ {
+ "pool": "10.20.30.1-10.20.30.10",
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 4,
+ "csv-format": true,
+ "data": "192.0.4.1",
+ "name": "time-servers",
+ "space": "dhcp4"
+ }
+ ]
+ }
+ ]
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet updated",
+ "arguments": {
+ "subnet4": [
+ {
+ "id": 123,
+ "subnet": "10.20.30.0/24"
+ }
+ ]
+ }
+ }
+
+The command updates subnet "10.20.30.0/24" with id 123 by changing the valid
+lifetime, adding or changing the subnet level option 3 ("routers"), by adding
+or changing the pool "10.20.30.1-10.20.30.10" and by adding or changing the pool
+level option 4 ("time-servers").
+
+.. isccmd:: subnet6-delta-add
+.. _command-subnet6-delta-add:
+
+The ``subnet6-delta-add`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update a subnet by adding or overwriting its parts in
+the existing server configuration. This operation has no impact on other
+subnets. The subnet identifier is used to identify the subnet to update; it must
+be specified and must be unique among all subnets. The subnet prefix should not
+be updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet6-delta-add`. The commands described in :ref:`hooks-host-cmds` should
+be used to update, remove, and modify static reservations.
+
+::
+
+ {
+ "command": "subnet6-delta-add",
+ "arguments": {
+ "subnet6": [ {
+ "valid-lifetime": 120,
+ "id": 243,
+ "subnet": "2001:db8:1::/64",
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 23,
+ "csv-format": true,
+ "data": "3000::3:1",
+ "name": "dns-servers",
+ "space": "dhcp6"
+ }
+ ],
+ "pd-pools": [
+ {
+ "prefix": "2001:db8:2::",
+ "prefix-len": 48,
+ "delegated-len": 64,
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 22,
+ "csv-format": true,
+ "data": "3000::4:1",
+ "name": "sip-server-addr",
+ "space": "dhcp6"
+ }
+ ]
+ }
+ ],
+ "pools": [
+ {
+ "pool": "2001:db8:1::1-2001:db8:1::10",
+ "option-data": [
+ {
+ "always-send": false,
+ "code": 31,
+ "csv-format": true,
+ "data": "3000::5:1",
+ "name": "sntp-servers",
+ "space": "dhcp6"
+ }
+ ]
+ }
+ ]
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv6 subnet updated",
+ "arguments": {
+ "subnet6": [
+ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+The command updates subnet "2001:db8:1::/64" with id 243 by changing the valid
+lifetime, adding or changing the subnet level option 23 ("dns-servers"), by
+adding or changing the pool "2001:db8:1::1-2001:db8:1::10", by adding or
+changing the pool level option 31 ("sntp-servers"), by adding or changing the
+pd-pool "2001:db8:2::" with prefix-len 48 and by adding or changing the pd-pool
+level option 22 ("sip-server-addr").
+
+.. isccmd:: subnet4-delta-del
+.. _command-subnet4-delta-del:
+
+The ``subnet4-delta-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update a subnet by removing its parts in the existing
+server configuration. This operation has no impact on other subnets.
+The subnet identifier is used to identify the subnet to update; it must be
+specified and must be unique among all subnets. The subnet prefix should not be
+updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet4-delta-del`. The commands described in :ref:`hooks-host-cmds` should
+be used to update, remove, and modify static reservations.
+
+The command is flexible and can delete the part of the subnet by either
+specifying the entire object that needs to be deleted, or just the keys
+identifying the respective object. The address pools are identified by the
+'pool' parameter, the options are identified by the 'name' or 'code' and
+'space' parameters. The 'space' parameter can be omitted if the option belongs
+to the default 'dhcp4' space.
+
+::
+
+ {
+ "command": "subnet4-delta-del",
+ "arguments": {
+ "subnet4": [ {
+ "valid-lifetime": 0,
+ "id": 123,
+ "subnet": "10.20.30.0/24",
+ "option-data": [
+ { "name": "routers" }
+ ],
+ "pools": [
+ {
+ "option-data": [
+ { "code": 4 }
+ ],
+ "pool": "10.20.30.11-10.20.30.20"
+ },
+ {
+ "pool": "10.20.30.21-10.20.30.30"
+ }
+ ]
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet updated",
+ "arguments": {
+ "subnet4": [
+ {
+ "id": 123,
+ "subnet": "10.20.30.0/24"
+ }
+ ]
+ }
+ }
+
+The command updates subnet "10.20.30.0/24" with id 123 by removing the valid
+lifetime, removing the subnet level option 3 ("routers"), by removing the pool
+"10.20.30.21-10.20.30.30" and by removing the pool level option 4
+("time-servers") in pool "10.20.30.11-10.20.30.20".
+The scalar values don't need to match what is configured, but still need to be
+present to maintain a valid json structure and to be a valid value to be able to
+be parsed.
+
+.. isccmd:: subnet6-delta-del
+.. _command-subnet6-delta-del:
+
+The ``subnet6-delta-del`` Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command is used to update a subnet by removing its parts in the existing
+server configuration. This operation has no impact on other subnets.
+The subnet identifier is used to identify the subnet to update; it must be
+specified and must be unique among all subnets. The subnet prefix should not be
+updated.
+
+The subnet information within this command has the same structure as the
+subnet information in the server configuration file, with the exception
+that static host reservations cannot be specified within
+:isccmd:`subnet6-delta-del`. The commands described in :ref:`hooks-host-cmds` should
+be used to update, remove, and modify static reservations.
+
+The command is flexible and can delete the part of the subnet by either
+specifying the entire object that needs to be deleted, or just the keys
+identifying the respective object. The address pools are identified by the
+'pool' parameter, the prefix pools are identified by the "prefix", "prefix-len"
+and "delegated-len" parameters, the options are identified by the 'name' or
+'code' and 'space' parameters. The 'space' parameter can be omitted if the
+option belongs to the default 'dhcp6' space.
+
+.. code-block:: json
+
+ {
+ "command": "subnet6-delta-del",
+ "arguments": {
+ "subnet6": [ {
+ "valid-lifetime": 0,
+ "id": 234,
+ "subnet": "2001:db8:1::/64",
+ "option-data": [
+ { "name": "dns-servers" }
+ ],
+ "pd-pools": [
+ {
+ "prefix": "2001:db8:3::",
+ "prefix-len": 48,
+ "delegated-len": 64,
+ "option-data": [
+ { "code": 22 }
+ ]
+ },
+ {
+ "prefix": "2001:db8:4::",
+ "prefix-len": 48,
+ "delegated-len": 64
+ }
+ ],
+ "pools": [
+ {
+ "option-data": [
+ { "code": 31 }
+ ],
+ "pool": "2001:db8:1::11-2001:db8:1::20"
+ },
+ {
+ "pool": "2001:db8:1::21-2001:db8:1::30"
+ }
+ ]
+ } ]
+ }
+ }
+
+The response to this command has the following structure:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv6 subnet updated",
+ "arguments": {
+ "subnet6": [
+ {
+ "id": 234,
+ "subnet": "2001:db8:1::/64"
+ }
+ ]
+ }
+ }
+
+The command updates subnet "2001:db8:1::/64" with id 243 by removing the valid
+lifetime, removing the subnet level option 23 ("dns-servers"), by removing the
+pool "2001:db8:1::21-2001:db8:1::30", by removing the pool level option 31
+("sntp-servers") in pool "2001:db8:1::11-2001:db8:1::20", by removing the
+pd-pool "2001:db8:4::" with prefix-len 48, by removing the pd-pool level option
+22 ("sip-server-addr") in pd-pool "2001:db8:3::" with prefix-len 48.
+The scalar values don't need to match what is configured, but still need to be
+present to maintain a valid json structure and to be a valid value to be able to
+be parsed.
+
+.. isccmd:: network4-list
+.. _command-network4-list:
+
+.. isccmd:: network6-list
+.. _command-network6-list:
+
+The ``network4-list``, ``network6-list`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to retrieve the full list of currently configured
+shared networks. The list contains only very basic information about
+each shared network. If more details are needed, please use
+:isccmd:`network4-get` or :isccmd:`network6-get` to retrieve all information
+available. This command does not require any parameters and its
+invocation is very simple:
+
+::
+
+ {
+ "command": "network4-list"
+ }
+
+An example response for :isccmd:`network4-list` looks as follows:
+
+::
+
+ {
+ "arguments": {
+ "shared-networks": [
+ { "name": "floor1" },
+ { "name": "office" }
+ ]
+ },
+ "result": 0,
+ "text": "2 IPv4 network(s) found"
+ }
+
+The :isccmd:`network6-list` command uses exactly the same syntax for both the
+command and the response.
+
+.. isccmd:: network4-get
+.. _command-network4-get:
+
+.. isccmd:: network6-get
+.. _command-network6-get:
+
+The ``network4-get``, ``network6-get`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to retrieve detailed information about shared
+networks, including subnets that are currently part of a given network.
+Both commands take one mandatory parameter, ``name``, which specifies the
+name of the shared network. An example command to retrieve details about
+an IPv4 shared network with the name "floor13" looks as follows:
+
+::
+
+ {
+ "command": "network4-get",
+ "arguments": {
+ "name": "floor13"
+ }
+ }
+
+An example response could look as follows:
+
+::
+
+ {
+ "result": 0,
+ "text": "Info about IPv4 shared network 'floor13' returned",
+ "arguments": {
+ "shared-networks": [
+ {
+ "match-client-id": true,
+ "name": "floor13",
+ "option-data": [ ],
+ "rebind-timer": 90,
+ "relay": {
+ "ip-address": "0.0.0.0"
+ },
+ "renew-timer": 60,
+ # "reservation-mode": "all",
+ # It is replaced by the "reservations-global",
+ # "reservations-in-subnet", and "reservations-out-of-pool"
+ # parameters.
+ # Specify if the server should look up global reservations.
+ "reservations-global": false,
+ # Specify if the server should look up in-subnet reservations.
+ "reservations-in-subnet": true,
+ # Specify if the server can assume that all reserved addresses
+ # are out-of-pool.
+ "reservations-out-of-pool": false,
+ "subnet4": [
+ {
+ "subnet": "192.0.2.0/24",
+ "id": 5,
+ ...
+ # many other subnet-specific details here
+ },
+ {
+ "id": 6,
+ "subnet": "192.0.3.0/31",
+ ...
+ # many other subnet-specific details here
+ }
+ ],
+ "valid-lifetime": 120
+ }
+ ]
+ }
+ }
+
+The actual response contains many additional fields that are
+omitted here for clarity. The response format is exactly the same as
+used in :isccmd:`config-get`, just limited to returning the shared network's
+information.
+
+.. isccmd:: network4-add
+.. _command-network4-add:
+
+.. isccmd:: network6-add
+.. _command-network6-add:
+
+The ``network4-add``, ``network6-add`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to add a new shared network, which must
+have a unique name. This command requires one parameter,
+``shared-networks``, which is a list and should contain exactly one
+entry that defines the network. The only mandatory element for a network
+is its name. Although it does not make operational sense, it is possible
+to add an empty shared network that does not have any subnets in it.
+That is allowed for testing purposes, but having empty networks (or networks with
+only one subnet) is discouraged in production environments. For details
+regarding syntax, see :ref:`shared-network4` and
+:ref:`shared-network6`.
+
+.. note::
+
+ As opposed to parameter inheritance during the processing of a full new
+ configuration, this command does not fully handle parameter inheritance.
+ Any missing parameters will be filled with default values, rather
+ than inherited from the global scope.
+
+An example that showcases how to add a new IPv4 shared network looks as
+follows:
+
+::
+
+ {
+ "command": "network4-add",
+ "arguments": {
+ "shared-networks": [ {
+ "name": "floor13",
+ "subnet4": [
+ {
+ "id": 100,
+ "pools": [ { "pool": "192.0.2.2-192.0.2.99" } ],
+ "subnet": "192.0.2.0/24",
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.2.1"
+ }
+ ]
+ },
+ {
+ "id": 101,
+ "pools": [ { "pool": "192.0.3.2-192.0.3.99" } ],
+ "subnet": "192.0.3.0/24",
+ "option-data": [
+ {
+ "name": "routers",
+ "data": "192.0.3.1"
+ }
+ ]
+ } ]
+ } ]
+ }
+ }
+
+Assuming there was no shared network with a name "floor13" and no subnets
+with IDs 100 and 101 previously configured, the command will be
+successful and will return the following response:
+
+::
+
+ {
+ "arguments": {
+ "shared-networks": [ { "name": "floor13" } ]
+ },
+ "result": 0,
+ "text": "A new IPv4 shared network 'floor13' added"
+ }
+
+The :isccmd:`network6-add` command uses the same syntax for both the query and the
+response. However, there are some parameters that are IPv4-only (e.g.
+``match-client-id``) and some that are IPv6-only (e.g. ``interface-id``). The same
+applies to subnets within the network.
+
+.. isccmd:: network4-del
+.. _command-network4-del:
+
+.. isccmd:: network6-del
+.. _command-network6-del:
+
+The ``network4-del``, ``network6-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to delete existing shared networks. Both
+commands take exactly one parameter, ``name``, that specifies the name of
+the network to be removed. An example invocation of the :isccmd:`network4-del`
+command looks as follows:
+
+::
+
+ {
+ "command": "network4-del",
+ "arguments": {
+ "name": "floor13"
+ }
+ }
+
+Assuming there was such a network configured, the response will look
+similar to the following:
+
+::
+
+ {
+ "arguments": {
+ "shared-networks": [
+ {
+ "name": "floor13"
+ }
+ ]
+ },
+ "result": 0,
+ "text": "IPv4 shared network 'floor13' deleted"
+ }
+
+The :isccmd:`network6-del` command uses exactly the same syntax for both the
+command and the response.
+
+If there are any subnets belonging to the shared network being deleted,
+they will be demoted to a plain subnet. There is an optional parameter
+called ``subnets-action`` that, if specified, takes one of two possible
+values: ``keep`` (which is the default) and ``delete``. It controls
+whether the subnets are demoted to plain subnets or removed. An example
+usage in the :isccmd:`network6-del` command that deletes the shared network and all
+subnets in it could look as follows:
+
+::
+
+ {
+ "command": "network4-del",
+ "arguments": {
+ "name": "floor13",
+ "subnets-action": "delete"
+ }
+ }
+
+Alternatively, to completely remove the subnets, it is possible to use the
+:isccmd:`subnet4-del` or :isccmd:`subnet6-del` commands.
+
+.. isccmd:: network4-subnet-add
+.. _command-network4-subnet-add:
+
+.. isccmd:: network6-subnet-add
+.. _command-network6-subnet-add:
+
+The ``network4-subnet-add``, ``network6-subnet-add`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to add existing subnets to existing shared
+networks. There are several ways to add a new shared network. The system
+administrator can add the whole shared network at once, either by
+editing a configuration file or by calling the :isccmd:`network4-add` or
+:isccmd:`network6-add` command with the desired subnets in it. This approach
+works well for completely new shared subnets. However, there may be
+cases when an existing subnet is running out of addresses and needs to
+be extended with additional address space; in other words, another subnet
+needs to be added on top of it. For this scenario, a system administrator
+can use :isccmd:`network4-add` or :isccmd:`network6-add`, and then add an existing
+subnet to this newly created shared network using
+:isccmd:`network4-subnet-add` or :isccmd:`network6-subnet-add`.
+
+The :isccmd:`network4-subnet-add` and
+:isccmd:`network6-subnet-add` commands take
+two parameters: ``id``, which is an integer and specifies the ID of
+an existing subnet to be added to a shared network; and ``name``, which
+specifies the name of the shared network to which the subnet will be added. The
+subnet must not belong to any existing network; to
+reassign a subnet from one shared network to another, use the
+:isccmd:`network4-subnet-del` or
+:isccmd:`network6-subnet-del` command commands first.
+
+An example invocation of the :isccmd:`network4-subnet-add` command looks as
+follows:
+
+::
+
+ {
+ "command": "network4-subnet-add",
+ "arguments": {
+ "name": "floor13",
+ "id": 5
+ }
+ }
+
+Assuming there is a network named "floor13", and there is a subnet with
+``subnet-id`` 5 that is not a part of the existing network, the command will
+return a response similar to the following:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now part of shared network 'floor13'"
+ }
+
+The :isccmd:`network6-subnet-add` command uses exactly the same syntax for both the
+command and the response.
+
+.. note::
+
+ As opposed to parameter inheritance during the processing of a full new
+ configuration or when adding a new shared network with new subnets,
+ this command does not fully handle parameter inheritance.
+ Any missing parameters will be filled with default values, rather
+ than inherited from the global scope or from the shared network.
+
+.. isccmd:: network4-subnet-del
+.. _command-network4-subnet-del:
+
+.. isccmd:: network6-subnet-del
+.. _command-network6-subnet-del:
+
+The ``network4-subnet-del``, ``network6-subnet-del`` Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are used to remove a subnet that is part of an existing
+shared network and demote it to a plain, stand-alone subnet.
+To remove a subnet completely, use the :isccmd:`subnet4-del` or :isccmd:`subnet6-del`
+commands instead. The :isccmd:`network4-subnet-del` and
+:isccmd:`network6-subnet-del` commands take two parameters: ``id``, which is
+an integer and specifies the ID of an existing subnet to be removed from
+a shared network; and ``name``, which specifies the name of the shared
+network from which the subnet will be removed.
+
+An example invocation of the :isccmd:`network4-subnet-del` command looks as
+follows:
+
+::
+
+ {
+ "command": "network4-subnet-del",
+ "arguments": {
+ "name": "floor13",
+ "id": 5
+ }
+ }
+
+Assuming there was a subnet with ``subnet-id`` 5, that was part of a
+shared network named "floor13", the response would look similar to the
+following:
+
+::
+
+ {
+ "result": 0,
+ "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now removed from shared network 'floor13'"
+ }
+
+The :isccmd:`network6-subnet-del` command uses exactly the same syntax for both the
+command and the response.
diff --git a/doc/sphinx/arm/hooks-user-chk.rst b/doc/sphinx/arm/hooks-user-chk.rst
new file mode 100644
index 0000000..37f94b4
--- /dev/null
+++ b/doc/sphinx/arm/hooks-user-chk.rst
@@ -0,0 +1,83 @@
+.. ischooklib:: libdhcp_user_chk.so
+.. _hooks-user-chk:
+
+``libdhcp_user_chk.so``: User Check
+===================================
+
+This library serves several purposes:
+
+- To assign "new" or "unregistered" users to a restricted subnet, while
+ "known" or "registered" users are assigned to unrestricted subnets.
+
+- To allow DHCP response options or vendor option values to be
+ customized based on user identity.
+
+- To provide a real-time record of user registration activity, which
+ can be sampled by an external consumer.
+
+- To serve as a demonstration of various capabilities possible using
+ the hooks interface.
+
+.. note::
+
+ :ischooklib:`libdhcp_user_chk.so` is part of the open source code and is
+ available to every Kea user.
+
+Once loaded, the library allows the separation of incoming requests into known
+and unknown clients. For known clients, packets are processed
+as usual, although it is possible to override the sending of certain options
+on a per-host basis. Clients that are not on the known
+hosts list are treated as unknown and are assigned to the last
+subnet defined in the configuration file.
+
+As an example of a use case, this behavior may be implemented to put unknown users
+into a separate subnet that leads to a "walled garden," where they can
+only access a registration portal. Once they fill in necessary data,
+their details are added to the known clients file and they get a proper
+address after their device is restarted.
+
+.. note::
+
+ This library was developed several years before the host reservation
+ mechanism became available. Host reservation is much
+ more powerful and flexible, but the ability of ``user_chk``
+ to consult an external source of information about clients and alter
+ Kea's behavior remains useful and of educational value.
+
+The library reads the ``/tmp/user_chk_registry.txt`` file while being loaded
+and each time an incoming packet is processed. Each line of the file is expected to
+contain a self-contained JSON snippet which must have the
+following two entries:
+
+- ``type`` - whose value is ``"HW_ADDR"`` for IPv4 users or ``"DUID"`` for IPv6
+ users.
+
+- ``id`` - whose value is either the hardware address or the DUID from
+ the request formatted as a string of hex digits, with or without ":"
+ delimiters.
+
+and may have zero or more of the following entries:
+
+- ``bootfile`` - whose value is the pathname of the desired file.
+
+- ``tftp_server`` - whose value is the hostname or IP address of the
+ desired server.
+
+A sample user registry file is shown below:
+
+::
+
+ { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" }
+ { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" }
+ { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" }
+ { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" }
+
+As with any other hook libraries provided by ISC, internals of the
+``user_chk`` code are well-documented. Users may refer to the `user_chk
+library section of the Kea Developer's Guide
+<https://reports.kea.isc.org/dev_guide/d8/db2/libdhcp_user_chk.html>`__
+for information on how the code works internally. That, together with the
+`Hooks Framework section of the Kea Developer's Guide
+<https://reports.kea.isc.org/dev_guide/index.html#hooksFramework>`__ should give users
+some pointers on how to extend this library and perhaps even write one
+from scratch.
diff --git a/doc/sphinx/arm/hooks.rst b/doc/sphinx/arm/hooks.rst
new file mode 100644
index 0000000..73a26b9
--- /dev/null
+++ b/doc/sphinx/arm/hooks.rst
@@ -0,0 +1,626 @@
+.. _hooks-libraries:
+
+**************
+Hook Libraries
+**************
+
+.. _hooks-libraries-introduction:
+
+Introduction
+============
+
+Kea is both flexible and customizable, via the use of "hooks." This feature
+lets Kea load one or more
+dynamically linked libraries (known as "hook libraries") and call functions
+in them at various points in its processing ("hook points").
+Those functions perform whatever custom processing is required.
+
+The hooks concept allows the core Kea code to remain reasonably small
+by moving features that only some, but not all, users find useful to
+external libraries. Those with no need for certain functions can simply choose not
+to load those libraries.
+
+Hook libraries are loaded by individual Kea processes, not by Kea as a
+whole. This means, among other things, that it is possible to associate one set
+of libraries with the DHCPv4 server and a different set with the DHCPv6
+server.
+
+It is also possible for a process to load
+multiple libraries. When processing reaches a hook point, Kea calls the
+hook library functions attached to it. If multiple libraries have
+attached a function to a given hook point, Kea calls all of them, in the
+order in which the libraries are specified in the configuration file.
+The order may be important; consult the documentation of the libraries
+for specifics.
+
+When a Kea process unloads a library, it expects the ``dlclose`` function
+to remove all library symbols, as well as the library code, from address space.
+Although most OSes implement the ``dlclose`` function, this behavior is not
+required by the POSIX standard and not all systems support it; for example, the musl
+library, used by default by Alpine Linux, implements the ``dlclose`` function
+as a no operation. On such systems a library actually remains loaded for the
+lifetime of the process, which means that it must be restarted
+to update libraries with newer versions; it is not sufficient to simply
+reconfigure or reload the Kea process.
+
+The next sections describe how to install and configure hook libraries. Users who are
+interested in writing their own hook library can find information
+in the `Hooks Developer's Guide section of the Kea Developer's
+Guide <https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__.
+
+Note that some libraries are available under different licenses.
+
+Please also note that some libraries may require additional dependencies and/or
+compilation switches to be enabled.
+
+
+Installing Hook Packages
+========================
+
+.. note::
+
+ For more details about installing the Kea Premium Hooks package, please read
+ `this Knowledgebase article <https://kb.isc.org/docs/aa-01587>`__.
+
+Some hook packages are included in the base Kea sources. There is no
+need to do anything special to compile or install them, as they are covered
+by the usual building and installation procedures. Please
+refer to :ref:`installation` for a general overview of the installation process.
+
+ISC provides several additional premium hooks in the form of packages, which
+follow a similar installation procedure but with several additional steps.
+For our users' convenience, the premium hooks installation procedure is described in this section.
+
+1. Download the package; detailed instructions are provided in the KB article
+above. The package will be a file with a name similar to
+``kea-premium-|release|.tar.gz``. (The name may vary depending on the package
+purchased.)
+
+2. Administrators who have the sources for the corresponding version of the
+open-source Kea package on their system from the initial Kea installation
+should skip this step. Otherwise, extract the Kea source from the original
+tarball that was downloaded. For example, with a download of Kea |release|,
+there should be a tarball called ``kea-|release|.tar.gz`` on the system.
+Unpack this tarball:
+
+.. parsed-literal::
+
+ $ tar -zxvf kea-|release|.tar.gz
+
+This will unpack the tarball into the ``kea-|release|`` subdirectory of
+the current working directory.
+
+3. Unpack the Kea premium hooks tarball into the same directory where the
+original Kea source is located. Once Kea |release| has been unpacked into a ``kea-|release|``
+subdirectory and the Kea premium tarball is in the current directory, the following
+steps will unpack the premium tarball into the correct location:
+
+.. parsed-literal::
+
+ $ cd kea-|release|
+ $ tar -xvf ../kea-premium-|release|.tar.gz
+
+Note that unpacking the Kea premium package puts the files into a
+directory named ``premium``. Regardless of the name of the package, the
+directory is always called ``premium``, although its contents will vary
+depending on the hooks package.
+
+4. Run the ``autoreconf`` tools. This step is necessary to update Kea's build
+script to include the additional directory. If this tool is not already
+available on the system, install the ``automake`` and ``autoconf``
+tools. To generate the configure script, please use:
+
+::
+
+ $ autoreconf -i
+
+5. Rerun ``configure``, using the same configuration options that were used when
+originally building Kea. It is possible to verify that ``configure`` has detected the
+premium package by inspecting the summary printed when it exits. The
+first section of the output should look something like this:
+
+.. parsed-literal::
+
+ Package:
+ Name: kea
+ Version: |release|
+ Extended version: |release| (tarball)
+ OS Family: Linux
+ Using GNU sed: yes
+ Premium package: yes
+ Included Hooks: forensic_log flex_id host_cmds
+
+The last line indicates which specific hooks were detected. Note that
+some hooks may require their own dedicated switches.
+Please consult later sections of this chapter for details.
+
+6. Rebuild Kea.
+
+::
+
+ $ make
+
+If the machine has multiple CPU cores, an interesting option to consider
+here is using the argument ``-j X``, where ``X`` is the number of available cores.
+
+7. Install Kea sources along with the hooks:
+
+::
+
+ $ sudo make install
+
+Note that as part of the installation procedure, the install script
+places additional hook libraries and associated files into the ``premium/`` directory.
+
+The installation location of the hook libraries depends on whether the
+``--prefix`` parameter was specified in the ``configure`` script. If not,
+the default location is ``/usr/local/lib/kea/hooks``. The proper installation
+of the libraries can be verified with this command:
+
+::
+
+ $ ls -l /usr/local/lib/kea/hooks/*.so
+ /usr/local/lib/kea/hooks/libdhcp_class_cmds.so
+ /usr/local/lib/kea/hooks/libdhcp_flex_id.so
+ /usr/local/lib/kea/hooks/libdhcp_flex_option.so
+ /usr/local/lib/kea/hooks/libdhcp_host_cmds.so
+ /usr/local/lib/kea/hooks/libdhcp_lease_cmds.so
+ /usr/local/lib/kea/hooks/libdhcp_legal_log.so
+ /usr/local/lib/kea/hooks/libdhcp_subnet_cmds.so
+
+The exact list returned depends on the packages installed. If the
+directory was specified via ``--prefix``, the hook libraries will be located in
+``{prefix directory}/lib/kea/hooks``.
+
+Configuring Hook Libraries
+===========================
+
+The hook libraries for a given process are configured using the
+``hooks-libraries`` keyword in the configuration for that process. (Note
+that the word "hooks" is plural.) The value of the keyword is an array
+of map structures, with each structure corresponding to a hook library. For
+example, to set up two hook libraries for the DHCPv4 server, the
+configuration would be:
+
+::
+
+ "Dhcp4": {
+ :
+ "hooks-libraries": [
+ {
+ "library": "/opt/first_custom_hooks_example.so"
+ },
+ {
+ "library": "/opt/local/second_custom_hooks_example.so",
+ "parameters": {
+ "mail": "spam@example.com",
+ "floor": 13,
+ "debug": false,
+ "users": [ "alice", "bob", "charlie" ],
+ "languages": {
+ "french": "bonjour",
+ "klingon": "yl'el"
+ }
+ }
+ }
+ ]
+ :
+ }
+
+.. note::
+
+ Libraries are reloaded even if their lists have not changed,
+ because the parameters specified for the library (or the files those
+ parameters point to) may have changed.
+
+Libraries may have additional parameters that are not mandatory, in the
+sense that there may be libraries that do not require them. However, for any
+given library there is often a requirement to specify a certain
+set of parameters. Please consult the documentation for each individual library for
+details. In the example above, the first library (``/opt/first_custom_hooks_example.so``)
+has no parameters. The second library (``/opt/local/second_custom_hooks_example.so``)
+has five parameters: specifying mail (string parameter), floor (integer parameter),
+debug (boolean parameter), lists (list of strings), and maps (containing strings).
+Nested parameters can be used if the library supports it. This topic is explained in detail
+in the `Hooks Developer's Guide section of the Kea Developer's Guide
+<https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__.
+
+Some hooks use user context to set the parameters. See :ref:`user-context-hooks`.
+
+Notes:
+
+- The full path to each library should be given.
+
+- As noted above, the order in which the hooks are called may be important;
+ consult the documentation for each library for specifics.
+
+- An empty list has the same effect as omitting the ``hooks-libraries``
+ configuration element altogether.
+
+ .. note::
+
+ There is one case where this is not true: if Kea is running with a
+ configuration that contains a ``hooks-libraries`` item, and that
+ item is removed and the configuration reloaded, the removal will
+ be ignored and the libraries remain loaded. As a workaround,
+ instead of removing the ``hooks-libraries`` item, change it to an
+ empty list.
+
+At the moment, only the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` processes support
+hook libraries.
+
+.. _order-of-configuration-hooks:
+
+Order of Configuration:
+~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to recognize that the order in which hook libraries are
+configured determines the order in which their callouts will be executed,
+in cases where more than one hook library implements the same callout. For
+example, if you wish to use the flex-id hook library to formulate the client
+IDs in conjunction with HA hook library for load-balanced HA, it is essential
+that the flex-id library be specified first in your server's ``hooks-libraries``
+section. This ensures that the client ID is formulated by the flex-id library
+before the HA library uses it for load-balancing. Similarly it would be best to
+specify forensic logging last, to ensure any other install hooks have made
+their contributions to the packet processing.
+
+.. _user-context-hooks:
+
+User Contexts in Hooks
+~~~~~~~~~~~~~~~~~~~~~~
+
+Hook libraries can have their own configuration parameters, which is
+convenient if the parameter applies to the whole library. However,
+sometimes it is useful to extend certain configuration entities
+with additional configuration data. This is where the concept
+of user contexts comes in. A system administrator can define an arbitrary set of
+data and attach it to Kea structures, as long as the data is specified
+as a JSON map. In particular, it is possible to define fields that are
+integers, strings, boolean, lists, or maps. It is possible to define
+nested structures of arbitrary complexity. Kea does not use that data on
+its own; it simply stores it and makes it available for the hook libraries.
+
+Another use case for user contexts may be storing comments and other
+information that will be retained by Kea. Regular comments are discarded
+when the configuration is loaded, but user contexts are retained. This is
+useful if administrators want their comments to survive :isccmd:`config-set` or :isccmd:`config-get`
+operations, for example.
+
+If user context is supported in a given context, the parser translates
+"comment" entries into user context with a "comment" entry.
+
+User context can store configuration for multiple hooks and comments at once.
+
+Some hooks use user context for a configuration that can be easily edited
+without the need to restart the server.
+
+The DDNS-Tuning Hook uses user-context to configure per subnet behavior. Example:
+
+::
+
+ "subnet4": [{
+ "id": 1,
+ "subnet": "192.0.2.0/24",
+ "pools": [{
+ "pool": "192.0.2.10 - 192.0.2.20"
+ } ],
+ "user-context": {
+ "ddns-tuning": {
+ "hostname-expr": "'guest-'+int8totext(substring(pkt4.yiaddr, 0,1))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 1,2))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 2,3))+'-' \
+ +int8totext(substring(pkt4.yiaddr, 3,4))"
+ },
+ "last-modified": "2017-09-04 13:32",
+ "phones": [ "x1234", "x2345" ],
+ "devices-registered": 42,
+ "billing": false
+ }
+ }]
+
+
+The Limits hook uses user-context in classes and subnets to set parameters. For example:
+
+.. code-block:: json
+
+ {
+ "Dhcp6": {
+ "client-classes": [
+ {
+ "name": "gold",
+ "user-context": {
+ "limits": {
+ "address-limit": 2,
+ "prefix-limit": 1,
+ "rate-limit": "1000 packets per second"
+ }
+ }
+ }
+ ],
+ "hooks-libraries": [
+ {
+ "library": "/usr/local/lib/libdhcp_limits.so"
+ }
+ ],
+ "subnet6": [
+ {
+ "id": 1,
+ "pools": [
+ {
+ "pool": "2001:db8::/64"
+ }
+ ],
+ "subnet": "2001:db8::/64",
+ "user-context": {
+ "limits": {
+ "address-limit": 4,
+ "prefix-limit": 2,
+ "rate-limit": "10 packets per minute"
+ }
+ }
+ }
+ ]
+ }
+ }
+
+Available Hook Libraries
+========================
+
+As described above, the hook functionality provides a way to customize
+a Kea server without modifying the core code. ISC has chosen to take
+advantage of this feature to provide functions that may only be useful
+to a subset of Kea users. To this end, ISC has created some hook
+libraries, discussed in the following sections.
+
+.. note::
+
+ Some of these libraries are available with the base code, while others are
+ premium libraries available for purchase, or only shared with organizations
+ who contribute to Kea's development through paid ISC support contracts. Paid support
+ includes professional engineering assistance, advance security notifications, input
+ into ISC's roadmap planning, and many other benefits, while helping
+ keep Kea sustainable in the long term. ISC encourages companies and organizations
+ to consider purchasing a paid support contract; further information can be
+ obtained by completing the form at https://www.isc.org/contact.
+
+The following table provides a list of hook libraries currently available
+from ISC. It is important to pay attention to which libraries may be
+loaded by which Kea processes. It is a common mistake to configure the
+:iscman:`kea-ctrl-agent` process to load libraries that should, in fact, be
+loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` processes. If a library
+from ISC does not work as expected, please make sure that it has been
+loaded by the correct process per the table below.
+
+.. tabularcolumns:: |p{0.1\linewidth}|p{0.1\linewidth}|p{0.8\linewidth}|
+
+.. table:: List of available hook libraries
+ :class: longtable
+ :widths: 10 10 80
+
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | Name | Availability | Description |
+ +===========================================================+==============+==============================================================+
+ | :ref:`BOOTP <hooks-bootp>` | Kea open | This hook library adds BOOTP support, as defined in |
+ | | source | RFC 1497. It recognizes received BOOTP requests: |
+ | | | they are translated into DHCPREQUEST packets, put into the |
+ | | | BOOTP client class, and receive infinite lifetime leases. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Class Commands <hooks-class-cmds>` | ISC support | This hook library allows configured DHCP client classes to |
+ | | customers | be added, updated, deleted, and fetched without |
+ | | | needing to restart the DHCP server. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Configuration Backend Commands <hooks-cb-cmds>` | ISC support | This hook |
+ | | customers | library implements a collection of commands to manage |
+ | | | Kea configuration information in a |
+ | | | database. This library may only be used in conjunction with |
+ | | | one of the supported Configuration Backend implementations. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`DDNS Tuning <hooks-ddns-tuning>` | ISC premium | This hook library adds custom behaviors related to Dynamic |
+ | | library | DNS updates on a per-client basis. Its primary feature is to |
+ | | | allow the host name used for DNS to be |
+ | | | calculated using an expression. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Flexible Identifier <hooks-flex-id>` | ISC premium | Kea software provides a way to handle host reservations that |
+ | | library | include addresses, prefixes, options, client classes and |
+ | | | other features. The reservation can be based on hardware |
+ | | | address, DUID, circuit-id, or client-id in DHCPv4 and on |
+ | | | hardware address or DUID in DHCPv6. However, there are |
+ | | | sometimes scenarios where the reservation is more complex, |
+ | | | e.g. uses other options than mentioned above, uses parts of |
+ | | | specific options, or perhaps uses a combination of several |
+ | | | options and fields to uniquely identify a client. Those |
+ | | | scenarios are addressed by the Flexible Identifier hook |
+ | | | application. It allows defining an expression, similar to |
+ | | | the one used in client classification, |
+ | | | e.g. ``substring(relay6[0].option[37],0,6)``. Each incoming |
+ | | | packet is evaluated against that expression and its value is |
+ | | | then searched in the reservations database. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Flexible Option <hooks-flex-option>` | Kea open | This library provides hooks that compute option values |
+ | | source | instead of static configured values. An expression is |
+ | | | evaluated on the query packet. Defined add, supersede, and |
+ | | | remove actions are applied on the response packet before |
+ | | | it is sent using the evaluation result. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Forensic Logging <hooks-legal-log>` | ISC premium | This library provides hooks that record a detailed log of |
+ | | library | lease assignments and renewals in a set of log files. In |
+ | | | many legal jurisdictions, companies - especially ISPs - must |
+ | | | record information about the addresses they have leased to |
+ | | | DHCP clients. This library is designed to help with that |
+ | | | requirement. If the information that it records is |
+ | | | sufficient, it may be used directly. If a jurisdiction |
+ | | | requires a different set of information to be saved, it can |
+ | | | be used as a template or example to create |
+ | | | custom logging hooks. In Kea 1.9.8, additional parameters |
+ | | | were added to give users more flexibility regarding |
+ | | | what information should be logged. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`GSS-TSIG <hooks-gss-tsig>` | ISC support | This hook library adds support to the Kea D2 server |
+ | | customers | (kea-dhcp-ddns) for using GSS-TSIG to sign DNS updates. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`High Availability <hooks-high-availability>` | Kea open | The risk of DHCP service unavailability can be minimized |
+ | | source | by setting up a pair of DHCP servers in a network. Two |
+ | | | modes of operation are supported. The first one is called |
+ | | | load-balancing, and is sometimes referred to as |
+ | | | "active-active." Each server can handle selected groups of |
+ | | | clients in this network, or all clients if it detects that |
+ | | | its partner has become unavailable. It is also possible to |
+ | | | designate one server to serve all DHCP clients, and leave |
+ | | | another server as standby. This mode is called "hot standby" |
+ | | | and is sometimes referred to as "active-passive." This |
+ | | | server activates its DHCP function only when it detects that |
+ | | | its partner is not available. Such cooperation between the |
+ | | | DHCP servers requires that these servers constantly |
+ | | | communicate with each other to send updates about allocated |
+ | | | leases, and to periodically test whether their partners are |
+ | | | still operational. The hook library also provides an ability |
+ | | | to send lease updates to external backup servers, making it |
+ | | | much easier to have a replacement that is up to date. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Host Cache <hooks-host-cache>` | ISC support | Some database backends, such as RADIUS, |
+ | | customers | may take a long time to respond. Since |
+ | | | Kea in general is synchronous, backend performance |
+ | | | directly affects DHCP performance. To minimize |
+ | | | performance impact, this library |
+ | | | provides a way to cache responses from other hosts. This |
+ | | | includes negative caching, i.e. the ability to remember that |
+ | | | there is no client information in the database. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Host Commands <hooks-host-cmds>` | ISC premium | Kea provides a way to store host reservations in a |
+ | | library | database. In many larger deployments it is useful to be able |
+ | | | to manage that information while the server is running. This |
+ | | | library provides management commands for adding, querying, |
+ | | | and deleting host reservations in a safe way without |
+ | | | restarting the server. In particular, it validates the |
+ | | | parameters, so an attempt to insert incorrect data, e.g. add |
+ | | | a host with conflicting identifier in the same subnet, is |
+ | | | rejected. Those commands are exposed via the command channel |
+ | | | (JSON over UNIX sockets) and the Control Agent (JSON over |
+ | | | RESTful interface). |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Lease Commands <hooks-lease-cmds>` | Kea open | This hook library offers a number of commands used to |
+ | | source | manage leases. Kea can store lease information in various |
+ | | | backends: memfile, MySQL, PostgreSQL. This library provides |
+ | | | a unified interface to manipulate leases in an unified, safe |
+ | | | way. In particular, it allows manipulation of memfile leases |
+ | | | while Kea is running, sanity check changes, lease existence |
+ | | | checks, and removal of all leases belonging to a specific |
+ | | | subnet. It can also catch obscure errors, like the addition |
+ | | | of a lease with subnet-id that does not exist in the |
+ | | | configuration, or configuration of a lease to use an address |
+ | | | that is outside of the subnet to which it is supposed to |
+ | | | belong. This library allows easy management of user contexts |
+ | | | associated with leases. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Leasequery <hooks-lease-query>` | ISC support | This library adds support for DHCPv4 |
+ | | customers | Leasequery as described in RFC 4388; and for DHCPv6 |
+ | | | Leasequery as described in RFC 5007. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Limits <hooks-limits>` | ISC support | With this hook library, :iscman:`kea-dhcp4` and |
+ | | customers | :iscman:`kea-dhcp6` servers can apply a limit to the rate at |
+ | | | which packets receive a response. The limit can be applied |
+ | | | per-client class or per-subnet. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`MySQL Configuration Backend <hooks-cb-mysql>` | Kea open | This hook library is an implementation of the Kea |
+ | | source | Configuration Backend for MySQL. It uses a MySQL database as |
+ | | | a repository for the Kea configuration information. Kea |
+ | | | servers use this library to fetch their configurations. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`PerfMon <hooks-perfmon>` | Kea open | With this hook library, :iscman:`kea-dhcp4` server and |
+ | | source | :iscman:`kea-dhcp6` servers can track and report performance |
+ | | | data. CURRENTLY UNDER DEVELOPMENT |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Ping Check <hooks-ping-check>` | ISC support | With this hook library, :iscman:`kea-dhcp4` server can |
+ | | customers | perform ping checks of candidate lease addresses before |
+ | | | offering them to clients. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`PostgreSQL Configuration Backend <hooks-cb-pgsql>` | Kea open | This hook library is an implementation of the Kea |
+ | | source | Configuration Backend for PostgreSQL. It uses a PostgreSQL |
+ | | | database as a repository for the Kea configuration |
+ | | | information. Kea servers use this library to fetch their |
+ | | | configurations. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`RADIUS <hooks-radius>` | ISC support | The RADIUS hook library allows Kea to interact with |
+ | | customers | RADIUS servers using access and accounting mechanisms. The |
+ | | | access mechanism may be used for access control, assigning |
+ | | | specific IPv4 or IPv6 addresses reserved by RADIUS, |
+ | | | dynamically assigning addresses from designated pools chosen |
+ | | | by RADIUS, or rejecting the client's messages altogether. |
+ | | | The accounting mechanism allows a RADIUS server to keep |
+ | | | track of device activity over time. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`RBAC <hooks-rbac>` | ISC support | This hook library adds support to the Kea Control Agent |
+ | | customers | (kea-ctrl-agent) for Role-Based Access Control filtering |
+ | | | of commands. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Run Script <hooks-run-script>` | Kea open | This hook library adds support to run external |
+ | | source | scripts for specific packet-processing hook points. There |
+ | | | are several exported environment variables available for |
+ | | | the script. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Statistics Commands <hooks-stat-cmds>` | Kea open | This library provides additional |
+ | | source | commands for retrieving accurate DHCP lease statistics, for |
+ | | | Kea DHCP servers that share the same lease database. This |
+ | | | setup is common in deployments where DHCP service redundancy |
+ | | | is required and a shared lease database is used to avoid |
+ | | | lease-data replication between the DHCP servers. |
+ | | | This hook library returns lease statistics |
+ | | | for each subnet. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`Subnet Commands <hooks-subnet-cmds>` | ISC support | In deployments in which subnet configuration needs to be |
+ | | customers | frequently updated, it is a hard requirement that such |
+ | | | updates be performed without the need for a full DHCP server |
+ | | | reconfiguration or restart. This hook library allows for |
+ | | | incremental changes to the subnet configuration such as |
+ | | | adding or removing a subnet. It also allows for |
+ | | | listing all available subnets and fetching detailed |
+ | | | information about a selected subnet. The commands exposed by |
+ | | | this library do not affect other subnets or configuration |
+ | | | parameters currently used by the server. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+ | :ref:`User Check <hooks-user-chk>` | Kea open | Reads known users list from a file. Unknown users will be |
+ | | source | assigned a lease from the last subnet defined in the |
+ | | | configuration file, e.g. to redirect them to a captive |
+ | | | portal. This demonstrates how an external source of |
+ | | | information can be used to influence the Kea allocation |
+ | | | engine. This hook is part of the Kea source code and is |
+ | | | available in the ``src/hooks/dhcp/user_chk`` directory. |
+ +-----------------------------------------------------------+--------------+--------------------------------------------------------------+
+
+ISC hopes to see more hook libraries become available as time
+progresses, developed both internally and externally. Since this list
+may evolve dynamically, it is maintained on a wiki page, available
+at https://gitlab.isc.org/isc-projects/kea/wikis/Hooks-available.
+Developers or others who are aware of any hook libraries not listed there
+are asked to please send a note to the kea-users or kea-dev mailing lists for
+updating. (Information on all of ISC's public mailing lists can be found
+at https://www.isc.org/mailinglists/.)
+
+The libraries developed by ISC are described in detail in the following
+sections.
+
+.. include:: hooks-bootp.rst
+.. include:: hooks-cb-cmds.rst
+.. include:: hooks-class-cmds.rst
+.. include:: hooks-ddns-tuning.rst
+.. include:: hooks-flex-id.rst
+.. include:: hooks-flex-option.rst
+.. include:: hooks-gss-tsig.rst
+.. include:: hooks-ha.rst
+.. include:: hooks-host-cache.rst
+.. include:: hooks-host-cmds.rst
+.. include:: hooks-lease-cmds.rst
+.. include:: hooks-lease-query.rst
+.. include:: hooks-legal-log.rst
+.. include:: hooks-limits.rst
+.. include:: hooks-cb-mysql.rst
+.. include:: hooks-perfmon.rst
+.. include:: hooks-ping-check.rst
+.. include:: hooks-cb-pgsql.rst
+.. include:: hooks-radius.rst
+.. include:: hooks-rbac.rst
+.. include:: hooks-run-script.rst
+.. include:: hooks-stat-cmds.rst
+.. include:: hooks-subnet-cmds.rst
+.. include:: hooks-user-chk.rst
diff --git a/doc/sphinx/arm/install.rst b/doc/sphinx/arm/install.rst
new file mode 100644
index 0000000..c9b24ea
--- /dev/null
+++ b/doc/sphinx/arm/install.rst
@@ -0,0 +1,633 @@
+.. _installation:
+
+************
+Installation
+************
+
+Packages
+========
+
+ISC publishes native RPM, deb, and APK packages, along with the tarballs
+with the source code. The packages are available on
+`Cloudsmith <https://cloudsmith.io/~isc/repos/>`_ at
+https://cloudsmith.io/~isc/repos. The native packages can be downloaded
+and installed using the system available in a specific distribution (such
+as dpkg or rpm). The Kea repository can also be added to the system,
+making it easier to install updates. For details, please
+go to https://cloudsmith.io/~isc/repos, choose the repository of
+interest, and then click the ``Set Me Up`` button. For detailed
+instructions or refer to ISC `KB article <https://kb.isc.org/docs/isc-kea-packages>`_.
+
+Installation From Cloudsmith Packages
+-------------------------------------
+ISC provides Kea packages for Alpine, Debian, Fedora, RHEL, and Ubuntu.
+The recommended method for installing Kea on any of these systems, from the
+Cloudsmith repository for Kea release 2.3.1 or later, is to install the ``isc-kea``
+metapackage. This metapackage is included on all supported distros and
+installs all of the services offered by the Kea software suite.
+
+Specific Kea components
+can be installed individually, with any of the following packages:
+
+- ``isc-kea-dhcp4`` — Kea DHCPv4 server package
+
+- ``isc-kea-dhcp6`` — Kea DHCPv6 server package
+
+- ``isc-kea-dhcp-ddns`` — Kea DHCP DDNS server
+
+- ``isc-kea-ctrl-agent`` — Kea Control Agent for remote configuration
+
+- ``isc-kea-admin`` — Kea database administration tools
+
+- ``isc-kea-hooks`` — Kea open source DHCP hooks
+
+Kea Premium hook packages are not included in the ``isc-kea-hooks`` package.
+For ISC customers with access to the premium hooks, those packages have the
+``isc-kea-premium-`` prefix.
+
+Once installed, the services can be managed through the distribution's
+service manager. The services are named: :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
+:iscman:`kea-dhcp-ddns`, and :iscman:`kea-ctrl-agent`.
+
+.. note::
+ The real service names on Debian and Ubuntu follow the names of the older
+ packages, to maintain compatibility with pre-existing scripts. A
+ systemd service alias is used to allow users to refer to them with shorter
+ names. Calling ``systemctl enable`` on these services requires
+ the real service names, which are: ``isc-kea-dhcp4-server``,
+ ``isc-kea-dhcp6-server``, ``isc-kea-dhcp-ddns-server``, and
+ ``isc-kea-ctrl-agent``.
+
+Caveats When Upgrading Kea Packages
+-----------------------------------
+
+To upgrade to Kea 2.3.2 or later from an earlier version of Kea on Debian
+and Ubuntu systems, run ``apt dist-upgrade`` instead of the usual ``apt upgrade``.
+Once this upgrade has been completed, it is possible to upgrade to later versions
+normally using ``apt upgrade`` on Debian and Ubuntu systems.
+
+Users may notice differences in the packages distributed in Kea versions prior to
+2.3.2 and those distributed with 2.3.2 and later. As a result of an overhaul of our
+package design with that release, some packages were renamed or removed.
+To ensure that upgrades go as smoothly as possible, pay attention to
+which packages are being removed and installed by the upgrade transaction,
+and ensure that all required packages are reinstalled.
+
+Specifically, there is a possibility for the following packages to be removed
+during the upgrade, depending on which packages were originally installed:
+
+- ``isc-kea-dhcp4``
+
+- ``isc-kea-dhcp6``
+
+- ``isc-kea-dhcp-ddns``
+
+- ``isc-kea-hooks``
+
+To install the entire Kea software suite, simply run
+``apt install isc-kea`` after upgrading, which
+will install all of the relevant subpackages that make up Kea.
+
+This upgrade path issue does not apply to RPM and Alpine systems; however,
+customers with ISC support contracts who experience difficulties with upgrading
+past 2.3.1 are invited to open a ticket in their support queue. Other users
+are encouraged to describe their situation on the kea-users mailing list for
+best-effort support from other list members.
+
+.. _install-hierarchy:
+
+Installation Hierarchy
+======================
+
+The following is the directory layout of the complete Kea installation.
+(All directory paths are relative to the installation directory.)
+
+- ``etc/kea/`` — configuration files.
+
+- ``include/`` — C++ development header files.
+
+- ``lib/`` — libraries.
+
+- ``lib/kea/hooks`` — additional hook libraries.
+
+- ``sbin/`` — server software and commands used by the system administrator.
+
+- ``share/doc/kea/`` — this guide, other supplementary documentation, and examples.
+
+- ``share/kea/`` — API command examples and database schema scripts.
+
+- ``share/man/`` — manual pages (online documentation).
+
+- ``var/lib/kea/`` — server identification and lease database files.
+
+- ``var/log/`` - log files.
+
+- ``var/run/kea`` - PID file and logger lock file.
+
+.. _build-requirements:
+
+Build Requirements
+==================
+
+In addition to the runtime requirements (listed in
+:ref:`required-software`), building Kea from source code requires
+various development include headers and program development tools.
+
+.. note::
+
+ Some operating systems have split their distribution packages into a
+ runtime and a development package. The
+ development package versions, which include header files and
+ libraries, must be installed to build Kea from the source code.
+
+Building from source code requires the following software installed on
+the system:
+
+- Boost C++ libraries (https://www.boost.org/). The oldest Boost version
+ used for testing is 1.57 (although Kea may also work with older
+ versions). The Boost system library must also be installed.
+ Installing a header-only version of Boost is not recommended.
+
+- OpenSSL (at least version 1.0.2) or Botan (at least version 2).
+ OpenSSL version 1.1.1 or later is strongly recommended.
+
+- log4cplus (at least version 1.0.3) development include headers.
+
+- A C++ compiler (with C++14 support) and standard development headers.
+
+- The development tools automake, libtool, and pkg-config.
+
+- The MySQL client and the client development libraries, when using the
+ ``--with-mysql`` configuration flag to build the Kea MySQL database
+ backend. In this case, an instance of the MySQL server running locally
+ or on a machine reachable over a network is required. Note that running
+ the unit tests requires a local MySQL server.
+
+- The PostgreSQL client and the client development libraries, when using the
+ ``--with-pgsql`` configuration flag to build the Kea PostgreSQL database
+ backend. In this case an instance of the PostgreSQL server running locally
+ or on a machine reachable over a network is required. Note that running
+ the unit tests requires a local PostgreSQL server.
+
+- Sysrepo v1.4.140 and libyang v1.0.240 are needed to connect to a Sysrepo
+ datastore. Earlier versions are no longer supported. When compiling from
+ sources, the configure switches that can be used are ``--with-libyang`` and
+ ``--with-sysrepo`` without any parameters. If these dependencies were
+ installed in custom paths, point the switches to them.
+
+- The MIT Kerberos 5 or Heimdal libraries are needed by Kea DDNS server to sign
+ and verify DNS updates using GSS-TSIG. The configuration switch which enables
+ this functionality is ``--with-gssapi`` without any parameters. If these
+ dependencies were installed in custom paths, point the switch to them.
+
+- googletest (version 1.8 or later) is required when using the ``--with-gtest``
+ configuration option to build the unit tests.
+
+- The documentation generation tools `Sphinx <https://www.sphinx-doc.org/>`_,
+ texlive with its extensions, and Doxygen, if using the
+ ``--enable-generate-docs`` configuration option to create the documentation.
+ Specifically, with Fedora, ``python3-sphinx``, ``python3-sphinx_rtd_theme``,
+ ``texlive``, and ``texlive-collection-latexextra`` are necessary.
+ With Ubuntu, ``python3-sphinx``, ``python3-sphinx-rtd-theme``,
+ ``texlive``, and ``texlive-latex-extra`` are needed.
+ If LaTeX packages are missing, Kea skips PDF generation and produces only
+ HTML documents.
+
+Visit ISC's Knowledgebase at https://kb.isc.org/docs/installing-kea for
+system-specific installation tips.
+
+.. _install:
+
+Installation From Source
+========================
+
+Although Kea may be available in pre-compiled, ready-to-use packages
+from operating system vendors, it is open source software written in
+C++. As such, it is freely available in source code form from ISC as a
+downloadable tar file. The source code can also be obtained from the Kea
+GitLab repository at https://gitlab.isc.org/isc-projects/kea. This
+section describes how to build Kea from the source code.
+
+Download Tar File
+-----------------
+
+The Kea release tarballs may be downloaded from:
+https://downloads.isc.org/isc/kea/.
+
+Retrieve From Git
+-----------------
+
+The latest development code is available on GitLab (see
+https://gitlab.isc.org/isc-projects/kea). The Kea source is public and
+development is done in the “master” branch.
+
+Downloading this "bleeding edge" code is recommended only for developers
+or advanced users. Using development code in a production environment is
+not recommended.
+
+.. note::
+
+ When building from source code retrieved via git, additional software
+ is required: automake (v1.11 or later), libtoolize, and autoconf
+ (v2.69 or later). These may need to be installed.
+
+The code can be checked out from
+``https://gitlab.isc.org/isc-projects/kea.git``:
+
+.. code-block:: console
+
+ $ git clone https://gitlab.isc.org/isc-projects/kea.git
+
+The code checked out from the git repository does not include the
+generated configure script or the Makefile.in files, nor their related build
+files. They can be created by running ``autoreconf`` with the
+``--install`` switch. This will run ``autoconf``, ``aclocal``,
+``libtoolize``, ``autoheader``, ``automake``, and related commands.
+
+Write access to the Kea repository is only granted to ISC staff.
+Developers planning to contribute to Kea should check our
+`Contributor's
+Guide <https://gitlab.isc.org/isc-projects/kea/blob/master/contributors-guide.md>`__.
+The `Kea Developer's
+Guide <https://reports.kea.isc.org/dev_guide/>`__ contains more
+information about the process, and describes the requirements for
+contributed code to be accepted by ISC.
+
+.. _configure:
+
+Configure Before the Build
+--------------------------
+
+Kea uses the GNU Build System to discover build environment details. To
+generate the makefiles using the defaults, simply run:
+
+.. code-block:: console
+
+ $ ./configure
+
+Run ``./configure`` with the ``--help`` switch to view the different
+options. Some commonly used options are:
+
+ - ``--prefix``
+ Define the installation location (the default is ``/usr/local``).
+
+ - ``--with-mysql``
+ Build Kea with code to allow it to store leases and host reservations
+ in a MySQL database.
+
+ - ``--with-pgsql``
+ Build Kea with code to allow it to store leases and host reservations
+ in a PostgreSQL database.
+
+ - ``--with-log4cplus``
+ Define the path to find the Log4cplus headers and libraries. Normally
+ this is not necessary.
+
+ - ``--with-boost-include``
+ Define the path to find the Boost headers. Normally this is not
+ necessary.
+
+ - ``--with-botan-config``
+ Specify the path to the botan-config script to build with Botan for
+ cryptographic functions. It is preferable to use OpenSSL (see below).
+
+ - ``--with-openssl``
+ Use the OpenSSL cryptographic library instead of Botan. By default
+ ``configure`` searches for a valid Botan installation; if one is not
+ found, Kea searches for OpenSSL. Normally this is not necessary.
+
+ - ``--enable-shell``
+ Build the optional :iscman:`kea-shell` tool (more in :ref:`kea-shell`).
+ The default is to not build it.
+
+ - ``--with-site-packages``
+ Only useful when :iscman:`kea-shell` is enabled, this switch causes the kea-shell
+ Python packages to be installed in the specified directory. This is
+ mostly useful for Debian-related distributions. While most systems store
+ Python packages in ``${prefix}/usr/lib/pythonX/site-packages``, Debian
+ introduced a separate directory for packages installed from DEB. Such
+ Python packages are expected to be installed in
+ ``/usr/lib/python3/dist-packages``.
+
+ - ``--enable-perfdhcp``
+ Build the optional :iscman:`perfdhcp` DHCP benchmarking tool. The default
+ is to not build it.
+
+.. note::
+
+ For instructions concerning the installation and configuration of
+ database backends for Kea, see :ref:`dhcp-install-configure`.
+
+There are many options that are typically not necessary for
+regular users. However, they may be useful for package maintainers,
+developers, or people who want to extend Kea code or send patches:
+
+ - ``--with-gtest``, ``--with-gtest-source``
+ Enable the building of C++ unit tests using the Google Test
+ framework. This option specifies the path to the gtest source. (If
+ the framework is not installed on the system, it can be downloaded
+ from https://github.com/google/googletest.)
+
+ - ``--enable-generate-docs``
+ Enable the rebuilding of Kea documentation. ISC publishes Kea
+ documentation for each release; however, in some cases it may be
+ desirable to rebuild it: for example, to change something in the
+ docs, or to generate new ones from git sources that are not yet
+ released.
+
+ - ``--enable-generate-parser``
+ Enable the generation of parsers using flex or bison. Kea sources include
+ .cc and .h parser files, pre-generated for users' convenience. By
+ default Kea does not use flex or bison, to avoid
+ requiring installation of unnecessary dependencies for users.
+ However, if anything in the parsers is changed (such as adding a new
+ parameter), flex and bison are required to regenerate
+ parsers. This option permits that.
+
+ - ``--enable-generate-messages``
+ Enable the regeneration of messages files from their messages source
+ files, e.g. regenerate xxx_messages.h and xxx_messages.cc from
+ xxx_messages.mes using the Kea message compiler. By default Kea is
+ built using these .h and .cc files from the distribution. However, if
+ anything in a .mes file is changed (such as adding a new message),
+ the Kea message compiler needs to be built and used. This option
+ permits that.
+
+As an example, the following command configures Kea to find the Boost
+headers in /usr/pkg/include, specifies that PostgreSQL support should be
+enabled, and sets the installation location to /opt/kea:
+
+.. code-block:: console
+
+ $ ./configure \
+ --with-boost-include=/usr/pkg/include \
+ --with-pgsql=/usr/local/bin/pg_config \
+ --prefix=/opt/kea
+
+Users who have any problems with building Kea using the header-only Boost
+code, or who would like to use the Boost system library (assumed for the
+sake of this example to be located in /usr/pkg/lib), should issue these
+commands:
+
+.. code-block:: console
+
+ $ ./configure \
+ --with-boost-libs=-lboost_system \
+ --with-boost-lib-dir=/usr/pkg/lib
+
+If ``configure`` fails, it may be due to missing or old dependencies.
+
+When ``configure`` succeeds, it displays a report with the parameters used
+to build the code. This report is saved into the file ``config.report``
+and is also embedded into the executable binaries, e.g., :iscman:`kea-dhcp4`.
+
+Build
+-----
+
+After the configure step is complete, build the executables from the C++
+code and prepare the Python scripts by running the command:
+
+.. code-block:: console
+
+ $ make
+
+Install
+-------
+
+To install the Kea executables, support files, and documentation, issue
+the command:
+
+.. code-block:: console
+
+ $ make install
+
+Do not use any form of parallel or job server options (such as GNU
+make's ``-j`` option) when performing this step; doing so may cause
+errors.
+
+.. note::
+
+ The install step may require superuser privileges.
+
+If required, run ``ldconfig`` as root with ``/usr/local/lib`` (or with
+prefix/lib if configured with ``--prefix``) in ``/etc/ld.so.conf`` (or the
+relevant linker cache configuration file for the OS):
+
+.. code-block:: console
+
+ $ ldconfig
+
+.. note::
+
+ If ``ldconfig`` is not run where required, users may see
+ errors like the following:
+
+ ::
+
+ program: error while loading shared libraries: libkea-something.so.1:
+ cannot open shared object file: No such file or directory
+
+
+Cross-Building
+--------------
+
+It is possible to cross-build Kea, i.e. to create binaries in a separate
+system (the ``build`` system) from the one where Kea runs
+(the ``host`` system).
+
+It is outside of the scope of common administrator operations and requires
+some developer skills, but the Developer Guide explains how to do that
+using an x86_64 Linux system to build Kea for a Raspberry Pi box running
+Raspbian: `Kea Cross-Compiling Example
+<https://reports.kea.isc.org/dev_guide/de/d9a/crossCompile.html>`__.
+
+.. _dhcp-install-configure:
+
+DHCP Database Installation and Configuration
+============================================
+
+Kea stores its leases in a lease database. The software has been written
+in a way that makes it possible to choose which database product should
+be used to store the lease information. Kea supports three
+database backends: MySQL, PostgreSQL and memfile. To limit external
+dependencies, MySQL and PostgreSQL support are disabled by default and only
+memfile is available. Support for the optional external database backend must
+be explicitly included when Kea is built.
+This section covers the building of Kea with one of the optional backends and
+the creation of the lease database.
+
+.. note::
+
+ When unit tests are built with Kea (i.e. the ``--with-gtest`` configuration
+ option is specified), the databases must be manually pre-configured
+ for the unit tests to run. The details of this configuration can be
+ found in the `Kea Developer's
+ Guide <https://reports.kea.isc.org/dev_guide/>`__.
+
+Building with MySQL Support
+---------------------------
+
+Install MySQL according to the instructions for the system. The client
+development libraries must be installed.
+
+Build and install Kea as described in :ref:`installation`,
+with the following modification. To enable the MySQL database code, at the
+"configure" step (see :ref:`configure`), the ``--with-mysql`` switch should be
+specified:
+
+.. code-block:: console
+
+ $ ./configure [other-options] --with-mysql
+
+If MySQL was not installed in the default location, the location of the
+MySQL configuration program "mysql_config" should be included with the
+switch:
+
+.. code-block:: console
+
+ $ ./configure [other-options] --with-mysql=path-to-mysql_config
+
+See :ref:`mysql-database-create` for details regarding MySQL
+database configuration.
+
+Building with PostgreSQL support
+--------------------------------
+
+Install PostgreSQL according to the instructions for the system. The
+client development libraries must be installed. Client development
+libraries are often packaged as "libpq".
+
+Build and install Kea as described in :ref:`installation`,
+with the following modification. To enable the PostgreSQL database code, at the
+"configure" step (see :ref:`configure`), the ``--with-pgsql`` switch should be
+specified:
+
+.. code-block:: console
+
+ $ ./configure [other-options] --with-pgsql
+
+If PostgreSQL was not installed in the default location, the location of
+the PostgreSQL configuration program "pg_config" should be included with
+the switch:
+
+.. code-block:: console
+
+ $ ./configure [other-options] --with-pgsql=path-to-pg_config
+
+See :ref:`pgsql-database-create` for details regarding PostgreSQL
+database configuration.
+
+
+
+.. include:: hammer.rst
+
+.. _non-root:
+
+Running Kea From a Non-root Account on Linux
+============================================
+
+Both Kea DHCPv4 and DHCPv6 servers perform operations that in general require root access
+privileges. In particular, DHCPv4 opens raw sockets and both DHCPv4 and DHCPv6 open UDP sockets on
+privileged ports. However, with some extra system configuration, it is possible to run Kea from
+non-root accounts.
+
+First, a regular user account must be created:
+
+.. code-block:: console
+
+ useradd admin
+
+Then, change the binaries' ownership and group to the new user. Note that
+the specific path may be different. Please refer to the ``--prefix``
+parameter passed to the configure script:
+
+.. code-block:: console
+
+ chown -R admin /opt/kea
+ chgrp -R admin /opt/kea
+ chown -R admin /var/log/kea-dhcp4.log
+ chgrp -R admin /var/log/kea-dhcp4.log
+ chown -R admin /var/log/kea-dhcp6.log
+ chgrp -R admin /var/log/kea-dhcp6.log
+
+If using systemd, modify its service file
+(e.g. /etc/systemd/system/kea-dhcp6.service):
+
+.. code-block:: console
+
+ User=admin
+ Group=admin
+
+The most important step is to set the capabilities of the binaries. Refer to `man capabilities` to get
+more information.
+
+.. code-block:: console
+
+ setcap 'cap_net_bind_service,cap_net_raw=+ep' /opt/kea/sbin/kea-dhcp4
+ setcap 'cap_net_bind_service=+ep' /opt/kea/sbin/kea-dhcp6
+
+If using systemd, also add this to the service file
+(e.g. /etc/systemd/system/kea-dhcp6.service):
+
+.. code-block:: console
+
+ ExecStartPre=setcap 'cap_net_bind_service=+ep' /opt/kea/sbin/kea-dhcp6
+
+After this step is complete, the admin user should be able to run Kea. Note that the DHCPv4 server by
+default opens raw sockets. If the network is only using relayed traffic, Kea can be instructed to
+use regular UDP sockets (refer to ``dhcp-socket-type`` parameter in the
+:ref:`dhcp4-interface-configuration` section) and the ``cap_net_raw`` capability can be skipped.
+
+.. note::
+
+ It is possible to avoid running Kea with root privileges by instructing Kea to
+ use non-privileged (greater than 1024) ports and redirecting traffic. This, however, only works
+ for relayed traffic. This approach in general is considered experimental and has not been tested
+ for deployment in production environments. Use with caution!
+
+ To use this approach, configure the server to listen on other non-privileged ports (e.g. 1547
+ and 1548) by running the process with the ``-p`` option in ``/etc/systemd/system/kea-dhcp4.service``:
+
+.. code-block:: console
+
+ ExecStart=/opt/kea/sbin/kea-dhcp4 -d -c /etc/kea/kea-dhcp4.conf -p 2067
+
+and ``/etc/systemd/system/kea-dhcp4.service``:
+
+.. code-block:: console
+
+ ExecStart=/opt/kea/sbin/kea-dhcp6 -d -c /etc/kea/kea-dhcp6.conf -p 1547
+
+Then configure port redirection with iptables and ip6tables for new ports (e.g. 1547
+and 1548). Be sure to replace ``ens4`` with the specific interface name.
+
+.. code-block:: console
+
+ iptables -t nat -A PREROUTING -i ens4 -p udp --dport 67 -j REDIRECT --to-port 2067
+ iptables -t nat -A PREROUTING -i ens4 -p udp --dport 2068 -j REDIRECT --to-port 68
+ ip6tables -t nat -A PREROUTING -i ens4 -p udp --dport 547 -j REDIRECT --to-port 1547
+ ip6tables -t nat -A PREROUTING -i ens4 -p udp --dport 1548 -j REDIRECT --to-port 548
+
+.. _deprecated:
+
+Deprecated Features
+===================
+
+This section lists significant features that have been or will be removed. We try to
+deprecate features before removing them to signal
+to current users to plan a migration. New users should not rely on deprecated features.
+
+Sysrepo 0.x or 1.x
+------------------
+
+Kea 2.3.2 introduced support for Sysrepo 2.x. Unfortunately,
+Sysrepo continues to undergo major changes that are backward-incompatible,
+and Kea versions 2.3.2 do not support Sysrepo earlier than versions 2.x.
+
+:isccmd:`libreload` command
+----------------------------------------
+
+The :isccmd:`libreload` command was deprecated in Kea 2.3.4. The code to handle this command is
+still there, but there are reports of it being buggy and not really usable.
+Kea 2.3 and 2.4 versions will produce a warning when this command
+is used, and it will be removed entirely sometime in the 2.5 branch.
diff --git a/doc/sphinx/arm/integrations.rst b/doc/sphinx/arm/integrations.rst
new file mode 100644
index 0000000..57f5734
--- /dev/null
+++ b/doc/sphinx/arm/integrations.rst
@@ -0,0 +1,11 @@
+*********************************
+Integration With External Systems
+*********************************
+
+Kea provides optional support for a variety of external systems, such as RADIUS, NETCONF,
+YANG, and GSS-TSIG. The following sections describe how to compile Kea with those additional
+capabilities and how to configure them.
+
+.. include:: ext-netconf.rst
+.. include:: ext-gss-tsig.rst
+.. include:: ext-radius.rst
diff --git a/doc/sphinx/arm/intro.rst b/doc/sphinx/arm/intro.rst
new file mode 100644
index 0000000..f5c82f5
--- /dev/null
+++ b/doc/sphinx/arm/intro.rst
@@ -0,0 +1,64 @@
+.. _intro:
+
+************
+Introduction
+************
+
+Kea is the next generation of DHCP software, developed by Internet Systems Consortium (ISC). It
+supports both the DHCPv4 and DHCPv6 protocols along with their extensions,
+e.g. prefix delegation and dynamic updates to DNS.
+
+This guide covers Kea version |release|.
+
+For information about supported platforms see :ref:`platforms`.
+
+.. include:: platforms.rst
+
+.. _kea_software:
+
+Kea Software
+============
+
+Kea is a modular DHCP server solution. This modularity is accomplished using multiple
+cooperating processes which, together, provide the server functionality.
+The following software is included with Kea:
+
+- :iscman:`keactrl` — This tool starts, stops, reconfigures, and reports the status of
+ the Kea servers.
+
+- :iscman:`kea-dhcp4` — The DHCPv4 server process. This process responds to
+ DHCPv4 queries from clients.
+
+- :iscman:`kea-dhcp6` — The DHCPv6 server process. This process responds to
+ DHCPv6 queries from clients.
+
+- :iscman:`kea-dhcp-ddns` — The DHCP Dynamic DNS process. This process acts
+ as an intermediary between the DHCP servers and external DNS servers. It
+ receives name update requests from the DHCP servers and sends DNS
+ update messages to the DNS servers.
+
+- :iscman:`kea-admin` — This is a useful tool for database backend maintenance
+ (creating a new database, checking versions, upgrading, etc.).
+
+- :iscman:`kea-lfc` — This process removes redundant information from the
+ files used to provide persistent storage for the memfile database
+ backend. While it can be run standalone, it is normally run as and
+ when required by the Kea DHCP servers.
+
+- :iscman:`kea-ctrl-agent` — The Kea Control Agent (CA) is a daemon that exposes
+ a RESTful control interface for managing Kea servers.
+
+- :iscman:`kea-netconf` - kea-netconf is an agent that provides a
+ YANG/NETCONF interface for configuring Kea.
+
+- :iscman:`kea-shell` — This simple text client uses the REST interface to
+ connect to the Kea Control Agent.
+
+- :iscman:`perfdhcp` — This is a DHCP benchmarking tool which simulates multiple
+ clients to test both DHCPv4 and DHCPv6 server performance.
+
+The tools and modules are covered in full detail in this guide. In
+addition, manual pages are also provided in the default installation.
+
+Kea also provides C++ libraries and programmer interfaces for DHCP.
+These include detailed developer documentation and code examples.
diff --git a/doc/sphinx/arm/keactrl.rst b/doc/sphinx/arm/keactrl.rst
new file mode 100644
index 0000000..93768c3
--- /dev/null
+++ b/doc/sphinx/arm/keactrl.rst
@@ -0,0 +1,364 @@
+.. _keactrl:
+
+***********************************
+Managing Kea with :iscman:`keactrl`
+***********************************
+
+.. _keactrl-overview:
+
+Overview
+========
+
+:iscman:`keactrl` is a shell script which controls the startup, shutdown, and
+reconfiguration of the Kea servers (:iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
+:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`). It also
+provides the means for checking the current status of the servers and
+determining the configuration files in use.
+
+:iscman:`keactrl` is available only when Kea is built from sources. When installing
+Kea using native packages, the native ``systemd`` scripts are provided. See
+:ref:`systemd` Section for details.
+
+.. _keactrl-usage:
+
+Command Line Options
+====================
+
+:iscman:`keactrl` is run as follows:
+
+.. code-block:: console
+
+ # keactrl <command> [-c keactrl-config-file] [-s server[,server,...]]
+
+``<command>`` is one of the commands described in :ref:`keactrl-commands`.
+
+The optional ``-c keactrl-config-file`` switch allows specification of
+an alternate :iscman:`keactrl` configuration file. (``--ctrl-config`` is a
+synonym for ``-c``.) In the absence of ``-c``, :iscman:`keactrl` uses the
+default configuration file ``[kea-install-dir]/etc/kea/keactrl.conf``.
+
+The optional ``-s server[,server,...]`` switch selects the servers to
+which the command is issued. (``--server`` is a synonym for ``-s``.) If
+absent, the command is sent to all servers enabled in the :iscman:`keactrl`
+configuration file. If multiple servers are specified, they should be
+separated by commas with no intervening spaces.
+
+.. _keactrl-config-file:
+
+The :iscman:`keactrl` Configuration File
+========================================
+
+Depending on the administrator's requirements, it may not be
+necessary to run all of the available servers.
+The :iscman:`keactrl` configuration file sets which servers are enabled and
+which are disabled. The default configuration file is
+``[kea-install-dir]/etc/kea/keactrl.conf``, but this can be overridden
+on a per-command basis using the ``-c`` switch.
+
+The contents of ``keactrl.conf`` are:
+
+.. code-block:: bash
+
+ # This is a configuration file for keactrl script which controls
+ # the startup, shutdown, reconfiguration and gathering the status
+ # of the Kea processes.
+
+ # prefix holds the location where the Kea is installed.
+ prefix=@prefix@
+
+ # Location of Kea configuration file.
+ kea_dhcp4_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp4.conf
+ kea_dhcp6_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp6.conf
+ kea_dhcp_ddns_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp-ddns.conf
+ kea_ctrl_agent_config_file=@sysconfdir@/@PACKAGE@/kea-ctrl-agent.conf
+ kea_netconf_config_file=@sysconfdir@/@PACKAGE@/kea-netconf.conf
+
+ # Location of Kea binaries.
+ exec_prefix=@exec_prefix@
+ dhcp4_srv=@sbindir@/kea-dhcp4
+ dhcp6_srv=@sbindir@/kea-dhcp6
+ dhcp_ddns_srv=@sbindir@/kea-dhcp-ddns
+ ctrl_agent_srv=@sbindir@/kea-ctrl-agent
+ netconf_srv=@sbindir@/kea-netconf
+
+ # Start DHCPv4 server?
+ dhcp4=yes
+
+ # Start DHCPv6 server?
+ dhcp6=yes
+
+ # Start DHCP DDNS server?
+ dhcp_ddns=no
+
+ # Start Control Agent?
+ ctrl_agent=yes
+
+ # Start Netconf?
+ netconf=no
+
+ # Be verbose?
+ kea_verbose=no
+
+.. note::
+
+ In the example above, strings of the form @something@ are replaced by
+ the appropriate values when Kea is installed.
+
+Setting the ``dhcp4``, ``dhcp6``, ``dhcp_ddns``, ``ctrl_agent``, and ``netconf``
+parameters set to "yes" configures :iscman:`keactrl` to manage (start,
+reconfigure) all servers, i.e. :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`,
+:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`. When any of
+these parameters is set to "no", :iscman:`keactrl` ignores the
+corresponding server when starting or reconfiguring Kea. Some daemons
+(dhcp_ddns and netconf) are disabled by default.
+
+By default, Kea servers managed by :iscman:`keactrl` are located in
+``[kea-install-dir]/sbin``. This should work for most installations. If
+the default location needs to be altered, the paths
+specified with the ``dhcp4_srv``, ``dhcp6_srv``, ``dhcp_ddns_srv``,
+``ctrl_agent_srv``, and ``netconf_srv`` parameters should be modified.
+
+The ``kea_verbose`` parameter specifies the verbosity of the servers
+being started. When ``kea_verbose`` is set to ``yes``, the logging level of
+the server is set to DEBUG. Modification of the logging severity in a
+configuration file, as described in :ref:`logging`, will have no
+effect as long as ``kea_verbose`` is set to "yes." Setting it to
+"no" causes the server to use the logging levels specified in the
+Kea configuration file. If no logging configuration is specified, the
+default settings are used.
+
+.. note::
+
+ The verbosity for the server is set when it is started. Once started,
+ the verbosity can only be changed by stopping the server and starting
+ it again with the new value of the ``kea_verbose`` parameter.
+
+.. _keactrl-commands:
+
+Commands
+========
+
+The following commands are supported by :iscman:`keactrl`:
+
+- ``start`` - starts the selected servers.
+
+- ``stop`` - stops all running servers.
+
+- ``reload`` - triggers reconfiguration of the selected servers by
+ sending the SIGHUP signal to them.
+
+- ``status`` - returns the status of the servers (active or inactive)
+ and the names of the configuration files in use.
+
+- ``version`` - prints out the version of the :iscman:`keactrl` tool itself,
+ together with the versions of the Kea daemons.
+
+Typical output from :iscman:`keactrl` when starting the servers looks similar
+to the following:
+
+.. code-block:: console
+
+ $ keactrl start
+ INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea-dhcp4.conf -d
+ INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea-dhcp6.conf -d
+ INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea-dhcp-ddns.conf -d
+ INFO/keactrl: Starting kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf -d
+ INFO/keactrl: Starting kea-netconf -c /usr/local/etc/kea/kea-netconf.conf -d
+
+Kea's servers create PID files upon startup. These files are used by
+:iscman:`keactrl` to determine whether a given server is running. If one or more
+servers are running when the start command is issued, the output
+looks similar to the following:
+
+.. code-block:: console
+
+ $ keactrl start
+ INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/run/kea/kea.kea-dhcp4.pid.
+ INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/run/kea/kea.kea-dhcp6.pid.
+ INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/run/kea/kea.kea-dhcp-ddns.pid.
+ INFO/keactrl: kea-ctrl-agent appears to be running, see: PID 10931, PID file: /usr/local/var/run/kea/kea.kea-ctrl-agent.pid.
+ INFO/keactrl: kea-netconf appears to be running, see: PID 10123, PID file: /usr/local/var/run/kea/kea.kea-netconf.pid.
+
+During normal shutdowns, these PID files are deleted; they may, however,
+be left over as remnants following a system crash. It is possible,
+though highly unlikely, that upon system restart the PIDs they contain
+may actually refer to processes unrelated to Kea. This condition will
+cause :iscman:`keactrl` to decide that the servers are running, when in fact they
+are not. In such a case the PID files listed in the :iscman:`keactrl` output
+must be manually deleted.
+
+The following command stops all servers:
+
+.. code-block:: console
+
+ $ keactrl stop
+ INFO/keactrl: Stopping kea-dhcp4...
+ INFO/keactrl: Stopping kea-dhcp6...
+ INFO/keactrl: Stopping kea-dhcp-ddns...
+ INFO/keactrl: Stopping kea-ctrl-agent...
+ INFO/keactrl: Stopping kea-netconf...
+
+Note that the ``stop`` command attempts to stop all servers
+regardless of whether they are "enabled" in ``keactrl.conf``. If any
+of the servers are not running, an informational message is displayed as
+in the ``stop`` command output below.
+
+.. code-block:: console
+
+ $ keactrl stop
+ INFO/keactrl: kea-dhcp4 isn't running.
+ INFO/keactrl: kea-dhcp6 isn't running.
+ INFO/keactrl: kea-dhcp-ddns isn't running.
+ INFO/keactrl: kea-ctrl-agent isn't running.
+ INFO/keactrl: kea-netconf isn't running.
+
+As already mentioned, the reconfiguration of each Kea server is
+triggered by the SIGHUP signal. The ``reload`` command sends the SIGHUP
+signal to any servers that are enabled in the :iscman:`keactrl` configuration
+file and that are currently running. When a server receives the SIGHUP signal
+it rereads its configuration file and, if the new configuration is
+valid, uses the new configuration.
+If the new configuration proves to be invalid, the server retains its
+current configuration; however, in some cases a fatal error message is logged
+indicating that the server is no longer providing any service: a working
+configuration must be loaded as soon as possible.
+
+A reload is executed as follows:
+
+.. code-block:: console
+
+ $ keactrl reload
+ INFO/keactrl: Reloading kea-dhcp4...
+ INFO/keactrl: Reloading kea-dhcp6...
+ INFO/keactrl: Reloading kea-dhcp-ddns...
+ INFO/keactrl: Reloading kea-ctrl-agent...
+
+If any of the servers are not running, an informational message is
+displayed as in the ``reload`` command output below.
+:iscman:`kea-netconf` does not support the SIGHUP signal. If its
+configuration has changed, please stop and restart it for the change to
+take effect.
+
+.. code-block:: console
+
+ $ keactrl stop
+ INFO/keactrl: kea-dhcp4 isn't running.
+ INFO/keactrl: kea-dhcp6 isn't running.
+ INFO/keactrl: kea-dhcp-ddns isn't running.
+ INFO/keactrl: kea-ctrl-agent isn't running.
+ INFO/keactrl: kea-netconf isn't running.
+
+.. note::
+
+ NETCONF is an optional feature that is disabled by default and can be
+ enabled during compilation. If Kea was compiled without NETCONF
+ support, :iscman:`keactrl` does not provide
+ information about it. The NETCONF entries are still present in
+ the ``keactrl.conf`` file, but NETCONF status is not shown and other
+ commands ignore it.
+
+.. note::
+
+ Currently :iscman:`keactrl` does not report configuration failures when the
+ server is started or reconfigured. To check if the server's
+ configuration succeeded, the Kea log must be examined for errors. By
+ default, the log is written to the `syslog` file.
+
+Sometimes it is useful to check which servers are running. The
+``status`` command reports this, with typical output that looks like:
+
+.. code-block:: console
+
+ $ keactrl status
+ DHCPv4 server: active
+ DHCPv6 server: inactive
+ DHCP DDNS: active
+ Control Agent: active
+ Netconf agent: inactive
+ Kea configuration file: /usr/local/etc/kea/kea.conf
+ Kea DHCPv4 configuration file: /usr/local/etc/kea/kea-dhcp4.conf
+ Kea DHCPv6 configuration file: /usr/local/etc/kea/kea-dhcp6.conf
+ Kea DHCP DDNS configuration file: /usr/local/etc/kea/kea-dhcp-ddns.conf
+ Kea Control Agent configuration file: /usr/local/etc/kea/kea-ctrl-agent.conf
+ Kea Netconf configuration file: /usr/local/etc/kea/kea-netconf.conf
+ keactrl configuration file: /usr/local/etc/kea/keactrl.conf
+
+``keactrl status`` offers basic reporting capabilities. For more extensive insight
+into Kea's health and status, consider deploying Stork. For details, see :ref:`stork`.
+
+.. _keactrl-overriding-servers:
+
+Overriding the Server Selection
+===============================
+
+The optional ``-s`` switch allows the selection of the server(s) to which
+the :iscman:`keactrl` command is issued. For example, the following instructs
+:iscman:`keactrl` to stop the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` servers and
+leave the :iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent` running:
+
+.. code-block:: console
+
+ $ keactrl stop -s dhcp4,dhcp6
+
+Similarly, the following starts only the :iscman:`kea-dhcp4` and
+:iscman:`kea-dhcp-ddns` servers, but not :iscman:`kea-dhcp6` or :iscman:`kea-ctrl-agent`.
+
+.. code-block:: console
+
+ $ keactrl start -s dhcp4,dhcp_ddns
+
+Note that the behavior of the ``-s`` switch with the ``start`` and
+``reload`` commands is different from its behavior with the ``stop``
+command. On ``start`` and ``reload``, :iscman:`keactrl` checks whether the
+servers given as parameters to the ``-s`` switch are enabled in the
+:iscman:`keactrl` configuration file; if not, the server is ignored. For
+``stop``, however, this check is not made; the command is applied to all
+listed servers, regardless of whether they have been enabled in the
+file.
+
+The following keywords can be used with the ``-s`` command-line option:
+
+- ``dhcp4`` for :iscman:`kea-dhcp4`.
+
+- ``dhcp6`` for :iscman:`kea-dhcp6`.
+
+- ``dhcp_ddns`` for :iscman:`kea-dhcp-ddns`.
+
+- ``ctrl_agent`` for :iscman:`kea-ctrl-agent`.
+
+- ``netconf`` for :iscman:`kea-netconf`.
+
+- ``all`` for all servers (default).
+
+.. _systemd:
+
+Native Packages and ``systemd``
+===============================
+
+:iscman:`keactrl` is a script that was developed to assist in managing Kea processes.
+However, all modern operating systems have their own process-management scripts,
+such as ``systemd``. In general, these native scripts should be used,
+as they have several advantages. ``systemd`` scripts handle processes in a uniform
+way, so Kea is handled in a similar fashion to HTTP or a mail
+server. Second and more importantly, ``systemd`` allows dependencies to be defined
+between services. For example, it is easy to specify that the Kea server should not start
+until the network interfaces are operational. Using native scripts also has other benefits, such as
+the ability to enable or disable services using commands, and the ability to temporarily start a disabled
+service.
+
+Thus, it is recommended to use ``systemctl`` commands if they are available. Native
+Kea packages do not provide :iscman:`keactrl`; ``systemctl`` service definitions are
+provided instead. Consult the system documentation for details.
+
+Briefly, here are example commands to check status, start, stop, and restart various Kea daemons:
+
+.. code-block:: console
+
+ # systemctl status kea-ctrl-agent
+ # systemctl start kea-dhcp4
+ # systemctl stop kea-dhcp6
+ # systemctl restart kea-dhcp-ddns
+
+Note that the service names may be slightly different between Linux distributions; in general,
+we have followed the naming conventions in third-party packages. In particular,
+some systems may not have the `isc-` prefix.
diff --git a/doc/sphinx/arm/lease-expiration.rst b/doc/sphinx/arm/lease-expiration.rst
new file mode 100644
index 0000000..a6ebd51
--- /dev/null
+++ b/doc/sphinx/arm/lease-expiration.rst
@@ -0,0 +1,328 @@
+.. _lease-expiration:
+
+****************
+Lease Expiration
+****************
+
+The primary role of the DHCP server is to assign addresses and/or
+delegate prefixes to DHCP clients. These addresses and prefixes are
+often referred to as "leases." Leases are typically assigned to clients
+for a finite amount of time, known as the "valid lifetime." DHCP clients
+who wish to continue using their assigned leases periodically renew
+them by sending the appropriate message to the DHCP server. The DHCP
+server records the time when these leases are renewed and calculates new
+expiration times for them.
+
+If the client does not renew a lease before its valid lifetime elapses,
+the lease is considered expired. There are many situations when the
+client may cease lease renewals; common scenarios include when the machine
+running the client shuts down for an extended period of time, or when a
+mobile device leaves the vicinity of a network.
+
+The process through which the DHCP server makes expired leases available
+for reassignment is referred to as "lease reclamation," and expired
+leases returned to availability through this process are referred to as
+"reclaimed." The DHCP server attempts to reclaim an expired lease as
+soon as it detects that it has expired. The server has several possible
+ways to detect expiration: it may attempt to allocate a lease to a
+client but find this lease already present in the database and expired;
+or it can periodically query the lease database for expired leases.
+Regardless of how an expired lease is detected, it must be reclaimed
+before it can be assigned to a client.
+
+This chapter explains how to configure the server to periodically query
+for the expired leases, and how to minimize the impact of the periodic
+lease-reclamation process on the server's responsiveness. Finally, it
+explains "lease affinity," which provides the means to assign the same
+lease to a returning client after its lease has expired.
+
+Although all configuration examples in this section are provided for the
+DHCPv4 server, the same parameters may be used for DHCPv6 server
+configuration.
+
+.. _lease-reclamation:
+
+Lease Reclamation
+=================
+
+Lease reclamation is the process through which an expired lease becomes
+available for assignment to the same or a different client. This process
+involves the following steps for each reclaimed lease:
+
+- Invoke callouts for the ``lease4_expire`` or ``lease6_expire`` hook
+ points, if hook libraries supporting those callouts are currently
+ loaded.
+
+- Update the DNS, i.e. remove any DNS entries associated with the
+ expired lease.
+
+- Update lease information in the lease database to indicate that the
+ lease is now available for reassignment.
+
+- Update counters on the server, a process that includes increasing the
+ number of reclaimed leases and decreasing the number of assigned
+ addresses or delegated prefixes.
+
+Please refer to :ref:`dhcp-ddns-server` to see how to configure DNS
+updates in Kea, and to :ref:`hooks-libraries` for information about
+using hook libraries.
+
+.. _lease-reclamation-defaults:
+
+Lease Reclamation Configuration Parameters
+==========================================
+
+The following list presents all the configuration parameters pertaining to
+processing expired leases, with their default values:
+
+- ``reclaim-timer-wait-time`` - this parameter governs intervals
+ between the completion of the previous reclamation cycle and the start of the
+ next one. Specified in seconds; the default value is 10.
+
+- ``flush-reclaimed-timer-wait-time`` - this parameter controls how
+ often the server initiates the lease reclamation procedure. Expressed in
+ seconds; the default value is 25. If both ``flush-reclaimed-timer-wait-time``
+ and ``hold-reclaimed-time`` are not 0, when the client sends a release
+ message the lease is expired instead of being deleted from lease storage.
+
+- ``hold-reclaimed-time`` - this parameter governs how long the lease
+ should be kept after it is reclaimed. This enables lease affinity
+ when set to a non-zero value. Expressed in seconds; the default value
+ is 3600. If both ``flush-reclaimed-timer-wait-time`` and
+ ``hold-reclaimed-time`` are not 0, when the client sends a release message
+ the lease is expired instead of being deleted from lease storage.
+
+- ``max-reclaim-leases`` - this parameter specifies the maximum number
+ of reclaimed leases that can be processed at one time. Zero means
+ unlimited (i.e. process all reclaimed leases). The default value is
+ 100.
+
+- ``max-reclaim-time`` - this parameter specifies an upper limit to the
+ length of time a lease reclamation procedure can take. Zero means no time
+ limit. Expressed in milliseconds; the default value is 250.
+
+- ``unwarned-reclaim-cycles`` - if lease reclamation limits are
+ specified (``max-reclaim-leases`` and/or ``max-reclaim-time``), then
+ under certain circumstances the server may not be able to deal with
+ the leases to be reclaimed fast enough. This parameter specifies how many
+ consecutive clean-up cycles must end with remaining leases to be
+ processed before a warning is printed. The default is 5 cycles.
+
+The parameters are explained in more detail in the rest of this chapter.
+
+The default value for any parameter is used when the parameter is not
+explicitly specified in the configuration. If the
+``expired-leases-processing`` map is omitted entirely in the
+configuration, the default values are used for all
+parameters listed above.
+
+.. _lease-reclaim-config:
+
+Configuring Lease Reclamation
+=============================
+
+Kea can be configured to periodically detect and reclaim expired leases.
+During this process the lease entries in the database are modified or
+removed. While this is happening the server does not process incoming
+DHCP messages, to avoid issues with concurrent access to database
+information. As a result, the server is unresponsive while lease
+reclamation is performed and DHCP queries will accumulate; responses
+will be sent once the lease-reclamation cycle is complete.
+
+In deployments where response time is critical, administrators may wish
+to minimize the interruptions in service caused by lease reclamation.
+To this end, Kea provides configuration parameters to control the
+frequency of lease reclamation cycles, the maximum number of leases
+processed in a single reclamation cycle, and the maximum amount of time
+a single reclamation cycle is allowed to run before being interrupted.
+The following examples demonstrate how these parameters can be used:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "expired-leases-processing": {
+ "reclaim-timer-wait-time": 5,
+ "max-reclaim-leases": 0,
+ "max-reclaim-time": 0
+ }
+ }
+ }
+
+The first parameter is expressed in seconds and specifies an interval
+between the two consecutive lease reclamation cycles. This is explained
+by the following diagram:
+
+::
+
+
+ | c1 | | c2 | |c3| | c4 |
+ |<---->|<---------->|<-->|<---------->|<>|<---------->|<-->|<--
+ ------------------------------------------------------------------>
+ | | 5s | | 5s | | 5s | | time
+
+This diagram shows four lease-reclamation cycles (c1 through c4) of
+variable duration. The duration of the reclamation cycle
+depends on the number of expired leases detected and processed in a
+particular cycle. This duration is usually significantly shorter than
+the interval between the cycles.
+
+According to the ``reclaim-timer-wait-time``, the server keeps fixed
+intervals of five seconds between the end of one cycle and the start of
+the next cycle. This guarantees the presence of 5-second-long periods during
+which the server remains responsive to DHCP queries and does not perform
+lease reclamation. The ``max-reclaim-leases`` and ``max-reclaim-time``
+are set to 0, which sets no restriction on the maximum number of leases
+reclaimed in the particular cycle, or on the maximum duration of each
+cycle.
+
+In deployments with high lease-pool utilization, relatively short valid
+lifetimes, and frequently disconnecting clients which allow leases to
+expire, the number of expired leases requiring reclamation at any given
+time may rise significantly. In this case, it is often desirable to
+apply restrictions to the maximum duration of a reclamation cycle or the
+maximum number of leases reclaimed in a cycle. The following
+configuration demonstrates how this can be done:
+
+.. code-block:: json
+
+ {
+ "Dhcp4": {
+ "expired-leases-processing": {
+ "reclaim-timer-wait-time": 3,
+ "max-reclaim-leases": 100,
+ "max-reclaim-time": 50,
+ "unwarned-reclaim-cycles": 10
+ }
+ }
+ }
+
+In this example, the ``max-reclaim-leases`` parameter limits the number of leases
+reclaimed in a single cycle to 100, and the ``max-reclaim-time`` limits the
+maximum duration of each cycle to 50ms. The lease-reclamation cycle will
+be interrupted if either of these limitations is reached. The
+reclamation of any unreclaimed leases will be attempted in subsequent
+cycles.
+
+The following diagram illustrates the behavior of the system in the
+presence of many expired leases, when the limits are applied for the
+reclamation cycles:
+
+::
+
+
+ | c1 | | c2 | | c3 | | c4 |
+ |<-->|<-------------->|<-->|<-------------->|<-->|<-------------->|<-->|<--
+ ------------------------------------------------------------------------------>
+ |50ms| 3s |50ms| 3s |50ms| 3s |50ms| time
+
+In this case, if any reclamation cycle takes
+more than 50ms, it is interrupted according to the value of the
+``max-reclaim-time``. This results in equal durations of all reclamation
+cycles over time. In this example, the limitation of the
+maximum 100 leases is not reached. This may be the case when database
+transactions or callouts in the hook libraries attached to the
+server are slow. Regardless, the chosen values for either the maximum
+number of leases or a maximum cycle time strongly depend on the
+particular deployment, the lease database backend being used, any
+hook libraries, etc. Administrators may need to experiment to tune the
+system to suit the dynamics of their deployment.
+
+It is important to realize that with the use of these limits, there is a
+risk that expired leases will accumulate faster than the server can
+reclaim them. This should not be a problem if the server is dealing with
+a temporary burst of expirations, because it should be able to
+eventually deal with them over time. However, if leases expire at a high
+rate for a long period of time, the unreclaimed leases will pile up in
+the database. To notify the administrator that the current configuration
+does not satisfy the needs for reclamation of expired leases, the server
+issues a warning message in the log if it is unable to reclaim all
+leases within several reclamation cycles. The number of cycles after
+which such a warning is issued is specified with the
+``unwarned-reclaim-cycles`` configuration parameter.
+
+Setting the ``reclaim-timer-wait-time`` to 0 disables periodic
+reclamation of the expired leases.
+
+.. _lease-affinity:
+
+Configuring Lease Affinity
+==========================
+
+Suppose that a laptop goes into sleep mode after a period of user
+inactivity. While the laptop is in sleep mode, its DHCP client does not
+renew leases obtained from the server and these leases will eventually
+expire. When the laptop wakes up, it is often desirable for it to
+continue using its previous assigned IP addresses. To facilitate this,
+the server needs to correlate returning clients with their expired
+leases. When the client returns, the server first checks for those
+leases and reassigns them if they have not been assigned to another
+client. The ability of the server to reassign the same lease to a
+returning client is referred to as "lease affinity."
+
+When lease affinity is enabled (i.e. when ``hold-reclaimed-time`` is configured
+to a value greater than zero), the server still reclaims leases according to the
+parameters described in :ref:`lease-reclaim-config`, but the reclaimed leases
+are held in the database for a specified amount of time rather than removed.
+If both ``flush-reclaimed-timer-wait-time`` and ``hold-reclaimed-time`` are
+greater than zero, the lease is expired immediately when the client sends a
+release message, instead of being deleted from lease storage. When the client
+returns, the server first verifies whether there are any reclaimed leases
+associated with this client and then reassigns them if possible. However, it is
+important to note that any reclaimed lease may be assigned to another client if
+that client specifically asks for it. Therefore, lease affinity does not
+guarantee that the reclaimed lease will be available for the client who used it
+before; it merely increases the chances of the client being assigned the same
+lease. If the lease pool is small - namely, in DHCPv4, for which address space
+is limited - there is an increased likelihood that the expired lease will be
+assigned to another client.
+
+Consider the following configuration:
+
+::
+
+ "Dhcp4": {
+ "expired-leases-processing": {
+ "reclaim-timer-wait-time": 3,
+ "hold-reclaimed-time": 1800,
+ "flush-reclaimed-timer-wait-time": 5
+ },
+ ...
+ }
+
+The ``hold-reclaim-time`` specifies how many seconds after an expiration
+a reclaimed lease should be held in the database for reassignment to
+the same client. In the example given above, reclaimed leases are
+held for 30 minutes (1800 seconds) after their expiration. During this time,
+the server will likely be able to reassign the same lease to the
+returning client, unless another client specifically requests this lease and the
+server assigns it.
+
+The server must periodically remove reclaimed leases for which the time
+indicated by ``hold-reclaim-time`` has elapsed. The
+``flush-reclaimed-timer-wait-time`` parameter controls how often the
+server removes such leases. In the example provided above, the server
+initiates removal of such leases five seconds after the previous
+removal attempt was completed. Setting this value to 0 disables lease
+affinity, meaning leases are removed from the lease database
+when they are reclaimed. If lease affinity is enabled, it is recommended
+that the ``hold-reclaim-time`` be set to a value significantly higher than
+the ``reclaim-timer-wait-time``, as timely removal of expired-reclaimed
+leases is less critical than the removal process, which may impact
+server responsiveness.
+
+There is no guarantee that lease affinity will work every time; if a
+server is running out of addresses, it will reassign expired addresses
+to new clients. Also, clients can request specific addresses and the
+server tries to honor such requests if possible. Administrators who want to
+ensure a client keeps its address, even after periods of inactivity,
+should consider using host reservations or leases with very long lifetimes.
+
+.. _leases-reclamation-using-command:
+
+Reclaiming Expired Leases via Command
+=====================================
+
+The :isccmd:`leases-reclaim` command can be used to trigger lease reclamation at
+any time. Please consult the :ref:`command-leases-reclaim` section
+for details about using this command.
diff --git a/doc/sphinx/arm/lfc.rst b/doc/sphinx/arm/lfc.rst
new file mode 100644
index 0000000..f28756a
--- /dev/null
+++ b/doc/sphinx/arm/lfc.rst
@@ -0,0 +1,73 @@
+.. _kea-lfc:
+
+***************
+The LFC Process
+***************
+
+.. _kea-lfc-overview:
+
+Overview
+========
+
+:iscman:`kea-lfc` is a service process that removes redundant information from
+the files used to provide persistent storage for the memfile database
+backend. This service is written to run as a standalone process.
+
+While :iscman:`kea-lfc` can be started externally, there is usually no need to
+do so. :iscman:`kea-lfc` is run on a periodic basis by the Kea DHCP servers.
+
+The process operates on a set of files, using them to receive input and
+output of the lease entries and to indicate what stage the process is
+in, in the event of an interruption. Currently the caller must supply
+names for all of the files.
+
+.. _kea-lfc-usage:
+
+Command-Line Options
+====================
+
+:iscman:`kea-lfc` is run as follows:
+
+::
+
+ kea-lfc [-4 | -6] -c config-file -p pid-file -x previous-file -i copy-file -o output-file -f finish-file
+
+The argument ``-4`` or ``-6`` selects the protocol version of the lease
+files.
+
+The ``-c`` argument specifies the configuration file. This is required,
+but is not currently used by the process.
+
+The ``-p`` argument specifies the PID file. When the :iscman:`kea-lfc` process
+starts, it attempts to determine whether another instance of the process
+is already running by examining the PID file. If one is already running,
+the new process is terminated; if one is not running, Kea writes its PID
+into the PID file.
+
+The other filenames specify where the :iscman:`kea-lfc` process should look
+for input, write its output, and perform its bookkeeping:
+
+- ``previous`` — when :iscman:`kea-lfc` starts, this is the result of any
+ previous run of :iscman:`kea-lfc`. When :iscman:`kea-lfc` finishes, it is the
+ result of this run. If :iscman:`kea-lfc` is interrupted before completing,
+ this file may not exist.
+
+- ``input`` — before the DHCP server invokes :iscman:`kea-lfc`, it moves
+ the current lease file here and then calls :iscman:`kea-lfc` with this file.
+
+- ``output`` — this is the temporary file where :iscman:`kea-lfc` writes the
+ leases. Once the file has finished writing, it is moved to the
+ ``finish`` file (see below).
+
+- ``finish`` — this is another temporary file :iscman:`kea-lfc` uses for
+ bookkeeping. When :iscman:`kea-lfc` completes writing the ``output`` file, it
+ moves the contents to the file of this name. After :iscman:`kea-lfc` finishes deleting the
+ other files (``previous`` and ``input``), it moves this file to the ``previous``
+ lease file. By moving the files in this fashion, :iscman:`kea-lfc` and
+ the DHCP server processes can determine the correct file to use even
+ if one of the processes is interrupted before completing its task.
+
+There are several additional arguments, mostly for debugging purposes.
+``-d`` sets the logging level to debug. ``-v`` and ``-V`` print out
+version stamps, with ``-V`` providing a longer form. ``-h`` prints out
+the usage string.
diff --git a/doc/sphinx/arm/logging.rst b/doc/sphinx/arm/logging.rst
new file mode 100644
index 0000000..897cf9e
--- /dev/null
+++ b/doc/sphinx/arm/logging.rst
@@ -0,0 +1,1077 @@
+.. _logging:
+
+*******
+Logging
+*******
+
+Logging Configuration
+=====================
+
+During its operation Kea may produce many log messages. They differ in
+severity (some are more important than others) and source (different
+components, like hooks, produce different messages). It is useful to
+understand which log messages are critical and which are not, and to
+configure logging appropriately. For example, debug-level messages
+can be safely ignored in a typical deployment. They are, however, very
+useful when debugging a problem.
+
+The logging system in Kea is configured through the ``loggers`` entry in the
+server section of the configuration file.
+
+Loggers
+-------
+
+Within Kea, a message is logged through an entity called a "logger."
+Different components log messages through different loggers, and each
+logger can be configured independently of the others. Some components,
+in particular the DHCP server processes, may use multiple loggers to log
+messages pertaining to different logical functions of the component. For
+example, the DHCPv4 server uses one logger for messages about packet
+reception and transmission, another logger for messages related to lease
+allocation, and so on. Some of the libraries used by the Kea server,
+such as libdhcpsrv, use their own loggers.
+
+Users implementing hook libraries (code attached to the server at
+runtime) are responsible for creating the loggers used by those
+libraries. Such loggers should have unique names, different from the
+logger names used by Kea. That way, the messages produced by the hook
+library can be distinguished from messages issued by the core Kea code.
+Unique names also allow the hook loggers to be configured independently of
+loggers used by Kea. Whenever it makes sense, a hook library can use
+multiple loggers to log messages pertaining to different logical parts
+of the library.
+
+In the server section of a configuration file, the
+configuration for zero or more loggers (including loggers used by the
+proprietary hook libraries) can be specified. If there are no loggers specified, the
+code uses default values; these cause Kea to log messages of INFO
+severity or greater to standard output. There is a small time window
+after Kea has been started but before it has read its configuration;
+logging in this short period can be controlled using environment
+variables. For details, see :ref:`logging-during-startup`.
+
+The three main elements of a logger configuration are: ``name`` (the
+component that is generating the messages), ``severity`` (what to log),
+and ``output_commands`` (where to log). There is also a ``debuglevel``
+element, which is only relevant if debug-level logging has been
+selected.
+
+The ``name`` (string) Logger
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each logger in the system has a name: that of the component binary file
+using it to log messages. For instance, to configure logging
+for the DHCPv4 server, add an entry for a logger named “kea-dhcp4”.
+This configuration will then be used by the loggers in the DHCPv4
+server and all the libraries used by it, unless a library defines its
+own logger and there is a specific logger configuration that applies to
+that logger.
+
+When tracking down an issue with the server's operation, use of DEBUG
+logging is required to obtain the verbose output needed for problem
+diagnosis. However, the high verbosity is likely to overwhelm the
+logging system in cases where the server is processing high-volume
+traffic. To mitigate this problem, Kea can use multiple loggers, for
+different functional parts of the server, that can each be configured
+independently. If the user is reasonably confident that a problem
+originates in a specific function of the server, or that the problem is
+related to a specific type of operation, they may enable high verbosity
+only for the relevant logger, thereby limiting the DEBUG messages to the
+required minimum.
+
+The loggers are associated with a particular library or binary of Kea.
+However, each library or binary may (and usually does) include multiple
+loggers. For example, the DHCPv4 server binary contains separate loggers
+for packet parsing, dropped packets, callouts, etc.
+
+The loggers form a hierarchy. For each program in Kea, there is a "root"
+logger, named after the program (e.g. the root logger for :iscman:`kea-dhcp4`, the
+DHCPv4 server, is named :iscman:`kea-dhcp4`). All other loggers are children of
+this logger and are named accordingly, e.g. the allocation engine in the
+DHCPv4 server logs messages using a logger called
+``kea-dhcp4.alloc-engine``.
+
+This relationship is important, as each child logger derives its default
+configuration from its parent root logger. In the typical case, the root
+logger configuration is the only logging configuration specified in the
+configuration file and so applies to all loggers. If an entry is made
+for a given logger, any attributes specified override those of the root
+logger, whereas any not specified are inherited from it.
+
+To illustrate this, suppose we are using the DHCPv4 server with the
+root logger :iscman:`kea-dhcp4` logging at the INFO level. In order to enable
+DEBUG verbosity for DHCPv4 packet drops, we must create a configuration
+entry for the logger with ``"name": "kea-dhcp4.bad-packets”``,
+``"severity": "DEBUG"``, and an explicit debug level. All other configuration
+parameters may be omitted for this logger if it should use the default values
+specified in the root logger's configuration.
+
+``debuglevel`` is inherited only if ``severity`` is missing as well. For
+predictable results, if ``severity`` is ``"DEBUG"``, these two attributes
+should always be explicitly specified or omitted together. An entry with an
+explicit ``"DEBUG"`` severity does not inherit ``debuglevel`` from the root
+logger and defaults to ``0`` if missing, resulting in no debug messages
+being logged. This is a consequence of relying on the log4cplus inheritance
+mechanism.
+
+If there are multiple logger specifications in the configuration that
+might match a particular logger, the specification with the more
+specific logger name takes precedence. For example, if there are entries
+for both :iscman:`kea-dhcp4` and ``kea-dhcp4.dhcpsrv``, the main DHCPv4 server
+program — and all libraries it uses other than the ``dhcpsrv`` library
+(libdhcpsrv) — logs messages according to the configuration in the
+first entry (:iscman:`kea-dhcp4`). Messages generated by the ``dhcpsrv`` library
+are logged according to the configuration set by the second entry.
+
+Currently defined loggers are listed in the following table. The
+"Software Package" column of this table specifies whether the particular
+loggers belong to the core Kea code (open source Kea binaries and
+libraries), or hook libraries (open source or premium).
+
+.. tabularcolumns:: |p{0.2\linewidth}|p{0.2\linewidth}|p{0.6\linewidth}|
+
+.. table:: List of loggers supported by Kea servers and hook libraries shipped with Kea/premium packages
+ :class: longtable
+ :widths: 20 20 60
+
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | Logger Name | Software Package | Description |
+ +==================================+=======================================+================================+
+ | ``kea-ctrl-agent`` | core | The root logger for |
+ | | | the Control Agent |
+ | | | exposing the RESTful |
+ | | | control API. All |
+ | | | components used by |
+ | | | the Control Agent |
+ | | | inherit the settings |
+ | | | from this logger. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.auth`` | core | A logger which covers |
+ | | | access control details, such as|
+ | | | a result of the basic HTTP |
+ | | | authentication. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.ctrl-agent`` | core | Used to log results of |
+ | | | configuration checks, |
+ | | | information about services |
+ | | | starting or failing to start, |
+ | | | command receival and |
+ | | | forwarding. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.http`` | core | A logger which |
+ | | | outputs log messages |
+ | | | related to receiving, |
+ | | | parsing, and sending |
+ | | | HTTP messages. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.rbac-hooks`` | :ischooklib:`libca_rbac.so` | Used to log messages related |
+ | | enterprise hook library | to the operation of the RBAC |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4`` | core | The root logger for |
+ | | | the DHCPv4 server. |
+ | | | All components used |
+ | | | by the DHCPv4 server |
+ | | | inherit the settings |
+ | | | from this logger. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp6`` | core | The root logger for |
+ | | | the DHCPv6 server. |
+ | | | All components used |
+ | | | by the DHCPv6 server |
+ | | | inherit the settings |
+ | | | from this logger. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.alloc-engine``, | core | Used by the lease |
+ | ``kea-dhcp6.alloc-engine`` | | allocation engine, |
+ | | | which is responsible |
+ | | | for managing leases |
+ | | | in the lease |
+ | | | database, i.e. |
+ | | | creating, modifying, |
+ | | | and removing DHCP |
+ | | | leases as a result of |
+ | | | processing messages |
+ | | | from clients. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.auth``, | core | Used to log malformed HTTP |
+ | ``kea-dhcp4.auth``, | | packets when using basic |
+ | ``kea-dhcp6.auth`` | | authentication. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.bad-packets``, | core | Used by the DHCP |
+ | ``kea-dhcp6.bad-packets`` | | servers for logging |
+ | | | inbound client |
+ | | | packets that were |
+ | | | dropped or to which |
+ | | | the server responded |
+ | | | with a DHCPNAK. It |
+ | | | allows administrators |
+ | | | to configure a |
+ | | | separate log output |
+ | | | that contains only |
+ | | | packet drop and |
+ | | | reject entries. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.bootp-hooks`` | :ischooklib:`libdhcp_bootp.so` | This logger is used to log |
+ | | open-source hook library | messages related to the |
+ | | | operation of the BOOTP hook |
+ | | | library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.callouts``, | core | Used to log messages |
+ | ``kea-dhcp4.callouts``, | | pertaining to the |
+ | ``kea-dhcp6.callouts``, | | callouts registation and |
+ | ``kea-dhcp-ddns.callouts`` | | execution for a particular |
+ | | | hook point. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.cb-cmds-hooks``, | :ischooklib:`libdhcp_cb_cmds.so` | Used to log messages related |
+ | ``kea-dhcp6.cb-cmds-hooks`` | subscription hook library | to the operation of the |
+ | | | Config Backend Commands |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.class-cmds-hooks``, | :ischooklib:`libdhcp_class_cmds.so` | Used to log messages related |
+ | ``kea-dhcp6.class-cmds-hooks`` | subscription hook library | to the operation of the |
+ | | | Class Commands |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.commands``, | core | Used to log messages |
+ | ``kea-dhcp6.commands`` | | relating to the |
+ | | | handling of commands |
+ | | | received by the DHCP |
+ | | | server over the |
+ | | | command channel. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.database``, | core | Used to log messages |
+ | ``kea-dhcp6.database`` | | relating to general |
+ | | | operations on the |
+ | | | relational databases. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.ddns-tuning-hooks``, | :ischooklib:`libdhcp_ddns_tuning.so` | Used to log messages related |
+ | ``kea-dhcp6.ddns-tuning-hooks`` | premium hook library | to the operation of the |
+ | | | DDNS Tuning hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.ddns``, | core | Used by the DHCP |
+ | ``kea-dhcp6.ddns`` | | server to log |
+ | | | messages related to |
+ | | | Client FQDN and |
+ | | | Hostname option |
+ | | | processing. It also |
+ | | | includes log messages |
+ | | | related to the |
+ | | | relevant DNS updates. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.dhcp4``, | core | Used to log basic operations. |
+ | ``kea-dhcp6.dhcp6`` | | |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.dhcpsrv``, | core | The base loggers for the |
+ | ``kea-dhcp6.dhcpsrv`` | | ``libkea-dhcpsrv.so`` library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.eval``, | core | Used to log messages |
+ | ``kea-dhcp6.eval`` | | relating to the |
+ | | | client classification |
+ | | | expression evaluation |
+ | | | code. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.flex-id-hooks``, | :ischooklib:`libdhcp_flex_id.so` | Used |
+ | ``kea-dhcp6.flex-id-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Flexible Identifier |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.flex-option-hooks``, | :ischooklib:`libdhcp_flex_option.so` | Used to log messages related |
+ | ``kea-dhcp6.flex-option-hooks`` | open-source hook library | to the operaton of |
+ | | | the Flexible Option |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.ha-hooks``, | :ischooklib:`libdhcp_ha.so` | Used |
+ | ``kea-dhcp6.ha-hooks`` | open-source hook library | to log messages |
+ | | | related to the |
+ | | | operation of the High |
+ | | | Availability hook |
+ | | | library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.hooks``, | core | Used to log messages related |
+ | ``kea-dhcp4.hooks``, | | to the maagemet of hook |
+ | ``kea-dhcp6.hooks``, | | libraries, e.g. |
+ | ``kea-dhcp-ddns.hooks`` | | registatin and |
+ | | | deregistration of the |
+ | | | libraries, and to the |
+ | | | initialization of the |
+ | | | callouts execution |
+ | | | for various hook |
+ | | | points within the |
+ | | | DHCP server. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.host-cache-hooks``, | :ischooklib:`libdhcp_host_cache.so` | Used |
+ | ``kea-dhcp6.host-cache-hooks`` | subscription hook library | to log messages |
+ | | | related to the |
+ | | | operation of the Host |
+ | | | Cache hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.host-cmds-hooks``, | :ischooklib:`libdhcp_host_cmds.so` | Used |
+ | ``kea-dhcp6.host-cmds-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the Host |
+ | | | Commands hook |
+ | | | library. In general, |
+ | | | these pertain to |
+ | | | the loading and |
+ | | | unloading of the |
+ | | | library and the |
+ | | | execution of commands |
+ | | | by the library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.hosts``, | core | Used within |
+ | ``kea-dhcp6.hosts`` | | ``libdhcpsrv``, it logs |
+ | | | messages related to |
+ | | | the management of |
+ | | | DHCP host |
+ | | | reservations, i.e. |
+ | | | retrieving |
+ | | | reservations and |
+ | | | adding new |
+ | | | reservations. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.lease-cmds-hooks``, | :ischooklib:`libdhcp_lease_cmds.so` | Used |
+ | ``kea-dhcp6.lease-cmds-hooks`` | open-source hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Lease Commands hook |
+ | | | library. In general, |
+ | | | these pertain to |
+ | | | the loading and |
+ | | | unloading of the |
+ | | | library and the |
+ | | | execution of commands |
+ | | | by the library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.limits-hooks``, | :ischooklib:`libdhcp_limits.so` | Used to log messages related |
+ | ``kea-dhcp6.limits-hooks`` | subscription hook library | to the operation of the |
+ | | | Limits hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.lease-query-hooks``, | :ischooklib:`libdhcp_lease_query.so` | Used |
+ | ``kea-dhcp6.lease-query-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Leasequery hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.leases``, | core | Used by the DHCP |
+ | ``kea-dhcp6.leases`` | | server to log |
+ | | | messages related to |
+ | | | lease allocation. The |
+ | | | messages include |
+ | | | detailed information |
+ | | | about the allocated |
+ | | | or offered leases, |
+ | | | errors during the |
+ | | | lease allocation, |
+ | | | etc. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.legal-log-hooks``, | :ischooklib:`libdhcp_legal_log.so` | Used |
+ | ``kea-dhcp6.legal-log-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Forensic Logging |
+ | | | hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.mysql-cb-hooks``, | :ischooklib:`libdhcp_mysql_cb.so` | Used |
+ | ``kea-dhcp6.mysql-cb-hooks`` | open-source hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | MySQL Configuration |
+ | | | Backend hook |
+ | | | library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.options``, | core | Used by the DHCP |
+ | ``kea-dhcp6.options`` | | server to log |
+ | | | messages related to |
+ | | | the processing of |
+ | | | options in the DHCP |
+ | | | messages, i.e. |
+ | | | parsing options, |
+ | | | encoding options into |
+ | | | on-wire format, and |
+ | | | packet classification |
+ | | | using options |
+ | | | contained in the |
+ | | | received packets. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.packets``, | core | Mostly |
+ | ``kea-dhcp6.packets`` | | used to log messages |
+ | | | related to |
+ | | | transmission of the |
+ | | | DHCP packets, i.e. |
+ | | | packet reception and |
+ | | | the sending of a |
+ | | | response. Such |
+ | | | messages include |
+ | | | information about the |
+ | | | source and |
+ | | | destination IP |
+ | | | addresses and |
+ | | | interfaces used to |
+ | | | transmit packets. The |
+ | | | logger is also used |
+ | | | to log messages |
+ | | | related to subnet |
+ | | | selection, as this |
+ | | | selection is usually |
+ | | | based on the IP |
+ | | | addresses, relay |
+ | | | addresses, and/or |
+ | | | interface names, |
+ | | | which can be |
+ | | | retrieved from the |
+ | | | received packet even |
+ | | | before the DHCP |
+ | | | message carried in |
+ | | | the packet is parsed. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.perfmon-hooks``, | :ischooklib:`libdhcp_perfmon.so` | Used to log messages related |
+ | ``kea-dhcp6.perfmon-hooks`` | open-source hook library | to performance monitoring. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.ping-check-hooks`` | :ischooklib:`libdhcp_ping_check.so` | Used |
+ | | subscription hook library | to log messages related to |
+ | | | carrying out pre-offer ping |
+ | | | checks of candidate leases. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.pgsql-cb-hooks``, | :ischooklib:`libdhcp_pgsql_cb.so` | Used |
+ | ``kea-dhcp6.pgsql-cb-hooks`` | open-source hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | PostgreSQL Configuration |
+ | | | Backend hook |
+ | | | library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.run-script-hooks``, | :ischooklib:`libdhcp_run_script.so` | Used to log messages related |
+ | ``kea-dhcp6.run-script-hooks`` | open-source hook library | to the operation of the |
+ | | | Run Script hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.radius-hooks``, | :ischooklib:`libdhcp_radius.so` | Used |
+ | ``kea-dhcp6.radius-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | RADIUS hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.stat-cmds-hooks``, | :ischooklib:`libdhcp_stat_cmds.so` | Used |
+ | ``kea-dhcp6.stat-cmds-hooks`` | opens-source hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Statistics Commands |
+ | | | hook library. In |
+ | | | general, these |
+ | | | pertain to loading |
+ | | | and unloading the |
+ | | | library and the |
+ | | | execution of commands |
+ | | | by the library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.subnet-cmds-hooks``, | :ischooklib:`libdhcp_subnet_cmds.so` | Used |
+ | ``kea-dhcp6.subnet-cmds-hooks`` | premium hook library | to log messages |
+ | | | related to the |
+ | | | operation of the |
+ | | | Subnet Commands hook |
+ | | | library. In general, |
+ | | | these pertain to |
+ | | | loading and unloading |
+ | | | the library and the |
+ | | | execution of commands |
+ | | | by the library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.tcp``, | core | Used to log messages related |
+ | ``kea-dhcp6.tcp`` | | to TCP traffic. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp4.user_chk``, | :ischooklib:`libdhcp_user_chk.so` | Used to log messages related |
+ | ``kea-dhcp6.user_chk`` | hook library | to the operaton of the |
+ | | | User Check hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns`` | core | The root logger for |
+ | | | the :iscman:`kea-dhcp-ddns` |
+ | | | daemon. All |
+ | | | components used by |
+ | | | this daemon inherit |
+ | | | the settings from |
+ | | | this logger unless |
+ | | | there are |
+ | | | configurations for |
+ | | | more specialized |
+ | | | loggers. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-ctrl-agent.dctl``, | core | Used to log basic inofrmaton |
+ | ``kea-dhcp-ddns.dctl`` | | about the process, |
+ | | | received signals, and |
+ | | | triggered |
+ | | | reconfigurations. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.asiodns``, | core | Used to log messages about |
+ | | | network events in DDNS |
+ | | | operations. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.dhcpddns`` | core | Used by |
+ | | | the :iscman:`kea-dhcp-ddns` |
+ | | | daemon to log |
+ | | | events related to |
+ | | | DDNS operations. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.dhcp-to-d2`` | core | Used by the |
+ | | | :iscman:`kea-dhcp-ddns` daemon |
+ | | | to log |
+ | | | information about |
+ | | | events dealing with |
+ | | | receiving messages |
+ | | | from the DHCP servers |
+ | | | and adding them to |
+ | | | the queue for |
+ | | | processing. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.d2-to-dns`` | core | Used by the |
+ | | | :iscman:`kea-dhcp-ddns` daemon |
+ | | | to log |
+ | | | information about |
+ | | | events dealing with |
+ | | | sending and receiving |
+ | | | messages to and from |
+ | | | the DNS servers. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.gss-tsig-hooks`` | :ischooklib:`libddns_gss_tsig.so` | Used to log messages related |
+ | | subscription hook library | to the operation of the |
+ | | | GSS-TSIG hook library. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-dhcp-ddns.libdhcp-ddns`` | core | Used to log events related to |
+ | | | DDNS operations. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+ | ``kea-netconf`` | core | The root logger for |
+ | | | the NETCONF agent. |
+ | | | All components used |
+ | | | by NETCONF inherit |
+ | | | the settings from |
+ | | | this logger if there |
+ | | | is no specialized |
+ | | | logger provided. |
+ +----------------------------------+---------------------------------------+--------------------------------+
+
+Note that user-defined hook libraries should not use any of the loggers
+mentioned above, but should instead define new loggers with names that
+correspond to the libraries using them. Suppose that a user created
+a library called “libdhcp-packet-capture” to dump packets received and
+transmitted by the server to a file. An appropriate name for the
+logger could be ``kea-dhcp4.packet-capture-hooks``. (Note that the hook
+library implementer only specifies the second part of this name, i.e.
+“packet-capture”. The first part is a root-logger name and is prepended
+by the Kea logging system.) It is also important to note that since this
+new logger is a child of a root logger, it inherits the configuration
+from the root logger, something that can be overridden by an entry in
+the configuration file.
+
+The easiest way to find a logger name is to configure all logging to go
+to a single destination and look there for specific logger names. See
+:ref:`logging-message-format` for details.
+
+The ``severity`` (string) Logger
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This specifies the category of messages logged. Each message is logged
+with an associated severity, which may be one of the following (in
+descending order of severity):
+
+- FATAL - associated with messages generated by a condition that is so
+ serious that the server cannot continue executing.
+
+- ERROR - associated with messages generated by an error condition. The
+ server continues executing, but the results may not be as
+ expected.
+
+- WARN - indicates an out-of-the-ordinary condition. However, the
+ server continues executing normally.
+
+- INFO - an informational message marking some event.
+
+- DEBUG - messages produced for debugging purposes.
+
+When the severity of a logger is set to one of these values, it
+only logs messages of that severity and above (e.g. setting the logging
+severity to INFO logs INFO, WARN, ERROR, and FATAL messages). The
+severity may also be set to NONE, in which case all messages from that
+logger are inhibited.
+
+.. note::
+
+ The :iscman:`keactrl` tool, described in :ref:`keactrl`, can be configured
+ to start the servers in verbose mode. If this is the case, the
+ settings of the logging severity in the configuration file have
+ no effect; the servers use a logging severity of DEBUG
+ regardless of the logging settings specified in the configuration
+ file. To control severity via the configuration file,
+ please make sure that the ``kea_verbose`` value is set to "no" within
+ the :iscman:`keactrl` configuration.
+
+.. _debuglevel:
+
+The ``debuglevel`` (integer) Logger
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a logger's severity is set to DEBUG, this value specifies the
+level of debug messages to be printed. It ranges from 0 (least
+verbose) to 99 (most verbose). If severity for the logger is not DEBUG,
+this value is ignored.
+
+The ``output-options`` (list) Logger
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each logger can have zero or more ``output-options``. These specify
+where log messages are sent and are explained in detail below.
+
+.. note::
+
+ As of Kea 2.5.1, alias ``output-options`` was added that can be used
+ interchangeably with previous ``output_options`` configuration key.
+ The reason behind this was to keep all configuration keys consistent i.e.
+ to use "dash" instead of "underscore" in the key name. For the time being
+ both configuration keys are considered correct and mean the same to Kea parsers.
+
+ As of Kea 2.5.2, the ``output-options`` becomes the default configuration key
+ and ``output_options`` can be used as an alias.
+
+The ``output`` (string) Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This value determines the type of output. There are several special
+values allowed here: ``stdout`` (messages are printed on standard
+output), ``stderr`` (messages are printed on stderr), ``syslog``
+(messages are logged to syslog using the default name), ``syslog:name``
+(messages are logged to syslog using a specified name). Any other value is
+interpreted as a filename to which messages should be written.
+
+The ``flush`` (boolean) Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This flushes the buffers after each log message. Doing this reduces performance
+but ensures that if the program terminates abnormally, all messages
+up to the point of termination are output. The default is ``true``.
+
+The ``maxsize`` (integer) Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This option is only relevant when the destination is a file; this is the maximum size
+in bytes that a log file may reach. When the maximum size is reached,
+the file is renamed and a new file created. Initially, a ".1" is
+appended to the name; if a ".1" file exists, it is renamed ".2", etc.
+This is referred to as rotation.
+
+The default value is 10240000 (10MB). The smallest value that can be
+specified without disabling rotation is 204800. Any value less than
+this, including 0, disables rotation. The greatest possible value is INT_MAX MB, which is
+approximately 2PB.
+
+.. note::
+
+ Due to a limitation of the underlying logging library (log4cplus),
+ rolling over the log files (from ".1" to ".2", etc.) may show odd
+ results; there can be multiple small files at the timing of rollover.
+ This can happen when multiple processes try to roll over the
+ files simultaneously. Version 1.1.0 of log4cplus solved this problem,
+ so if this version or later of log4cplus is used to build Kea, the
+ issue should not occur. Even with older versions, it is normally
+ expected to happen rarely unless the log messages are produced very
+ frequently by multiple different processes.
+
+The ``maxver`` (integer) Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This option is only relevant when the destination is a file and rotation is enabled
+(i.e. maxsize is large enough). This is the maximum number of rotated
+versions that will be kept. Once that number of files has been reached,
+the oldest file, "log-name.maxver", is discarded each time the log
+rotates. In other words, at most there will be the active log file plus
+maxver rotated files. The minimum and default value is 1.
+
+The ``pattern`` (string) Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This option can be used to specify the layout pattern of messages for
+a logger. Kea logging is implemented using the log4cplus library and its
+output formatting is based, conceptually, on the printf formatting from C;
+this is discussed in detail in the next section,
+:ref:`logging-message-format`.
+
+Each output type (``stdout``, file, or ``syslog``) has a default ``pattern`` which
+describes the content of its log messages. This parameter can be used to
+specify a desired pattern. The pattern for each logger is governed
+individually, so each configured logger can have its own pattern. Omitting
+the ``pattern`` parameter or setting it to an empty string, "", causes
+Kea to use the default pattern for that logger's output type.
+
+In addition to the log text itself, the default patterns used for ``stdout``
+and files contain information such as date and time, logger level, and
+process information. The default pattern for ``syslog`` is limited primarily
+to log level, source, and the log text. This avoids duplicating information
+which is usually supplied by syslog.
+
+.. warning::
+ Users are strongly encouraged to test their pattern(s) on a local,
+ non-production instance of Kea, running in the foreground and
+ logging to ``stdout``.
+
+.. _logging-message-format:
+
+Logging Message Format
+----------------------
+
+As mentioned above, Kea log message content is controlled via a scheme similar
+to the C language's printf formatting. The "pattern" used for each message is
+described by a string containing one or more format components as part of a
+text string. In addition to the components, the string may contain any other
+useful text for the administrator.
+
+The behavior of Kea's format strings is determined by log4cplus. The following
+time format options are possible enclosed in ``%D{}`` or ``%d{}``:
+
+.. table:: List of supported time format string components by Kea's logger
+ :class: longtable
+ :widths: 8 40
+
+ +-----------+-----------------------------------------------+
+ | Component | Value |
+ +===========+===============================================+
+ | ``%a`` | Abbreviated weekday name |
+ +-----------+-----------------------------------------------+
+ | ``%A`` | Full weekday name |
+ +-----------+-----------------------------------------------+
+ | ``%b`` | Abbreviated month name |
+ +-----------+-----------------------------------------------+
+ | ``%B`` | Full month name |
+ +-----------+-----------------------------------------------+
+ | ``%c`` | Standard date and time string |
+ +-----------+-----------------------------------------------+
+ | ``%d`` | Day of month as a decimal(1-31) |
+ +-----------+-----------------------------------------------+
+ | ``%H`` | Hour(0-23) |
+ +-----------+-----------------------------------------------+
+ | ``%I`` | Hour(1-12) |
+ +-----------+-----------------------------------------------+
+ | ``%j`` | Day of year as a decimal(1-366) |
+ +-----------+-----------------------------------------------+
+ | ``%m`` | Month as decimal(1-12) |
+ +-----------+-----------------------------------------------+
+ | ``%M`` | Minute as decimal(0-59) |
+ +-----------+-----------------------------------------------+
+ | ``%p`` | Locale's equivalent of AM or PM |
+ +-----------+-----------------------------------------------+
+ | ``%q`` | milliseconds as decimal(0-999) |
+ +-----------+-----------------------------------------------+
+ | ``%Q`` | microseconds as decimal(0-999.999) |
+ +-----------+-----------------------------------------------+
+ | ``%S`` | Second as decimal(0-59) |
+ +-----------+-----------------------------------------------+
+ | ``%U`` | Week of year, Sunday being first day(0-53) |
+ +-----------+-----------------------------------------------+
+ | ``%w`` | Weekday as a decimal(0-6, Sunday being 0) |
+ +-----------+-----------------------------------------------+
+ | ``%W`` | Week of year, Monday being first day(0-53) |
+ +-----------+-----------------------------------------------+
+ | ``%x`` | Standard date string |
+ +-----------+-----------------------------------------------+
+ | ``%X`` | Standard time string |
+ +-----------+-----------------------------------------------+
+ | ``%y`` | Year in decimal without century(0-99) |
+ +-----------+-----------------------------------------------+
+ | ``%Y`` | Year including century as decimal |
+ +-----------+-----------------------------------------------+
+ | ``%Z`` | Time zone name |
+ +-----------+-----------------------------------------------+
+ | ``%%`` | The percent sign |
+ +-----------+-----------------------------------------------+
+
+Refer to the documentation for the ``strftime()`` function found in the
+``<ctime>`` header or the ``strftime(3)`` UNIX manual page for more
+information.
+
+It is probably easiest to understand this by examining the default pattern
+for stdout and files; currently they are the same. That pattern is shown
+below:
+
+::
+
+ "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c/%i.%t] %m\n"
+
+and a typical log produced by this pattern looks something like this:
+
+::
+
+ 2019-08-05 14:27:45.871 DEBUG [kea-dhcp4.dhcpsrv/8475.12345] DHCPSRV_TIMERMGR_START_TIMER starting timer: reclaim-expired-leases
+
+That breaks down to:
+
+ - ``%D{%Y-%m-%d %H:%M:%S.%q}``
+ "%D" is the local date and time when the log message is generated,
+ while everything between the curly braces, "{}", are date and time components.
+ From the example log above this produces:
+ ``2019-08-05 14:27:45.871``
+
+ - ``%-5p``
+ The severity of the message, output as a minimum of five characters,
+ using right-padding with spaces. In our example log: ``DEBUG``
+
+ - ``%c``
+ The log source. This includes two elements: the Kea process generating the
+ message, in this case, :iscman:`kea-dhcp4`; and the component within the program
+ from which the message originated, ``dhcpsrv`` (e.g. the name of the
+ library used by DHCP server implementations).
+
+ - ``%i``
+ The process ID. From the example log: ``8475``.
+
+ - ``%t``
+ The thread ID. From the example log: ``12345``.
+ The format of the thread ID is OS-dependent: e.g. on some systems
+ it is an address, so it is displayed in hexadecimal.
+
+ - ``%m``
+ The log message itself. Kea log messages all begin with a message identifier
+ followed by arbitrary log text. Every message in Kea has a unique
+ identifier, which can be used as an index to the :ref:`kea-messages`, where
+ more information can be obtained. In our example log above, the identifier
+ is ``DHCPSRV_TIMERMGR_START_TIMER``. The log text is typically a brief
+ description detailing the condition that caused the message to be logged. In
+ our example, the information logged,
+ ``starting timer: reclaim-expired-leases``, explains that the timer for the
+ expired lease reclamation cycle has been started.
+
+.. Warning::
+
+ Omitting ``%m`` omits the log message text from the output, making it
+ rather useless. ``%m`` should be considered mandatory.
+
+Finally, note that spacing between components, the square brackets around the
+log source and PID, and the final carriage return ``\n`` are all literal text
+specified as part of the pattern.
+
+.. Warning::
+
+ To ensure that each log entry is a separate line, patterns
+ must end with an ``\n``. There may be use cases where it is not desired
+ so we do not enforce its inclusion. If it is omitted from
+ the pattern, the log entries will run together in one long "line".
+
+The default pattern for ``syslog`` output is:
+
+::
+
+ "%-5p [%c.%t] %m\n"
+
+It omits the date and time as well as the process ID, as this
+information is typically output by ``syslog``. Note that Kea uses the pattern
+to construct the text it sends to ``syslog`` (or any other destination). It has
+no influence on the content ``syslog`` may add or formatting it may do.
+
+Consult the OS documentation for ``syslog`` behavior, as there are multiple
+implementations.
+
+A complete list of logging parameters supported by Kea is shown in the table below:
+
+.. table:: List of supported format string components by Kea's logger
+ :class: longtable
+ :widths: 8 40
+
+ +-----------+------------------------------------------------------------------------+
+ | Component | Value |
+ +===========+========================================================================+
+ | ``%b`` | Outputs file that called the log e.g., logger_impl.cc |
+ +-----------+------------------------------------------------------------------------+
+ | ``%c`` | Outputs the logger of the event e.g., kea-dhcp4.hosts |
+ +-----------+------------------------------------------------------------------------+
+ | ``%d`` | ``%d{}`` formats UTC time output e.g., ``%d{%Y-%m-%d %H:%M:%S.%q}`` |
+ +-----------+------------------------------------------------------------------------+
+ | ``%D`` | ``%D{}`` formats LOCAL time output e.g., ``%D{%Y-%m-%d %H:%M:%S.%q}`` |
+ +-----------+------------------------------------------------------------------------+
+ | ``%E`` | Outputs environment variables e.g., ``%E{PATH}`` |
+ +-----------+------------------------------------------------------------------------+
+ | ``%F`` | Outputs filename where logging request was issued e.g., logger_impl.cc |
+ +-----------+------------------------------------------------------------------------+
+ | ``%h`` | Outputs hostname of the system e.g., host-1 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%H`` | Outputs fully qualified domain name e.g., host-1.example.com |
+ +-----------+------------------------------------------------------------------------+
+ | ``%l`` | Equivalent to ``%F:%L`` e.g., logger_impl.cc:179 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%L`` | Outputs the line number where the log was called e.g., 179 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%m`` | Outputs the actual log message |
+ +-----------+------------------------------------------------------------------------+
+ | ``%M`` | Outputs caller (function name) of the log message |
+ +-----------+------------------------------------------------------------------------+
+ | ``%n`` | Outputs line separator suppored by platform e.g., ``\n`` in Linux |
+ +-----------+------------------------------------------------------------------------+
+ | ``%p`` | Outputs log severity e.g., INFO |
+ +-----------+------------------------------------------------------------------------+
+ | ``%r`` | Outputs milliseconds since program start e.g., 1235 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%t`` | Outputs thread id that generated the log message e.g., 281472855306256 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%T`` | Outputs thread name that generated the log message e.g., 168005 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%i`` | Outputs process id that generated the log message e.g., 168030 |
+ +-----------+------------------------------------------------------------------------+
+ | ``%%`` | Outputs a literal percent sign |
+ +-----------+------------------------------------------------------------------------+
+
+Padding and truncation are also possible with modifiers preceeding the component. This is
+done by placing a number and other modifier characters between the component and the %
+sign. There are five ways of modifying the output shown by example here.
+
+ - ``%20p``
+ Left pads with spaces (align right) if the severity is shorter than 20 characters.
+
+ - ``%-15r``
+ Right pads with spaces (align left) if the milliseconds since program start is shorter
+ than 15 characters.
+
+ - ``%.30m``
+ Truncates from the beginning of the message if the message is longer than 30
+ characters.
+
+ - ``%10.35E{PATH}``
+ Left pad with spaces (align right) if the environment variable "PATH" is shorter than
+ 10 characters. If the content is longer than 35 characters, then truncate from the
+ beginning of the string.
+
+ - ``%-15.40m``
+ Right pad with spaces (align left) if the log message is shorter than 15 characters.
+ If the message is longer than 40 characters, truncate from the beginning.
+
+Supported parameters depend on the liblog4cplus version used to compile Kea. This can
+be checked by executing ``kea-dhcp4 -W | grep -i log4cplus`` which will produce output
+like this: ``LOG4CPLUS_VERSION: 2.0.5``. Consult the documentation in the
+`log4cplus wiki <https://github.com/log4cplus/log4cplus/wiki>`__ for further information
+about the version you have installed.
+
+Example Logger Configurations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this example, we want to set the server logging to write to the
+console using standard output.
+
+::
+
+ "Server": {
+ "loggers": [
+ {
+ "name": "kea-dhcp4",
+ "output-options": [
+ {
+ "output": "stdout"
+ }
+ ],
+ "severity": "WARN"
+ }
+ ]
+ }
+
+As a second example, we want to store DEBUG log messages in a file
+that is at most 2MB and keep up to eight copies of old log files. Once the
+logfile grows to 2MB, it should be renamed and a new file should be created.
+
+::
+
+ "Server": {
+ "loggers": [
+ {
+ "name": "kea-dhcp6",
+ "output-options": [
+ {
+ "output": "/var/log/kea-debug.log",
+ "maxver": 8,
+ "maxsize": 204800,
+ "flush": true,
+ "pattern": "%d{%j %H:%M:%S.%q} %c %m\n"
+ }
+ ],
+ "severity": "DEBUG",
+ "debuglevel": 99
+ }
+ ]
+ }
+
+Notice that the above configuration uses a custom pattern which produces output like this:
+
+::
+
+ 220 13:50:31.783 kea-dhcp4.dhcp4 DHCP4_STARTED Kea DHCPv4 server version 1.6.0-beta2-git started
+
+
+.. _logging-during-startup:
+
+Logging During Kea Startup
+--------------------------
+
+The logging configuration is specified in the configuration file.
+However, when Kea starts, the configuration file is not read until partway into the
+initialization process. Prior to that, the logging settings are set to
+default values, although it is possible to modify some aspects of the
+settings by means of environment variables. In the absence of
+any logging configuration in the configuration file, the settings of the
+(possibly modified) default configuration will persist while the program
+is running.
+
+The following environment variables can be used to control the behavior
+of logging during startup:
+
+``KEA_LOCKFILE_DIR``
+
+ Specifies a directory where the logging system should create its lock
+ file. If not specified, it is prefix/var/run/kea, where "prefix"
+ defaults to /usr/local. This variable must not end with a slash.
+ There is one special value: "none", which instructs Kea not to create
+ a lock file at all. This may cause issues if several processes log to
+ the same file.
+
+``KEA_LOGGER_DESTINATION``
+
+ Specifies logging output. There are several special values:
+
+ ``stdout``
+ Log to standard output.
+
+ ``stderr``
+ Log to standard error.
+
+ ``syslog[:fac]``
+ Log via syslog. The optional "fac" (which is separated from the word
+ "syslog" by a colon) specifies the facility to be used for the log
+ messages. Unless specified, messages are logged using the
+ facility "local0".
+
+ Any other value is treated as a name of the output file. If not
+ otherwise specified, Kea logs to standard output.
+
+Logging Levels
+==============
+
+All Kea servers follow the overall intention to let the user
+know what is going on while not overloading the logging system with too much information, as that
+could easily be used as a denial-of-service attack.
+
+Unlike the FATAL, ERROR, WARN and
+INFO levels, DEBUG has additional parameters. The following list details
+the basic information that is logged on each level. Sometimes the circumstances
+determine whether a piece of information is logged on a higher
+or lower level. For example, if a packet is being dropped due to configured classification, that
+is an execution of the configured policy and would be logged on debuglevel 15. However, if the
+packet is dropped due to an exception being thrown, it is much more important, as it may indicate
+a software bug, serious problems with memory, or database connectivity problems. As such it may
+be logged on much higher levels, such as WARN or even ERROR.
+
+- 0 - singular messages printed during startup or shutdown of the server.
+- 10 - log information about received API commands.
+- 15 - information about reasons why a packet was dropped.
+- 40 - tracing information, including processing decisions, results
+ of expression evaluations, and more.
+- 45 - similar to level 40, but with more details, e.g. the subnet being
+ selected for an incoming packet.
+- 50 - evaluations of expressions, status received from hook points, lease
+ processing, packet processing details, including unpacking, packing, sending, etc.
+- 55 - includes all details available, including full packet contents
+ with all options printed.
+
+The debug levels apply only to messages logged on DEBUG, and are configured using
+the ``debuglevel`` option. See the :ref:`debuglevel` section for details.
diff --git a/doc/sphinx/arm/quickstart.rst b/doc/sphinx/arm/quickstart.rst
new file mode 100644
index 0000000..81cc316
--- /dev/null
+++ b/doc/sphinx/arm/quickstart.rst
@@ -0,0 +1,382 @@
+.. _quickstart:
+
+***********
+Quick Start
+***********
+
+This section describes the basic steps needed to get Kea up and running.
+For further details, full customizations, and troubleshooting, see the
+respective chapters elsewhere in this Kea Administrator Reference Manual (ARM).
+
+.. _quick-start-tarball:
+
+Quick Start Guide Using tarball
+===============================
+
+1. Install required runtime and build dependencies. See
+ :ref:`build-requirements` for details.
+
+2. Download the Kea source tarball from
+ `the ISC.org downloads page <https://www.isc.org/download/>`__ or
+ `the ISC downloads site <https://downloads.isc.org/isc/kea/>`__ or
+ `the ISC Cloudsmith page <https://cloudsmith.io/~isc/packages/?q=format%3Araw>`__.
+
+3. Extract the tarball. For example:
+
+ .. parsed-literal::
+
+ $ tar -xvzf kea-|release|.tar.gz
+
+4. Go into the source directory and run the configure script:
+
+ .. parsed-literal::
+
+ $ cd kea-|release|
+ $ ./configure [your extra parameters]
+
+5. Build it:
+
+ .. code-block:: console
+
+ $ make
+
+6. Install it (by default it will be placed in ``/usr/local/``, so
+ root privileges are likely required for this step):
+
+ .. code-block:: console
+
+ $ make install
+
+.. _quick-start-repo:
+
+Quick Start Guide Using Native Packages
+=======================================
+
+ISC provides native Alpine, deb, and RPM packages, which make Kea installation
+much easier. Unless specific compilation options are desired, it is usually
+easier to install Kea using native packages.
+
+1. Go to `Kea on cloudsmith.io <https://cloudsmith.io/~isc/repos/>`__.
+
+2. Choose the Cloudsmith repository e.g. |cloudsmith_repo| for Kea |version|.
+
+3. Click on the arrow besides the ``Set Me Up`` button and select your OS flavor
+ out of: ``Alpine``, ``Debian``, ``RedHat``.
+
+4. Follow the instructions written there.
+
+.. note::
+ For example, the Debian setup instructions for Kea 2.4 can be found here:
+ https://cloudsmith.io/~isc/repos/kea-2-4/setup/#formats-deb
+
+ The dropdown near the top of the page offers instructions for
+ other operating systems.
+
+5. Kea is split into various packages. The entire list is available on the
+ Cloudsmith repository page under ``Packages``, or it can be retrieved
+ using ``apk``/``apt``/``dnf``.
+
+.. list-table::
+ :stub-columns: 1
+ :widths: 10 90
+
+ * - Debian/Ubuntu
+
+ - .. code-block:: console
+
+ $ apt search isc-kea
+
+ .. note::
+ ``isc-kea-dhcp4-server`` and ``isc-kea-dhcp6-server`` are empty
+ transitional packages. The working server packages are
+ ``isc-kea-dhcp4`` and ``isc-kea-dhcp6``.
+
+ * - Fedora/RedHat
+
+ - .. code-block:: console
+
+ $ dnf search 'isc-kea*'
+
+ * - Alpine
+
+ - .. code-block:: console
+
+ $ apk search isc-kea
+
+6. Install the metapackage containing all the tools, libraries, servers,
+ documentation, and open source hooks:
+
+.. list-table::
+ :stub-columns: 1
+ :widths: 10 90
+
+ * - Debian/Ubuntu
+
+ - .. code-block:: console
+
+ $ sudo apt install isc-kea
+
+ * - Fedora/RedHat
+
+ - .. code-block:: console
+
+ $ sudo dnf install isc-kea
+
+ * - Alpine
+
+ - .. code-block:: console
+
+ # apk add isc-kea
+
+or specific packages:
+
+.. list-table::
+ :stub-columns: 1
+ :widths: 10 90
+
+ * - Debian/Ubuntu
+
+ - .. code-block:: console
+
+ $ sudo apt install isc-kea-dhcp6
+
+ * - Fedora/RedHat
+
+ - .. code-block:: console
+
+ $ sudo dnf install isc-kea-dhcp6
+
+ * - Alpine
+
+ - .. code-block:: console
+
+ $ apk add isc-kea-dhcp6
+
+or every single Kea-related package, including development headers, debug
+symbols, and premium hooks (if available):
+
+.. list-table::
+ :stub-columns: 1
+ :widths: 10 90
+
+ * - Debian/Ubuntu
+
+ - .. code-block:: console
+
+ $ sudo apt install 'isc-kea*'
+
+ * - Fedora/RedHat
+
+ - .. code-block:: console
+
+ $ sudo dnf install 'isc-kea*'
+
+ * - Alpine
+
+ - Installing packages via globbing (``*``) is not available for Alpine,
+ but it can be simulated with the following command:
+
+ .. code-block:: console
+
+ # apk search isc-kea | sed 's/-[0-9].*//g' | xargs apk add
+
+or all packages with a specified version number:
+
+.. list-table::
+ :stub-columns: 1
+ :widths: 10 90
+
+ * - Debian/Ubuntu
+
+ - .. code-block:: console
+
+ $ sudo apt install 'isc-kea*=2.4.0-isc20230921141113'
+
+ * - Fedora/RedHat
+
+ - .. code-block:: console
+
+ $ sudo dnf install 'isc-kea*2.4.0-isc20230921141113*'
+
+ * - Alpine
+
+ - Installing packages via globbing (``*``) is not available for Alpine,
+ but it can be simulated with the following command:
+
+ .. code-block:: console
+
+ # apk search isc-kea | sed 's/-[0-9].*//g' | grep r20230921141113 | xargs apk add
+
+8. All installed packages should be now available directly.
+
+ You can start a server up manually:
+
+ .. code-block:: console
+
+ # kea-dhcp6 -c /etc/kea/kea-dhcp6.conf
+
+ or using systemd:
+
+ .. code-block:: console
+
+ # systemctl restart kea-dhcp6
+
+ or using OpenRC on Alpine:
+
+ .. code-block:: console
+
+ # service kea-dhcp6 restart
+
+.. note::
+ :iscman:`keactrl` is not available in packages, as similar functionality is provided
+ by the native systemctl scripts.
+
+9. On Debian/Ubuntu systems, the service is enabled at boot time automatically
+ when the package is installed. On Fedora/RHEL and Alpine, the service is not
+ enabled automatically, so, if desired, it must be enabled manually.
+
+ With systemd on Fedora/RedHat:
+
+ .. code-block:: console
+
+ # systemctl enable kea-dhcp6
+
+ With OpenRC on Alpine:
+
+ .. code-block:: console
+
+ # rc-update add kea-dhcp6
+
+
+.. _quick-start-docker:
+
+Quick Start Guide Using Docker Containers
+=========================================
+
+1. Go to `ISC docker repository on cloudsmith.io <https://cloudsmith.io/~isc/repos/docker/packages/>`__.
+
+2. Create an ipvlan network attached to the client-facing host interface and
+ assigned to the subnet that is served by Kea.
+
+.. code-block:: console
+
+ $ docker network create --driver ipvlan --ipv6 --subnet 2001:db8::/64 --opt parent=eth0 ipvlan0
+
+3. Pick the desired image and pull it locally.
+
+.. code-block:: console
+
+ $ docker pull docker.cloudsmith.io/isc/docker/kea-dhcp6
+
+
+4. Create a container out of the image. Mount the configuration volume and the
+ data volume if needed.
+
+.. code-block:: console
+
+ $ docker create \
+ --name kea-dhcp6 \
+ --network ipvlan0 \
+ --volume /local/kea/config:/etc/kea \
+ --volume /local/kea/data:/var/lib/kea \
+ docker.cloudsmith.io/isc/docker/kea-dhcp6
+
+5. Start the docker container.
+
+.. code-block:: console
+
+ $ docker start kea-dhcp6
+
+6. To stop the docker container, run:
+
+.. code-block:: console
+
+ $ docker stop kea-dhcp6
+
+.. note::
+
+ Refer to the `kea-docker readme <https://gitlab.isc.org/isc-projects/kea-docker#user-content-docker-files-for-building-kea-containers>`__ for more complex scenarios.
+
+
+.. _quick-start-services:
+
+Quick Start Guide for DHCPv4 and DHCPv6 Services
+================================================
+
+1. Edit the Kea configuration files, which by default are installed in
+ the ``[kea-install-dir]/etc/kea/`` directory. These are:
+ ``kea-dhcp4.conf``, ``kea-dhcp6.conf``, ``kea-dhcp-ddns.conf`` and
+ ``kea-ctrl-agent.conf``, ``keactrl.conf`` for DHCPv4 server, DHCPv6 server,
+ D2, Control Agent, and the keactrl script, respectively.
+
+2. To start the DHCPv4 server in the background, run the
+ following command (as root):
+
+ .. code-block:: console
+
+ # keactrl start -s dhcp4
+
+ Or run the following command to start the DHCPv6 server:
+
+ .. code-block:: console
+
+ # keactrl start -s dhcp6
+
+ Note that it is also possible to start all servers simultaneously:
+
+ .. code-block:: console
+
+ # keactrl start
+
+3. Verify that the Kea server(s) is/are running:
+
+ .. code-block:: console
+
+ # keactrl status
+
+ A server status of "inactive" may indicate a configuration error.
+ Please check the log file (by default named
+ ``[kea-install-dir]/var/log/kea-dhcp4.log``,
+ ``[kea-install-dir]/var/log/kea-dhcp6.log``,
+ ``[kea-install-dir]/var/log/kea-ddns.log``, or
+ ``[kea-install-dir]/var/log/kea-ctrl-agent.log``) for the details of
+ any errors.
+
+4. If the server has started successfully, test that it is
+ responding to DHCP queries and that the client receives a
+ configuration from the server; for example, use the `ISC DHCP
+ client <https://www.isc.org/download/>`__.
+
+5. To stop running the server(s):
+
+ .. code-block:: console
+
+ # keactrl stop
+
+For system-specific instructions, please read the
+`system-specific notes <https://kb.isc.org/docs/installing-kea>`__,
+available in the Kea section of `ISC's
+Knowledgebase <https://kb.isc.org/docs>`__.
+
+The details of :iscman:`keactrl` script usage can be found in :ref:`keactrl`.
+
+Once Kea services are up and running, consider deploying a dashboard solution
+to monitor running services. For more details, see :ref:`stork`.
+
+.. _quick-start-direct-run:
+
+Running the Kea Servers Directly
+================================
+
+The Kea servers can be started directly, without the need to use
+:iscman:`keactrl` or ``systemctl``. To start the DHCPv4 server run the following command:
+
+.. code-block:: console
+
+ # kea-dhcp4 -c /path/to/your/kea4/config/file.json
+
+Similarly, to start the DHCPv6 server, run the following command:
+
+.. code-block:: console
+
+ # kea-dhcp6 -c /path/to/your/kea6/config/file.json
diff --git a/doc/sphinx/arm/rst_arm_sources.mk b/doc/sphinx/arm/rst_arm_sources.mk
new file mode 100644
index 0000000..dc2cf45
--- /dev/null
+++ b/doc/sphinx/arm/rst_arm_sources.mk
@@ -0,0 +1,54 @@
+rst_arm_sources += arm/acknowledgments.rst
+rst_arm_sources += arm/admin.rst
+rst_arm_sources += arm/agent.rst
+rst_arm_sources += arm/classify.rst
+rst_arm_sources += arm/config-backend.rst
+rst_arm_sources += arm/config-templates.rst
+rst_arm_sources += arm/config.rst
+rst_arm_sources += arm/congestion-handling.rst
+rst_arm_sources += arm/ctrl-channel.rst
+rst_arm_sources += arm/database-connectivity.rst
+rst_arm_sources += arm/ddns.rst
+rst_arm_sources += arm/dhcp4-srv.rst
+rst_arm_sources += arm/dhcp6-srv.rst
+rst_arm_sources += arm/ext-gss-tsig.rst
+rst_arm_sources += arm/ext-netconf.rst
+rst_arm_sources += arm/ext-radius.rst
+rst_arm_sources += arm/hammer.rst
+rst_arm_sources += arm/hooks-bootp.rst
+rst_arm_sources += arm/hooks-cb-cmds.rst
+rst_arm_sources += arm/hooks-class-cmds.rst
+rst_arm_sources += arm/hooks-ddns-tuning.rst
+rst_arm_sources += arm/hooks-flex-id.rst
+rst_arm_sources += arm/hooks-flex-option.rst
+rst_arm_sources += arm/hooks-gss-tsig.rst
+rst_arm_sources += arm/hooks-ha.rst
+rst_arm_sources += arm/hooks-host-cache.rst
+rst_arm_sources += arm/hooks-host-cmds.rst
+rst_arm_sources += arm/hooks-lease-cmds.rst
+rst_arm_sources += arm/hooks-lease-query.rst
+rst_arm_sources += arm/hooks-limits.rst
+rst_arm_sources += arm/hooks-cb-mysql.rst
+rst_arm_sources += arm/hooks-cb-pgsql.rst
+rst_arm_sources += arm/hooks-legal-log.rst
+rst_arm_sources += arm/hooks-perfmon.rst
+rst_arm_sources += arm/hooks-ping-check.rst
+rst_arm_sources += arm/hooks-radius.rst
+rst_arm_sources += arm/hooks-rbac.rst
+rst_arm_sources += arm/hooks-run-script.rst
+rst_arm_sources += arm/hooks-stat-cmds.rst
+rst_arm_sources += arm/hooks-subnet-cmds.rst
+rst_arm_sources += arm/hooks-user-chk.rst
+rst_arm_sources += arm/hooks.rst
+rst_arm_sources += arm/install.rst
+rst_arm_sources += arm/integrations.rst
+rst_arm_sources += arm/intro.rst
+rst_arm_sources += arm/keactrl.rst
+rst_arm_sources += arm/lease-expiration.rst
+rst_arm_sources += arm/lfc.rst
+rst_arm_sources += arm/logging.rst
+rst_arm_sources += arm/quickstart.rst
+rst_arm_sources += arm/security.rst
+rst_arm_sources += arm/shell.rst
+rst_arm_sources += arm/stats.rst
+rst_arm_sources += arm/stork.rst
diff --git a/doc/sphinx/arm/security.rst b/doc/sphinx/arm/security.rst
new file mode 100644
index 0000000..3063fb0
--- /dev/null
+++ b/doc/sphinx/arm/security.rst
@@ -0,0 +1,445 @@
+.. _security:
+
+************
+Kea Security
+************
+
+Kea was originally designed to be installed in a protected environment, in a network
+datacenter; it did not offer hardened security features. However, due to customer demand
+and evolving network requirements, support for basic HTTP authentication and Transport
+Layer Security (TLS) have been added to Kea.
+
+.. _tls:
+
+TLS/HTTPS Support
+=================
+
+Since Kea 1.9.6, TLS can be used to secure HTTP communication. There are three levels of
+protection possible:
+
+- No TLS. The connection is plain-text, unencrypted HTTP. (This is
+ the only option available in versions prior to Kea 1.9.6.)
+
+- Encryption, which protects against passive attacks and
+ eavesdropping. In this case, the server is authenticated but the client is
+ not. This is the typical mode when securing a website, where
+ clients and servers are not under the control of a common entity.
+
+- Mutual authentication between the client and the server. This is the
+ strictest security mode and is the default when TLS is
+ enabled.
+
+.. note::
+
+ TLS mutual authentication is for TLS entities only. When TLS and
+ an HTTP authentication scheme are used together, there is no binding between
+ the two security mechanisms, and therefore no proof that the TLS client and server
+ are the same as the HTTP authentication client and server.
+
+.. _tls_config:
+
+Building Kea with TLS/HTTPS Support
+-----------------------------------
+
+TLS/HTTPS support is available with either the OpenSSL or the Botan
+cryptographic library. There are some constraints on the Boost library
+that must be used:
+
+- OpenSSL versions older than 1.0.2 are obsolete and should not be used.
+ Kea TLS support has not been tested with and is not supported on these versions.
+
+- OpenSSL version 1.0.2 has extended support, but only for OpenSSL premium
+ customers. Kea TLS support has been tested but is not supported on this version.
+
+- OpenSSL versions 1.1.x and later have been tested and are supported. Many
+ recent operating system versions include TLS 1.3 support.
+
+- OpenSSL 3.x has been released and Kea will build with it.
+
+- LibreSSL 3.2.4 has been tested. LibreSSL shares the OpenSSL 1.0.2 API, so
+ it should work, but is not supported.
+
+- Botan 1.x versions are obsolete and should not be used.
+ Kea TLS support has not been tested and is not supported with these versions.
+
+- Botan versions 2.14.0 and later have been tested and are supported. Kea TLS
+ support requires the four Asio header files which are included in Botan
+ packages and which are installed only if Botan is configured with the
+ ``--with-boost`` option.
+
+ Many packages provided by operating systems, such as Ubuntu 20.10,
+ do not build Botan with Boost support, making those packages
+ unusable for Kea with TLS.
+
+ It is still possible to take these files from the corresponding
+ Botan distribution and install them manually in the Botan include
+ directory, but this should be a last-resort procedure.
+
+ Without these header files, or with a Botan version prior
+ to 2.14.0, Kea can still build, but the TLS/HTTPS support is disabled;
+ any attempt to use it will fail with a fatal error.
+
+- Very old Boost versions provide SSL support (based on OpenSSL)
+ without offering a choice of the TLS version; Kea can still use them,
+ but they are not recommended.
+
+- Boost versions prior to 1.64 provide SSL support with a fixed
+ choice of the TLS version; Kea enforces the use of TLS 1.2 with them.
+
+- Boost versions 1.64 or newer provide SSL support with a generic
+ TLS version; the best (highest) version available on both peers is
+ selected.
+
+TLS/HTTPS Configuration
+-----------------------
+
+The TLS configuration parameters are:
+
+- ``trust-anchor`` - this string parameter specifies the name of a file
+ or directory where the certification authority (CA) certificate of
+ the other peer can be found. With OpenSSL, the directory must include
+ hash symbolic links. With Botan, the directory is recursively
+ searched for certificates.
+
+- ``cert-file`` - this string parameter specifies the name of the file
+ containing the end-entity certificate of the Kea instance
+ being configured.
+
+- ``key-file`` - this string parameter specifies the private key of the
+ end-entity certificate of the Kea instance being configured.
+ The file must not be encrypted; it is highly recommended to
+ restrict its access.
+
+The three string parameters must be either all unspecified (TLS disabled)
+or all specified (TLS enabled).
+
+TLS is asymmetric: the authentication of the server by the client is
+mandatory but the authentication of the client by the server is optional.
+In TLS terms, this means the server may require the client certificate, or
+may not; there is a server-specific TLS parameter.
+
+- ``cert-required`` - this boolean parameter allows a server to not
+ require the client certificate. Its default value is ``true``, which
+ means the client certificate is required and the
+ client must be authenticated. This flag has no meaning on the client side; the server
+ always provides a certificate which is validated by the client.
+
+Objects in files must be in the PEM format. Files can contain more
+than one certificate, but this has not been tested and is not supported.
+
+Botan requires CA certificates to have the standard CA certificate
+attributes, verifies that end-entity certificates are version 3
+certificates (as required by the TLS standard), and supports only PKCS 8
+files for the private key.
+
+.. note::
+
+ Some cryptographic libraries (e.g. Botan and recent OpenSSL) enforce
+ minimal strength (i.e. key length), e.g. at least 2048 for RSA.
+
+A sample set of certificates and associated objects is available at
+``src/lib/asiolink/testutils/ca`` in the Kea sources, with a ``doc.txt`` file
+explaining how they were generated using the ``openssl`` command. These
+files are for testing purposes only. **Do not use them in production.**
+
+TLS handshake, the phase where the cryptographic parameters are exchanged
+and authentication is verified, can fail in multiple ways. Error messages
+often do not help to pinpoint the source of the problem.
+Both OpenSSL and Botan provide a command-line tool with a ``verify`` command
+which can be used to understand and fix handshake issues.
+
+OpenSSL Tuning
+--------------
+
+Kea accepts the default OpenSSL configuration parameters, but administrators can
+also fine-tune the OpenSSL settings. For example, it may be desirable to limit
+the TLS version.
+
+The default OpenSSL configuration file is named ``openssl.cnf``. It can
+be found in a system-dependent ``etc`` directory, and the location can be overridden
+using the ``OPENSSL_CONF`` environment variable. For OpenSSL versions greater than
+1.0.2, the minimum acceptable protocol can be set via the ``MinProtocol`` variable.
+
+For these examples, we assume that no variables are already set and no sections already
+exist; it is, of course, possible to reuse existing variables and sections.
+
+In the default application, ``openssl_conf``, the corresponding variable
+must be set to the name of the section that handles defaults: in this example,
+``default_conf``. If ``openssl_conf`` is not yet set, add this command
+at the beginning of the OpenSSL configuration file (before the first
+section):
+
+.. code-block:: ini
+
+ openssl_conf = default_conf
+
+In the ``default_conf`` section, the ``ssl_conf`` variable must be set
+to the name of the section that handles SSL/TLS defaults: in this
+example, ``ssl_sect``.
+
+.. code-block:: ini
+
+ [ default_conf ]
+ ssl_conf = ssl_sect
+
+In the ``ssl_sect`` section, the ``system_default`` variable must be
+set to the name of the section that handles system defaults: in
+this example, ``system_default_sect``.
+
+.. code-block:: ini
+
+ [ ssl_sect ]
+ system_default = system_default_sect
+
+In the ``system_default_sect`` section, the ``MinProtocol`` variable must be
+set to the desired minimal SSL/TLS version: in this example, ``TLSv1.2``.
+
+.. code-block:: ini
+
+ [ system_default_sect ]
+ MinProtocol = TLSv1.2
+
+The same steps can be used to enforce other crypto parameters if
+desired.
+
+It is highly recommended to read the ``openssl.cnf`` manual page,
+normally called ``config.5ssl`` and displayed using ``man config``.
+
+Securing a Kea Deployment
+=========================
+
+Below is a list of considerations for administrators wishing to improve Kea's
+security. In many cases, there are trade-offs between convenience and security.
+
+Component-Based Design
+----------------------
+
+The Kea architecture is modular, with separate daemons for separate tasks.
+A Kea deployment may include DHCPv4, DHCPv6, and Dynamic DNS daemons; a Control Agent
+daemon run on each application server; the ``kea-lfc utility`` for doing periodic lease
+file cleanup; MySQL and or PostgreSQL databases, run either locally on the application
+servers or accessed over the internal network; and a Stork monitoring system.
+This modular architecture allows the administrator to minimize the attack surface
+by minimizing the code that is loaded and running.
+For example, :iscman:`kea-dhcp-ddns` should not be run unless DNS updates are required.
+Similarly, :iscman:`kea-lfc` is never triggered (and can be safely removed or never installed) if memfile is not used.
+Potential Kea security issues can be minimized by running only those processes required in the local environment.
+
+Limiting Application Permissions
+--------------------------------
+
+The DHCPv4 and DHCPv6 protocols assume the server opens privileged UDP port 67
+(DHCPv4) or 547 (DHCPv6), which requires root access under normal circumstances. However, via the
+capabilities mechanism on Linux systems, Kea can run from an unprivileged account. See
+:ref:`non-root` for details on how to run Kea without root access.
+
+The Control Agent (CA) can accept incoming HTTP or HTTPS connections. The default port is 8000, which
+does not require privileged access.
+
+Securing Kea Administrative Access
+----------------------------------
+
+The three primary Kea daemons (:iscman:`kea-dhcp4`, :iscman:`kea-dhcp6` and :iscman:`kea-dhcp-ddns`) all support a control
+channel, which is implemented as a UNIX socket. The control channel, which opens a UNIX socket, is disabled by default;
+however, many configuration examples have it enabled, as it is a very popular feature. To
+read from or write to this socket, root access is generally required, although if Kea is configured
+to run as non-root, the owner of the process can write to it. Access can be controlled using normal
+file-access control on POSIX systems (owner, group, others, read/write).
+
+Kea configuration is controlled by a JSON file on the Kea server. This file can be viewed or edited
+by anyone with file permissions (which are controlled by the operating system). Note that
+passwords are stored in clear text in the configuration file, so anyone with access to read the
+configuration file can find this information. As a practical matter, anyone with permission to edit
+the configuration file has control over Kea.
+Limiting user permission to read or write the Kea configuration file is an important security step.
+
+Securing Database Connections
+-----------------------------
+
+Kea can use an external MySQL or PostgreSQL database to store configuration, host reservations,
+or/and leases, or/and for forensic logging. The use of databases is a popular feature, but it is optional;
+it is also possible to store data in a flat file on disk.
+
+When using a database, Kea stores and uses the following credentials to authenticate with the database:
+username, password, host, port, and database name. **These are stored in clear text
+in the configuration file.**
+
+Depending on the database configuration, it is also possible to verify whether the system user matches the
+database username. Consult the MySQL or PostgreSQL manual for details.
+
+Information Leakage Through Logging
+-----------------------------------
+
+It is possible for Kea to log an entire configuration file, including passwords and secrets.
+Since Kea 1.9.7, this issue has been resolved by replacing the value of all entries ending in
+``password`` or ``secret`` with asterisks, as was already done for database logs.
+
+Logs are sent to stdout, stderr, files, or syslog; system file permissions system apply to
+stdout/stderr and files. Syslog may export the logs over the network, exposing them further to possible snooping.
+
+Cryptography Components
+-----------------------
+
+Kea supports the use of either of two cryptographic libraries: Botan or OpenSSL.
+The choice is made at compile time, and creates both compile and runtime dependencies
+between the Kea and the selected library. While OpenSSL is the most popular choice for
+deployments, Botan remains a fully supported alternative.
+
+The primary use cases for the cryptographic libraries are:
+
+- TLS support for the Control Agent (CA), introduced in Kea 1.9.6.
+- TSIG signatures when sending DNS updates.
+- calculating DHCID records when sending DNS updates.
+- random number generation (but not for usage requiring a crypto grade generator).
+
+For OpenSSL and Botan, only the low-level crypto interface is used (e.g. libcrypto). Kea does not link
+with libssl. Some dependent software systems, such as database client libraries, can also depend on a crypto
+library.
+
+One way to limit exposure for potential OpenSSL or Botan vulnerabilities is not to use DDNS. The
+libraries would still be needed to build and run Kea, but the code would never be used, so any
+potential bugs in the libraries would not be exploitable.
+
+TSIG Signatures
+---------------
+
+Kea supports the following algorithms when signing DNS updates with TSIG signatures:
+
+- HMAC-MD5
+- HMAC-SHA1
+- HMAC-SHA224
+- HMAC-SHA256
+- HMAC-SHA384
+- HMAC-SHA512
+
+See :ref:`d2-tsig-key-list-config` for an up-to-date list.
+
+Kea uses SHA256 to calculate DHCID records. This is irrelevant from the cryptography perspective, as
+the DHCID record is only used to generate unique identifiers for two devices that may have been
+assigned the same IP address at different times.
+
+Raw Socket Support
+------------------
+
+In principle, Kea DHCPv4 uses raw sockets to receive traffic from clients. The difficulty is with
+receiving packets from devices that do not yet have an IPv4 address. When dealing with direct traffic
+(where both client and server are connected to the same link, not separated by relays), the kernel
+normally drops the packet as the source IP address is 0.0.0.0. Therefore, Kea needs to open raw
+sockets to be able to receive this traffic.
+
+However, this is not necessary if all the traffic is coming via relays, which is often the case in
+many networks. In that case normal UDP sockets can be used instead. There is a ``dhcp-socket-type``
+parameter that controls this behavior.
+
+The default is to permit raw socket usage, as it is more versatile.
+
+When using raw sockets, Kea is able to receive raw layer 2 packets, bypassing most firewalls
+(including iptables). This effectively means that when raw sockets are used, the iptables cannot be
+used to block DHCP traffic. This is a design choice of the Linux kernel.
+
+Kea can be switched to use UDP sockets. This is an option when all traffic is relayed.
+However, it does not work for directly connected devices. If Kea is limited to UDP sockets,
+iptables should work properly.
+
+If raw sockets are not required, disabling this access can improve security.
+
+Remote Administrative Access
+----------------------------
+
+Kea's Control Agent (CA) exposes a RESTful API over HTTP or HTTPS (HTTP over TLS). The CA is an
+optional feature that is disabled by default, but it is very popular. When enabled, it listens on the
+loopback address (127.0.0.1 or ::1) by default, unless configured otherwise. See :ref:`tls`
+for information about protecting the TLS traffic. Limiting the incoming connections with a firewall, such as
+iptables, is generally a good idea.
+
+Note that in High Availability (HA) deployments, DHCP partners connect to each other using a CA
+connection.
+
+Authentication for Kea's RESTful API
+------------------------------------
+
+Kea 1.9.0 added support for basic HTTP authentication (`RFC 7617 <https://tools.ietf.org/html/rfc7617>`_),
+to control access for incoming REST commands over HTTP. The credentials (username, password) are
+stored in a local Kea configuration file on disk. The username is logged with the API command, so it
+is possible to determine which authenticated user performed each command. The access control details
+are logged using a dedicated ``auth`` logger. Basic HTTP
+authentication is weak on its own as there are known dictionary attacks, but those attacks require
+a "man in the middle" to get access to the HTTP traffic. That can be eliminated by using basic HTTP
+authentication exclusively over TLS. In fact, if possible, using client certificates for TLS is better than
+using basic HTTP authentication.
+
+Kea 1.9.2 introduced a new ``auth`` hook point. With this new hook point, it is possible to develop an external
+hook library to extend the access controls, integrate with another authentication authority, or add role-based
+access control to the Control Agent.
+
+Kea Security Processes
+======================
+
+The following sections discuss how the Kea DHCP development team ensures code quality and handles vulnerabilities.
+
+Vulnerability Handling
+----------------------
+
+ISC is an experienced and active participant in the industry-standard vulnerability disclosure
+process and maintains accurate documentation on our process and vulnerabilities in ISC software.
+See https://kb.isc.org/docs/aa-00861 for ISC's Software Defect and Security Vulnerability Disclosure Policy.
+
+In case of a security vulnerability in Kea, ISC notifies support customers ahead of any public
+disclosure, and provides a patch and/or updated installer package to remediate the
+vulnerability.
+
+When a security update is published, both the source tarballs and the ISC-maintained packages are
+published on the same day. This enables users of the native Linux update mechanisms (such as
+Debian's and Ubuntu's apt or RedHat's dnf) to update their systems promptly.
+
+Code Quality and Testing
+------------------------
+
+Kea undergoes extensive tests during its development. The following are some of the
+processes that are used to ensure adequate code quality:
+
+- Each line of code goes through a formal review before it is accepted. The review process is
+ documented and available publicly.
+- Roughly 50% of the source code is dedicated to unit tests. As of December 2020, there were over 6000
+ unit tests and the number is increasing with time. Unit tests are required to commit any new feature.
+- There are around 1500 system tests for Kea. These simulate both correct and invalid
+ situations, covering network packets (mostly DHCP, but also DNS, HTTP, HTTPS and others),
+ command-line usage, API calls, database interactions, scripts, and more.
+- There are performance tests with over 80 scenarios that test Kea overall performance and
+ resiliency to various levels of traffic, and measuring various metrics (latency, leases per seconds,
+ packets per seconds, CPU usage, memory utilization, and others).
+- Kea uses Continuous Integration (CI). This means that the great majority of tests (all unit and system
+ tests, and in some cases also performance tests) are run for every commit. Many "lighter" tests are
+ run on branches, before the code is even accepted.
+- Many unit and system tests check for negative scenarios, such as incomplete,
+ broken, or truncated packets, API commands, and configuration files, as well as incorrect sequences (such as sending
+ packets in an invalid order) and more.
+- The Kea development team uses many tools that perform automatic code quality checks, such as danger, as well as
+ internally developed sanity checkers.
+- The Kea team uses the following static code analyzers: Coverity Scan, shellcheck, and danger.
+- The Kea team uses the following dynamic code analyzers: Valgrind and Thread Sanitizer (TSAN).
+
+Fuzz Testing
+------------
+
+The Kea team has a process for running fuzz testing, using `AFL <https://github.com/google/AFL>`_. There
+are two modes which are run: the first mode fuzzes incoming packets, effectively throwing millions of mostly
+broken packets at Kea per day, while the second mode fuzzes configuration structures and forces Kea to
+attempt to load them. Kea has been fuzzed since around 2018 in both modes. The input seeds
+(the data being used to generate or "fuzz" other input) are changed periodically.
+
+Release Integrity
+-----------------
+
+All ISC software releases are signed with PGP and distributed via the ISC website, which is itself
+DNSSEC-signed, so users can be confident the software has not been tampered with.
+
+Bus Factor
+----------
+
+According to the `Core Infrastructure project <https://bestpractices.coreinfrastructure.org/>`_, a "bus
+factor" or "truck factor" is the minimum number of project members that have to suddenly disappear
+from a project ("be hit by a bus") before the project stalls due to lack of knowledgeable or competent
+personnel. It is hard to estimate precisely, but the bus factor for Kea is somewhere around five. As of
+2021, there are six core developers and two quality assurance engineers, with many additional casual
+contributors (product manager, support team, IT, etc.). The team is geographically dispersed.
diff --git a/doc/sphinx/arm/shell.rst b/doc/sphinx/arm/shell.rst
new file mode 100644
index 0000000..62a9900
--- /dev/null
+++ b/doc/sphinx/arm/shell.rst
@@ -0,0 +1,165 @@
+.. _kea-shell:
+
+*************
+The Kea Shell
+*************
+
+.. _shell-overview:
+
+Overview of the Kea Shell
+=========================
+
+The Kea Control Agent (CA, see
+:ref:`kea-ctrl-agent`) provides a RESTful control interface
+over HTTP. That API is typically expected to be used by various IPAMs
+and similar management systems. Nevertheless, there may be cases when an
+administrator wants to send a command to the CA directly, and the Kea shell
+provides a way to do this. It is a simple command-line,
+scripting-friendly, text client that is able to connect to the CA, send
+it commands with parameters, retrieve the responses, and display them.
+
+As the primary purpose of the Kea shell is as a tool in a scripting
+environment, it is not interactive. However, by following simple guidelines it can
+be run manually.
+
+Kea 1.9.0 introduced basic HTTP authentication support.
+
+Shell Usage
+===========
+
+:iscman:`kea-shell` is run as follows:
+
+.. code-block:: console
+
+ $ kea-shell [--host hostname] [--port number] [--path path] [--auth-user] [--auth-password] [--timeout seconds] [--service service-name] [command]
+
+where:
+
+- ``--host hostname`` specifies the hostname of the CA. If not
+ specified, "localhost" is used.
+
+- ``--port number`` specifies the TCP port on which the CA listens. If
+ not specified, 8000 is used.
+
+- ``--path path`` specifies the path in the URL to connect to. If not
+ specified, an empty path is used. As the CA listens at the empty
+ path, this parameter is useful only with a reverse proxy.
+
+- ``--auth-user`` specifies the user ID for basic HTTP authentication.
+ If not specified or specified as the empty string, authentication is
+ not used.
+
+- ``--auth-password`` specifies the password for basic HTTP authentication.
+ If not specified but the user ID is specified, an empty password is used.
+
+- ``--timeout seconds`` specifies the timeout (in seconds) for the
+ connection. If not given, 10 seconds is used.
+
+- ``--service service-name`` specifies the target of a command. If not
+ given, the CA is used as the target. This may be used more than once
+ to specify multiple targets.
+
+- ``command`` specifies the command to be sent. If not specified, the
+ :isccmd:`list-commands` command is used.
+
+Other switches are:
+
+- ``-h`` - prints a help message.
+
+- ``-v`` - prints the software version.
+
+See :ref:`shell-tls` for new command-line arguments associated with TLS/HTTPS support.
+
+Once started, the shell reads the parameters for the command from standard
+input, which are expected to be in JSON format. When all have been read,
+the shell establishes a connection with the CA using HTTP, sends the
+command, and awaits a response. Once that is received, it is displayed
+on standard output.
+
+For a list of available commands, see :ref:`ctrl-channel`;
+additional commands may be provided by hook libraries. For a list of
+all supported commands from the CA, use the :isccmd:`list-commands` command.
+
+The following shows a simple example of usage:
+
+.. code-block:: console
+
+ $ kea-shell --host 192.0.2.1 --port 8001 --service dhcp4 list-commands
+ ^D
+
+After the command line is entered, the program waits for command
+parameters to be entered. Since :isccmd:`list-commands` does not take any
+arguments, Ctrl-D (represented in the above example by "^D")
+indicates end-of-file and terminates the parameter input. The shell
+then contacts the CA and prints out the list of available commands
+returned for the service named ``dhcp4``.
+
+The Kea shell will likely be most frequently used in
+scripts; the next example shows a simple scripted execution. It sends
+the command :isccmd:`config-write` to the CA (the ``--service`` parameter has not
+been used), along with the parameters specified in param.json. The
+result will be stored in result.json.
+
+.. code-block:: console
+
+ $ cat param.json
+ "filename": "my-config-file.json"
+ $ cat param.json | kea-shell --host 192.0.2.1 config-write > result.json
+
+When a reverse proxy is used to de-multiplex requests to different
+servers, the default empty path in the URL is not enough, so the
+``--path`` parameter should be used. For instance, if requests to the
+"/kea" path are forwarded to the CA this can be used:
+
+.. code-block:: console
+
+ $ kea-shell --host 192.0.2.1 --port 8001 --path kea ...
+
+The Kea shell requires Python to be installed on the system. It has been
+tested with various versions of Python 3, up to 3.5.
+Since not every Kea deployment uses this feature and there are
+deployments that do not have Python, the Kea shell is not enabled by
+default. To use it, specify ``--enable-shell`` when running ``configure``
+during the installation of Kea. When building on Debian systems,
+``--with-site-packages=...`` may also be useful.
+
+.. note::
+
+ From Kea 2.4.0 version, the :iscman:`kea-shell` no longer supports Python 2.7.
+
+The Kea shell is intended to serve more as a demonstration of the
+RESTful interface's capabilities (and, perhaps, an illustration for
+people interested in integrating their management environments with Kea)
+than as a serious management client. It is not likely to be
+significantly expanded in the future; it is, and will remain, a simple
+tool.
+
+.. note::
+
+ When using this tool with basic HTTP authentication, please keep in
+ mind that command-line arguments are not hidden from local users.
+
+.. _shell-tls:
+
+TLS Support
+===========
+
+Since Kea 1.9.6, :iscman:`kea-shell` supports HTTPS connections. The TLS/HTTPS
+support requires Python 3. The additional command-line arguments are:
+
+- ``--ca`` specifies the file or directory name of the Certification
+ Authority. If not specified, HTTPS is not used.
+
+- ``--cert`` specifies the file name of the user end-entity public key
+ certificate. If specified, the file name of the user key must also be specified.
+
+- ``--key`` specifies the file name of the user key file. If specified,
+ the file name of the user certificate must also be specified.
+ Encrypted key files are not supported.
+
+For example, a basic HTTPS request to get a list of commands could
+look like this:
+
+.. code-block:: console
+
+ $ kea-shell --host 127.0.0.1 --port 8000 --ca ./kea-ca.crt list-commands
diff --git a/doc/sphinx/arm/stats.rst b/doc/sphinx/arm/stats.rst
new file mode 100644
index 0000000..b37b37a
--- /dev/null
+++ b/doc/sphinx/arm/stats.rst
@@ -0,0 +1,1043 @@
+.. _stats:
+
+**********
+Statistics
+**********
+
+Statistics Overview
+===================
+
+Both Kea DHCP servers support statistics gathering. A working DHCP
+server encounters various events that can cause certain statistics to be
+collected. For example, a DHCPv4 server may receive a packet
+(the ``pkt4-received`` statistic increases by one) that after parsing is
+identified as a DHCPDISCOVER (``pkt4-discover-received``). The server
+processes it and decides to send a DHCPOFFER representing its answer
+(the ``pkt4-offer-sent`` and ``pkt4-sent statistics`` increase by one). Such
+events happen frequently, so it is not uncommon for the statistics to have
+values in the high thousands. They can serve as an easy and powerful
+tool for observing a server's and a network's health. For example, if
+the ``pkt4-received`` statistic stops growing, it means that the clients'
+packets are not reaching the server.
+
+There are four types of statistics:
+
+- *integer* - this is the most common type. It is implemented as a
+ 64-bit integer (int64_t in C++), so it can hold any value between
+ -2^63 to 2^63-1.
+
+- *big integer* - this type is inteded for holding large numbers. It is
+ implemented as a 128-bit integer (boost::multiprecision::int128_t in C++), so
+ it can hold any value between -2^127 to 2^127-1.
+
+- *floating point* - this type is intended to store floating-point
+ precision. It is implemented as a C++ double type.
+
+- *duration* - this type is intended for recording time periods. It
+ uses the \`boost::posix_time::time_duration type, which stores hours,
+ minutes, seconds, and microseconds.
+
+- *string* - this type is intended for recording statistics in text
+ form. It uses the C++ std::string type.
+
+During normal operation, the DHCPv4 and DHCPv6 servers gather
+statistics. For a list of DHCPv4 and DHCPv6 statistics, see
+:ref:`dhcp4-stats` and :ref:`dhcp6-stats`, respectively.
+
+To extract data from the statistics module, the control channel can be
+used. See :ref:`ctrl-channel` for details. It is possible to
+retrieve a single statistic or all statistics, reset the statistics (i.e.
+set them to a neutral value, typically zero), or even completely remove a
+single statistic or all statistics. See the section :ref:`command-stats`
+for a list of statistics-oriented commands.
+
+Statistics can be used by external tools to monitor Kea. One example of such a tool is Stork.
+See :ref:`stork` for details on how to use it and other data sources to retrieve statistics periodically
+to get better insight into Kea's health and operational status.
+
+.. _stats-lifecycle:
+
+Statistics Lifecycle
+====================
+
+All of the statistics supported by Kea's servers are initialized upon the servers' startup
+and are returned in response to the commands such as
+:isccmd:`statistic-get-all`. The runtime statistics concerning DHCP packets
+processed are initially set to 0 and are reset upon the server
+restart.
+
+Per-subnet statistics are recalculated when reconfiguration takes place.
+
+In general, once a statistic is initialized it is held in the manager until
+explicitly removed, via :isccmd:`statistic-remove` or
+:isccmd:`statistic-remove-all`,
+or when the server is shut down.
+
+Removing a statistic that is updated frequently makes little sense, as
+it will be re-added when the server code next records that statistic.
+The :isccmd:`statistic-remove` and
+:isccmd:`statistic-remove-all` commands are
+intended to remove statistics that are not expected to be observed in
+the near future. For example, a misconfigured device in a network may
+cause clients to report duplicate addresses, so the server will report
+increasing values of ``pkt4-decline-received``. Once the problem is found
+and the device is removed, the system administrator may want to remove
+the ``pkt4-decline-received`` statistic so that it is no longer reported, until
+and unless a duplicate address is again detected.
+
+.. isccmd:: stats
+.. _command-stats:
+
+Commands for Manipulating Statistics
+====================================
+
+There are several commands defined that can be used for accessing
+(``-get``), resetting to zero or a neutral value (``-reset``), or removing a
+statistic completely (``-remove``). The statistics time-based
+limit (``-sample-age-set``) and size-based limit (``-sample-count-set``), which
+control how long or how many samples of a given statistic are retained, can also
+be changed.
+
+The difference between ``-reset`` and ``-remove`` is somewhat subtle.
+The ``-reset`` command sets the value of the statistic to zero or a neutral value,
+so that after this operation, the statistic has a value of 0 (integer),
+0.0 (float), 0h0m0s0us (duration), or "" (string).
+When requested, a statistic with the values mentioned is returned.
+``-remove`` removes a statistic completely, so the statistic is no longer
+reported. However, the server code may add it back if there is a reason
+to record it.
+
+.. note::
+
+ The following sections describe commands that can be sent to the
+ server; the examples are not fragments of a configuration file. For
+ more information on sending commands to Kea, see
+ :ref:`ctrl-channel`.
+
+.. isccmd:: statistic-get
+.. _command-statistic-get:
+
+The ``statistic-get`` Command
+-----------------------------
+
+The :isccmd:`statistic-get` command retrieves a single statistic. It takes a
+single-string parameter called ``name``, which specifies the statistic
+name. An example command may look like this:
+
+::
+
+ {
+ "command": "statistic-get",
+ "arguments": {
+ "name": "pkt4-received"
+ }
+ }
+
+The server returns details of the requested statistic, with a result of
+0 indicating success and the specified statistic as the value of the
+``arguments`` parameter. If the requested statistic is not found, the
+response contains an empty map, i.e. only { } as an argument, but
+the status code still indicates success (0).
+
+Here is an example response:
+
+::
+
+ {
+ "command": "statistic-get",
+ "arguments": {
+ "pkt4-received": [ [ 125, "2019-07-30 10:11:19.498739" ], [ 100, "2019-07-30 10:11:19.498662" ] ]
+ },
+ "result": 0
+ }
+
+.. isccmd:: statistic-reset
+.. _command-statistic-reset:
+
+The ``statistic-reset`` Command
+-------------------------------
+
+The :isccmd:`statistic-reset` command sets the specified statistic to its
+neutral value: 0 for integer, 0.0 for float, 0h0m0s0us for time
+duration, and "" for string type. It takes a single-string parameter
+called ``name``, which specifies the statistic name. An example command
+may look like this:
+
+::
+
+ {
+ "command": "statistic-reset",
+ "arguments": {
+ "name": "pkt4-received"
+ }
+ }
+
+If the specific statistic is found and the reset is successful, the
+server responds with a status of 0, indicating success, and an empty
+parameters field. If an error is encountered (e.g. the requested
+statistic was not found), the server returns a status code of 1 (error)
+and the text field contains the error description.
+
+.. isccmd:: statistic-remove
+.. _command-statistic-remove:
+
+The ``statistic-remove`` Command
+--------------------------------
+
+The :isccmd:`statistic-remove` command deletes a single statistic. It
+takes a single-string parameter called ``name``, which specifies the
+statistic name. An example command may look like this:
+
+::
+
+ {
+ "command": "statistic-remove",
+ "arguments": {
+ "name": "pkt4-received"
+ }
+ }
+
+If the specific statistic is found and its removal is successful, the
+server responds with a status of 0, indicating success, and an empty
+parameters field. If an error is encountered (e.g. the requested
+statistic was not found), the server returns a status code of 1 (error)
+and the text field contains the error description.
+
+.. isccmd:: statistic-get-all
+.. _command-statistic-get-all:
+
+The ``statistic-get-all`` Command
+---------------------------------
+
+The :isccmd:`statistic-get-all` command retrieves all statistics recorded. An
+example command may look like this:
+
+::
+
+ {
+ "command": "statistic-get-all",
+ "arguments": { }
+ }
+
+The server responds with details of all recorded statistics, with a
+result set to 0 to indicate that it iterated over all statistics (even
+when the total number of statistics is zero).
+
+Here is an example response returning all collected statistics:
+
+::
+
+ {
+ "command": "statistic-get-all",
+ "arguments": {
+ "cumulative-assigned-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836166"
+ ]
+ ],
+ "declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836156"
+ ]
+ ],
+ "pkt4-ack-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616247"
+ ]
+ ],
+ "pkt4-ack-sent": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616290"
+ ]
+ ],
+ "pkt4-decline-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616296"
+ ]
+ ],
+ "pkt4-discover-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616303"
+ ]
+ ],
+ "pkt4-inform-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616308"
+ ]
+ ],
+ "pkt4-nak-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616312"
+ ]
+ ],
+ "pkt4-nak-sent": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616314"
+ ]
+ ],
+ "pkt4-offer-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616318"
+ ]
+ ],
+ "pkt4-offer-sent": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616323"
+ ]
+ ],
+ "pkt4-parse-failed": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616326"
+ ]
+ ],
+ "pkt4-receive-drop": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616330"
+ ]
+ ],
+ "pkt4-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616335"
+ ]
+ ],
+ "pkt4-release-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616339"
+ ]
+ ],
+ "pkt4-request-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616343"
+ ]
+ ],
+ "pkt4-sent": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616348"
+ ]
+ ],
+ "pkt4-unknown-received": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616354"
+ ]
+ ],
+ "reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836159"
+ ]
+ ],
+ "reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836163"
+ ]
+ ],
+ "subnet[1].assigned-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836173"
+ ]
+ ],
+ "subnet[1].cumulative-assigned-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836098"
+ ]
+ ],
+ "subnet[1].declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836178"
+ ]
+ ],
+ "subnet[1].pool[0].assigned-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836205"
+ ]
+ ],
+ "subnet[1].pool[0].cumulative-assigned-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836137"
+ ]
+ ],
+ "subnet[1].pool[0].declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836213"
+ ]
+ ],
+ "subnet[1].pool[0].reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836225"
+ ]
+ ],
+ "subnet[1].pool[0].reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836236"
+ ]
+ ],
+ "subnet[1].pool[0].total-addresses": [
+ [
+ 11010049,
+ "2023-06-13 20:42:46.836128"
+ ]
+ ],
+ "subnet[1].reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836186"
+ ]
+ ],
+ "subnet[1].reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836194"
+ ]
+ ],
+ "subnet[1].total-addresses": [
+ [
+ 11010049,
+ "2023-06-13 20:42:46.836083"
+ ]
+ ],
+ "subnet[1].v4-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836105"
+ ]
+ ],
+ "subnet[1].v4-reservation-conflicts": [
+ [
+ 0,
+ "2023-06-13 20:42:46.836111"
+ ]
+ ],
+ "v4-allocation-fail": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616358"
+ ]
+ ],
+ "v4-allocation-fail-classes": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616363"
+ ]
+ ],
+ "v4-allocation-fail-no-pools": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616368"
+ ]
+ ],
+ "v4-allocation-fail-shared-network": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616372"
+ ]
+ ],
+ "v4-allocation-fail-subnet": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616376"
+ ]
+ ],
+ "v4-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616410"
+ ]
+ ],
+ "v4-reservation-conflicts": [
+ [
+ 0,
+ "2023-06-13 20:42:46.616412"
+ ]
+ ]
+ },
+ "result": 0
+ }
+
+or
+
+::
+
+ {
+ "command": "statistic-get-all",
+ "arguments": {
+ "cumulative-assigned-nas": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196757"
+ ]
+ ],
+ "cumulative-assigned-pds": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196758"
+ ]
+ ],
+ "declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196754"
+ ]
+ ],
+ "pkt6-advertise-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177731"
+ ]
+ ],
+ "pkt6-advertise-sent": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177739"
+ ]
+ ],
+ "pkt6-decline-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177739"
+ ]
+ ],
+ "pkt6-dhcpv4-query-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177740"
+ ]
+ ],
+ "pkt6-dhcpv4-response-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177740"
+ ]
+ ],
+ "pkt6-dhcpv4-response-sent": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177741"
+ ]
+ ],
+ "pkt6-infrequest-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177742"
+ ]
+ ],
+ "pkt6-parse-failed": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177742"
+ ]
+ ],
+ "pkt6-rebind-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177743"
+ ]
+ ],
+ "pkt6-receive-drop": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177743"
+ ]
+ ],
+ "pkt6-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177744"
+ ]
+ ],
+ "pkt6-release-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177744"
+ ]
+ ],
+ "pkt6-renew-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177745"
+ ]
+ ],
+ "pkt6-reply-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177745"
+ ]
+ ],
+ "pkt6-reply-sent": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177746"
+ ]
+ ],
+ "pkt6-request-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177747"
+ ]
+ ],
+ "pkt6-sent": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177747"
+ ]
+ ],
+ "pkt6-solicit-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177748"
+ ]
+ ],
+ "pkt6-unknown-received": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177748"
+ ]
+ ],
+ "reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196755"
+ ]
+ ],
+ "reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196756"
+ ]
+ ],
+ "subnet[1].assigned-nas": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196760"
+ ]
+ ],
+ "subnet[1].assigned-pds": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196761"
+ ]
+ ],
+ "subnet[1].cumulative-assigned-nas": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196727"
+ ]
+ ],
+ "subnet[1].cumulative-assigned-pds": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196729"
+ ]
+ ],
+ "subnet[1].declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196763"
+ ]
+ ],
+ "subnet[1].pd-pool[0].assigned-pds": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196785"
+ ]
+ ],
+ "subnet[1].pd-pool[0].cumulative-assigned-pds": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196744"
+ ]
+ ],
+ "subnet[1].pd-pool[0].reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196789"
+ ]
+ ],
+ "subnet[1].pd-pool[0].total-pds": [
+ [
+ 256,
+ "2023-06-13 21:28:57.196741"
+ ]
+ ],
+ "subnet[1].pool[0].assigned-nas": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196773"
+ ]
+ ],
+ "subnet[1].pool[0].cumulative-assigned-nas": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196739"
+ ]
+ ],
+ "subnet[1].pool[0].declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196775"
+ ]
+ ],
+ "subnet[1].pool[0].reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196779"
+ ]
+ ],
+ "subnet[1].pool[0].reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196783"
+ ]
+ ],
+ "subnet[1].pool[0].total-nas": [
+ [
+ 281474976710656,
+ "2023-06-13 21:28:57.196736"
+ ]
+ ],
+ "subnet[1].reclaimed-declined-addresses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196766"
+ ]
+ ],
+ "subnet[1].reclaimed-leases": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196770"
+ ]
+ ],
+ "subnet[1].total-nas": [
+ [
+ 281474976710656,
+ "2023-06-13 21:28:57.196720"
+ ]
+ ],
+ "subnet[1].total-pds": [
+ [
+ 256,
+ "2023-06-13 21:28:57.196724"
+ ]
+ ],
+ "subnet[1].v6-ia-na-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196731"
+ ]
+ ],
+ "subnet[1].v6-ia-pd-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.196733"
+ ]
+ ],
+ "v6-allocation-fail": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177749"
+ ]
+ ],
+ "v6-allocation-fail-classes": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177755"
+ ]
+ ],
+ "v6-allocation-fail-no-pools": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177756"
+ ]
+ ],
+ "v6-allocation-fail-shared-network": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177756"
+ ]
+ ],
+ "v6-allocation-fail-subnet": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177757"
+ ]
+ ],
+ "v6-ia-na-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177757"
+ ]
+ ],
+ "v6-ia-pd-lease-reuses": [
+ [
+ 0,
+ "2023-06-13 21:28:57.177758"
+ ]
+ ]
+ },
+ "result": 0
+ }
+
+or
+
+::
+
+ {
+ "command": "statistic-get-all",
+ "arguments": {
+ "ncr-error": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627751"
+ ]
+ ],
+ "ncr-invalid": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627749"
+ ]
+ ],
+ "ncr-received": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627737"
+ ]
+ ],
+ "update-error": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627759"
+ ]
+ ],
+ "update-sent": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627752"
+ ]
+ ],
+ "update-signed": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627753"
+ ]
+ ],
+ "update-success": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627755"
+ ]
+ ],
+ "update-timeout": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627757"
+ ]
+ ],
+ "update-unsigned": [
+ [
+ 0,
+ "2023-06-13 21:42:54.627754"
+ ]
+ ]
+ },
+ "result": 0
+ }
+
+.. isccmd:: statistic-reset-all
+.. _command-statistic-reset-all:
+
+The ``statistic-reset-all`` Command
+-----------------------------------
+
+The :isccmd:`statistic-reset` command sets all statistics to their neutral
+values: 0 for integer, 0.0 for float, 0h0m0s0us for time duration, and
+"" for string type. An example command may look like this:
+
+::
+
+ {
+ "command": "statistic-reset-all",
+ "arguments": { }
+ }
+
+If the operation is successful, the server responds with a status of 0,
+indicating success, and an empty parameters field. If an error is
+encountered, the server returns a status code of 1 (error) and the text
+field contains the error description.
+
+.. isccmd:: statistic-remove-all
+.. _command-statistic-remove-all:
+
+The ``statistic-remove-all`` Command
+------------------------------------
+
+The :isccmd:`statistic-remove-all` command attempts to delete all statistics. An
+example command may look like this:
+
+::
+
+ {
+ "command": "statistic-remove-all",
+ "arguments": { }
+ }
+
+If the removal of all statistics is successful, the server responds with
+a status of 0, indicating success, and an empty parameters field. If an
+error is encountered, the server returns a status code of 1 (error) and
+the text field contains the error description.
+
+.. isccmd:: statistic-sample-age-set
+.. _command-statistic-sample-age-set:
+
+The ``statistic-sample-age-set`` Command
+----------------------------------------
+
+The :isccmd:`statistic-sample-age-set` command sets a time-based limit
+on samples for a given statistic. It takes two parameters: a string
+called ``name``, which specifies the statistic name, and an integer value called
+``duration``, which specifies the time limit for the given statistic in seconds.
+An example command may look like this:
+
+::
+
+ {
+ "command": "statistic-sample-age-set",
+ "arguments": {
+ "name": "pkt4-received",
+ "duration": 1245
+ }
+
+ }
+
+If the command is successful, the server responds with a status of
+0, indicating success,
+and an empty parameters field. If an error is encountered (e.g. the
+requested statistic was not found), the server returns a status code
+of 1 (error) and the text field contains the error description.
+
+.. isccmd:: statistic-sample-age-set-all
+.. _command-statistic-sample-age-set-all:
+
+The ``statistic-sample-age-set-all`` Command
+--------------------------------------------
+
+The :isccmd:`statistic-sample-age-set-all` command sets time-based limits
+on samples for all statistics. It takes a single-integer parameter
+called ``duration``, which specifies the time limit for the statistic
+in seconds. An example command may look like this:
+
+::
+
+ {
+ "command": "statistic-sample-age-set-all",
+ "arguments": {
+ "duration": 1245
+ }
+
+ }
+
+If the command is successful, the server responds with a status of
+0, indicating success,
+and an empty parameters field. If an error is encountered, the server returns
+a status code of 1 (error) and the text field contains the error description.
+
+.. isccmd:: statistic-sample-count-set
+.. _command-statistic-sample-count-set:
+
+The ``statistic-sample-count-set`` Command
+------------------------------------------
+
+The :isccmd:`statistic-sample-count-set` command sets a size-based limit
+on samples for a given statistic. An example command may look
+like this:
+
+::
+
+ {
+ "command": "statistic-sample-count-set",
+ "arguments": {
+ "name": "pkt4-received",
+ "max-samples": 100
+ }
+
+ }
+
+If the command is successful, the server responds with a status of
+0, indicating success,
+and an empty parameters field. If an error is encountered (e.g. the
+requested statistic was not found), the server returns a status code
+of 1 (error) and the text field contains the error description.
+
+.. isccmd:: statistic-sample-count-set-all
+.. _command-statistic-sample-count-set-all:
+
+The ``statistic-sample-count-set-all`` Command
+----------------------------------------------
+
+The :isccmd:`statistic-sample-count-set-all` command sets size-based limits
+on samples for all statistics. An example command may look
+like this:
+
+::
+
+ {
+ "command": "statistic-sample-count-set-all",
+ "arguments": {
+ "max-samples": 100
+ }
+
+ }
+
+If the command is successful, the server responds with a status of
+0, indicating success,
+and an empty parameters field. If an error is encountered, the server returns
+a status code of 1 (error) and the text field contains the error description.
+
+.. _time-series:
+
+Time Series
+===========
+
+With certain statistics, a single isolated data point may be useful. However,
+some statistics, such as received
+packet size, packet processing time, or number of database queries needed to
+process a packet, are not cumulative and it is useful to keep many data
+points, perhaps to do some statistical analysis afterwards.
+
+
+Each Kea statistic holds 20 data points; setting such
+a limit prevents unlimited memory growth.
+There are two ways to define the limits: time-based (e.g. keep samples from
+the last 5 minutes) and size-based. The size-based
+limit can be changed using one of two commands: :isccmd:`statistic-sample-count-set`,
+to set a size limit for a single statistic, and :isccmd:`statistic-sample-count-set-all`,
+to set size-based limits for all statistics. To set time-based
+limits for a single statistic, use :isccmd:`statistic-sample-age-set`; use
+:isccmd:`statistic-sample-age-set-all` to set time-based limits for all statistics.
+For a given statistic only one type of limit can be active; storage
+is limited by either time or size, not both.
diff --git a/doc/sphinx/arm/stork.rst b/doc/sphinx/arm/stork.rst
new file mode 100644
index 0000000..bfa4a06
--- /dev/null
+++ b/doc/sphinx/arm/stork.rst
@@ -0,0 +1,50 @@
+.. _stork:
+
+*************************
+Monitoring Kea With Stork
+*************************
+
+Most administrators want to be able to monitor any Kea services that are running. Kea offers so many
+pieces of information - configuration files, API, statistics, logs, open database content, and more -
+that it may sometimes
+be overwhelming to keep up. ISC's Stork project is intended to address this problem for both Kea
+and BIND 9. Stork is useful in a variety of ways:
+
+- Stork can be used as a dashboard. It provides insight into what exactly is happening
+ on the servers. In particular, it allows users to: see up-to-date details regarding pool
+ utilization in subnets and shared networks; monitor the state of the HA pair (and
+ provide extra insight in case of failover and recovery events); list, filter, and
+ search for specific host reservations; and more. Only
+ a single Stork server needs to be deployed, and one Stork agent on each machine to be monitored.
+
+- The Stork agent can integrate Kea with Prometheus and Grafana. Once the Stork
+ agent is active on the server, it serves as a Prometheus exporter. Users who have deployed
+ Prometheus in their networks can visualize statistics as time series using Grafana.
+
+- Stork can act as both a dashboard and an integrator for Prometheus/Grafana. Once Stork
+ is linked to where Grafana is deployed on the network, users can inspect the current status and
+ visit a customized link to Grafana to see how a given property behaves over time.
+
+Stork is available as source code, but also as native deb and RPM packages, which makes it easy
+to install on most popular systems. For more details, please see the
+`Stork ARM <https://stork.readthedocs.io>`_ or the `Stork project page <https://gitlab.isc.org/isc-projects/stork>`_.
+The ARM has a nice collection of screenshots that is frequently updated, to give users
+an idea of what is currently available. Stork is in the midst of full development with
+monthly releases, so please check back frequently.
+
+.. _grafana:
+.. _prometheus:
+
+Kea Statistics in Grafana
+=========================
+
+The ISC Stork project provides an agent that can be deployed alongside Kea. It
+exposes Kea statistics in a format that is accepted by Prometheus.
+One of the major benefits of Prometheus is that it turns repeated one-time observations into time series,
+which lets users monitor how certain behaviors change over time. It is easy to use other tools
+to visualize data available in Prometheus; the most common approach is to use
+Grafana to provide visual dashboards. The Stork project provides dashboard
+definitions for Kea that can be imported into Grafana very easily.
+
+Learn more about Prometheus and Grafana on their websites: `Prometheus <https://prometheus.io/>`
+and `Grafana <https://grafana.com/>`.