16. Hook Libraries

16.1. 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.

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.

16.2. Installing Hook Packages

Note

For more details about installing the Kea Premium Hooks package, please read this Knowledgebase article.

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 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 2.7.5, there should be a tarball called kea-|release|.tar.gz on the system. Unpack this tarball:

$ tar -zxvf kea-2.7.5.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 2.7.5 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:

$ cd kea-2.7.5
$ tar -xvf ../kea-premium-2.7.5.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:

Package:
  Name:             kea
  Version:          2.7.5
  Extended version: 2.7.5 (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.

  1. 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.

  1. 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.

16.3. 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.

Some hooks use user context to set the parameters. See User Contexts in 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 is 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 kea-dhcp4 and kea-dhcp6 processes support hook libraries.

16.3.1. 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, to use the Flexible Identifier (also called Flex ID) hook library to formulate the client IDs in conjunction with the High Availability (HA) hook library for load-balanced HA, it is essential that the Flex ID library be specified first in the 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 is best to specify the Forensic Logging library last, to ensure that any other installed hooks have already made their contributions to the packet processing before that one is loaded.

16.3.2. 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 config-set or 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. Here's an 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:

{
  "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"
          }
        }
      }
    ]
  }
}

16.3.3. 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." When work is ready to continue, the server unparks the response and continues processing.

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.

Here is an example of the global parameter used with libdhcp_ha.so. It lowers the number of concurrently parked packets to 128.

{
  "Dhcp6": {
    "parked-packet-limit": 128
    "hooks-libraries": [
      {
        "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so"
      },
      {
        "library": "/usr/lib/kea/hooks/libdhcp_ha.so",
        "parameters": {
          "high-availability": [
            {
              "mode": "hot-standby",
              "peers": [
                {
                  "name": "server1",
                  "role": "primary",
                  "url": "http://127.0.0.1:8080/"
                },
                {
                  "name": "server2",
                  "role": "standby",
                  "url": "http://127.0.0.1:8088/"
                }
              ],
              "this-server-name": "server1"
            }
          ]
        }
      }
    ]
  }
}

16.4. 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 at no cost with the open source base code; others are premium libraries available for standalone purchase, while some are only available to organizations that 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 kea-ctrl-agent process to load libraries that should, in fact, be loaded by the kea-dhcp4 or 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.

List of available hook libraries

Name

Availability

Description

BOOTP

Kea open source

This hook library adds BOOTP support, as defined in RFC 1497. It recognizes received BOOTP requests: they are translated into DHCPREQUEST packets, put into the BOOTP client class, and receive infinite lifetime leases.

Class Commands

ISC support customers

This hook library allows configured DHCP client classes to be added, updated, deleted, and fetched without needing to restart the DHCP server.

Configuration Backend Commands

ISC support customers

This hook 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.

DDNS Tuning

ISC premium library

This hook library adds custom behaviors related to Dynamic 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.

Flexible Identifier

ISC premium library

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, 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.

Flexible Option

Kea open source

This library provides hooks that compute option values 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.

Forensic Logging

ISC premium library

This library provides hooks that record a detailed log of 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.

GSS-TSIG

ISC support customers

This hook library adds support to the Kea D2 server (kea-dhcp-ddns) for using GSS-TSIG to sign DNS updates.

High Availability

Kea open source

The risk of DHCP service unavailability can be minimized 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.

Host Cache

ISC support customers

Some database backends, such as RADIUS, 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.

Host Commands

ISC premium library

Kea provides a way to 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. 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).

Lease Commands

Kea open source

This hook library offers a number of commands used to 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.

Leasequery

ISC support customers

This library adds support for DHCPv4 Leasequery (RFC 4388), DHCPv4 Bulk Leasequery (RFC6926); DHCPv6 Leasequery (RFC 5007), and DHCPv6 Bulk Leasequery (RFC5460).

Limits

ISC support customers

With this hook library, kea-dhcp4 and 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.

MySQL Configuration Backend

Kea open source

This hook library is an implementation of the Kea Lease, Host and Configuration Backend for MySQL. It uses a MySQL database as a repository for the Kea leases, host reservations and configuration information. Kea servers use this library to fetch their configurations if Configuration Backend is used.

PerfMon CURRENTLY EXPERIMENTAL

Kea open source

With this hook library, kea-dhcp4 and kea-dhcp6 servers can track and report performance data.

Ping Check

ISC support source customers

With this hook library, the kea-dhcp4 server can perform ping checks of candidate lease addresses before offering them to clients.

PostgreSQL Database Backend

Kea open source

This hook library is an implementation of the Kea Lease, Host and Configuration Backend for PostgreSQL. It uses a PostgreSQL database as a repository for the Kea leases, host reservations and configuration information. Kea servers use this library to fetch their configurations if Configuration Backend is used.

RADIUS

ISC support customers

The RADIUS hook library allows Kea to interact with 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.

RBAC

ISC support customers

This hook library adds support to the Kea Control Agent (kea-ctrl-agent) for Role-Based Access Control filtering of commands.

Run Script

Kea open source

This hook library adds support to run external scripts for specific packet-processing hook points. There are several exported environment variables available for the script.

Statistics Commands

Kea open source

This library provides additional 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.

Subnet Commands

ISC support customers

In deployments in which subnet configuration needs to be 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.

User Check

Kea open source

Reads known users list from a file. Unknown users will be 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.

16.5. libdhcp_bootp.so: Support for BOOTP Clients

This hook library adds support for BOOTP with vendor-information extensions (RFC 1497). 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

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 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).

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-classes": [ "BOOTP" ]
            },
            {
                // Regular DHCP clients will be handled here
                "pool": "192.0.2.1 - 192.0.2.199",
                "client-classes": [ "DHCP" ]
            }],
            ...
        },
        ...
    ],
    ...
}

16.5.1. BOOTP Hooks Limitations

Currently the BOOTP library has the following limitation:

  • Basic BOOTP, as defined in RFC 951, is not supported. Kea only supports BOOTP with vendor-information extensions.

16.6. 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: libdhcp_mysql.so implements this API for MySQL while libdhcp_pgsql.so implements this API for PostgreSQL. To manage the configuration information in a MySQL database, both libdhcp_mysql.so and libdhcp_cb_cmds.so must be loaded by the server used for configuration management. To manage the configuration information in a PostgreSQL database, both libdhcp_pgsql.so and libdhcp_cb_cmds.so must be loaded by the server used for 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 Configuration Backend in DHCPv4 and Configuration Backend in DHCPv6 sections.

Note

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 kea-dhcp4 or kea-dhcp6 process.

Note

Please read about CB Capabilities and Limitations before using the commands described in this section.

16.6.1. Command Structure

There are 5 types of commands supported by this library:

All types of commands accept an optional remote map which selects the database instance to which the command refers. For example:

{
    "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 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.

16.6.2. Control Commands for DHCP Servers

This section describes and gives some examples of the control commands implemented by 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.

16.6.3. 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 remote-network4-list command, which includes the metadata:

{
    "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.

16.6.4. 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:

{
    "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 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 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 remote-subnet4-del-by-id or remote-subnet4-del-by-prefix command, if it is no longer needed.

The following is the successful response to the remote-server4-del command:

{
    "result": 0,
    "text": "1 DHCPv4 server(s) deleted.",
    "arguments": {
        "count": 1
    }
}

Warning

The remote-server4-del and 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.

16.6.5. 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:

{
    "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:

{
    "result": 0,
    "text": "DHCP server server1 found.",
    "arguments": {
        "servers": [
            {
                "server-tag": "server1",
                "description": "A DHCPv6 server located on the first floor."
            }
        ],
        "count": 1
    }
}

16.6.6. 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:

{
    "command": "remote-server4-get-all",
    "arguments": {
        "remote": {
            "type": "mysql"
        }
    }
}

The response includes basic information about each server, such as its server tag and description:

{
    "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
    }
}

16.6.7. 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 remote-server4-set or remote-server6-set commands. The following command creates a new (or updates an existing) DHCPv6 server in the database:

{
    "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:

{
    "result": 0,
    "text": "DHCPv6 server successfully set.",
    "arguments": {
        "servers": [
            {
                "server-tag": "server1",
                "description": "A DHCP server on the ground floor."
            }
        ]
    }
}

16.6.8. 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:

{
    "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.

16.6.9. 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":

{
    "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.:

{
    "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:

{
    "result": 0,
    "text": "1 DHCPv4 global parameter found.",
    "arguments": {
        "parameters": {
            "renew-timer": 2000,
            "metadata": {
                "server-tags": [ "server1" ]
            }
        },
        "count": 1
    }
}

The real value:

{
    "result": 0,
    "text": "1 DHCPv4 global parameter found.",
    "arguments": {
        "parameters": {
            "t1-percent": 0.85,
            "metadata": {
                "server-tags": [ "all" ]
            }
        },
        "count": 1
    }
}

Finally, the boolean value:

{
    "result": 0,
    "text": "1 DHCPv4 global parameter found.",
    "arguments": {
        "parameters": {
            "match-client-id": true,
            "metadata": {
                "server-tags": [ "server2" ]
            }
        },
        "count": 1
    }
}

16.6.10. 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":

{
    "command": "remote-global-parameter4-get-all",
    "arguments": {
        "remote": {
            "type": "mysql"
        },
        "server-tags": [ "server1" ]
    }
}

The example response may look as follows:

{
    "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.

16.6.11. 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:

{
    "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 remote-global-parameter4-get-all or 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.

16.6.12. 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:

{
    "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 network4-del, network6-del commands with respect to the subnets-action parameter.

Note that the server-tags parameter cannot be used for this command.

16.6.13. 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:

{
    "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.

16.6.14. 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":

{
    "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:

{
    "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:

{
    "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 remote-network4-get or 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:

{
    "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.

16.6.15. 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 Shared Networks in DHCPv4 and Shared Networks in DHCPv6 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 remote-subnet4-set, remote-subnet6-set commands should be used.

The following command adds the IPv6 shared network "level3" to the database:

{
    "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.

16.6.16. 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:

{
    "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.

16.6.17. 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":

{
    "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.

16.6.18. 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:

{
    "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:

{
    "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.

16.6.19. 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 Custom DHCPv4 Options and Custom DHCPv6 Options). The following command creates the DHCPv4 option definition at the top-level "dhcp4" option space and associates it with "server1":

{
    "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.

16.6.20. 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:

{
    "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.

16.6.21. 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:

{
    "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.

16.6.22. 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":

{
    "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:

{
    "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
    }
}

16.6.23. 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 Standard DHCPv4 Options and Standard DHCPv6 Options). For example:

{
    "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:

{
    "command": "remote-option6-global-set",
    "arguments": {
        "options": [
            {
                "code": 1,
                "space": "isc",
                "data": "2001:db8:1::1"
            }
        ],
        "server-tags": [ "server1" ]
    }
}

16.6.24. 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 remote-option4-subnet-del, 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".

{
    "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.

16.6.25. 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 Standard DHCPv4 Options and Standard DHCPv6 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.

{
    "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.

16.6.26. 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 remote-option6-subnet-del command must be used instead.

{
    "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.

16.6.27. 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 Standard DHCPv4 Options and Standard DHCPv6 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:

{
    "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.

16.6.28. 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 remote-option4-subnet-del or remote-option6-subnet-del command 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:

{
    "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.

16.6.29. 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 Standard DHCPv4 Options and Standard DHCPv6 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:

{
    "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.

16.6.30. 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.

{
    "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.

16.6.31. 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 Standard DHCPv4 Options and Standard DHCPv6 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.

{
    "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.

16.6.32. 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:

{
    "command": "remote-subnet4-del-by-id",
    "arguments": {
        "subnets": [
            {
                "id": 5
            }
        ],
        "remote": {
            "type": "mysql"
        }
    }
}

The server-tags parameter cannot be used with this command.

16.6.33. 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:

{
    "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.

16.6.34. 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:

{
    "command": "remote-subnet4-get-by-id",
    "arguments": {
        "subnets": [
            {
                "id": 5
            }
        ],
        "remote": {
            "type": "mysql"
        }
    }
}

The server-tags parameter cannot be used with this command.

16.6.35. 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:

{
    "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.

16.6.36. 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":

{
    "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:

{
    "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:

{
    "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 remote-subnet4-get-by-id / remote-subnet6-get-by-id command or the remote-subnet4-get-by-prefix / remote-subnet6-get-by-prefix command.

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:

{
    "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.

16.6.37. 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 DHCPv4 Server Configuration and DHCPv6 Server Configuration). The subnet information conveyed in the remote-subnet4-set or remote-subnet6-set command must include the additional parameter shared-network-name, which denotes whether the subnet belongs to a shared network.

Consider the following example:

{
    "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 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:

{
    "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 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.

16.6.38. 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 remote-class4-get-all command to fetch all client classes and find the dependent ones.

{
    "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.

16.6.39. The remote-class4-get, remote-class6-get Commands

These commands retrieve DHCPv4 or DHCPv6 client class information by a client-class name.

{
    "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:

{
    "result": 0,
    "text": "DHCPv4 client class 'foo' found.",
    "arguments": {
        "client-classes": [
            {
                "name": "foo",
                "metadata": {
                    "server-tags": [ "all" ]
                }
            }
        ],
        "count": 1
    }
}

16.6.40. 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:

{
    "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:

{
    "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
    }
}

16.6.41. 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 Client Classification in DHCPv4 and Client Classification in DHCPv6 for details).

{
    "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 Using Expressions in Classification 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:

{
    "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.:

{
    "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.

16.7. 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

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 kea-dhcp4 or kea-dhcp6 process.

16.7.1. The class-add Command

The 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 class-add command in our example:

{
    "result": 0,
    "text": "Class 'ipxe_efi_x64' added."
}

16.7.2. The class-update Command

The 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 class-add command must be used instead to create the new client class.

The class-update command has the same argument structure as the 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 class-del command and then added again with a different name using 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 an entry. If the client class previously had a resource assigned to it, and the class-update command is missing the resource, it is deleted from the server configuration. If an incremental update of the class is desired, it can be achieved by issuing a class-get to get the current state of the client class, selecting the client class from the response, modifying it to the required outcome, and then issuing the client-update command with the resulting client class attached.

16.7.3. The class-del Command

The 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 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.

16.7.4. The class-list Command

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 class-get command should be used.

16.7.5. The class-get Command

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-in-additional-list": 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-in-additional-list, test, and option-def are not returned if they are not specified for the class.

Note

As of Kea version 2.7.4, only-if-required has been replaced with only-in-additional-list and deprecated. In order to allow users time to migrate class commands will still accept it as input but translate it to only-in-additional-list on output. Eventually support for the old name will be removed.

16.8. 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

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 kea-dhcp4 and kea-dhcp6 daemons by adding it to the hooks-libraries element of the server's configuration:

{
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_ddns_tuning.so",
            "parameters": {
                ...
            }
        },
        ...
    ],
    ...
}

16.8.1. 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 Client Classification. An example of a global expression is shown below:

{
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_ddns_tuning.so",
            "parameters": {
                "hostname-expr": "'host-'+hexstring(pkt4.mac,'-')",
                ...
            }
        },
        ...
    ],
    ...
}

The default behavior of kea-dhcp4 is to prefer the FQDN option (code 81) over the host name option (code 12) when a client sends both. The following example shows the hostname-expr one would use to reverse this rule:

{
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_ddns_tuning.so",
            "parameters": {
                "hostname-expr" : "ifelse(option[12].exists, option[host-name].text, option[81].text)"
            }
        }
    ]
}

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:

{
 "subnet4": [{
     "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))"
         }
     }
 }],
 ...
}

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.

16.8.1.1. DHCPv4 Host-Name Generation

With this library installed, the behavior for 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.

16.8.1.2. DHCPv6 Host-Name Generation

With this library installed, the behavior for 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.

16.8.2. Skipping DDNS Updates

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 (kea-dhcp4 and kea-dhcp6) do not send DDNS update requests (NCRs) to 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:

{
    "reservations": [
    {
        "hw-address": "01:02:03:04:05:06",
        "ip-address": "192.0.2.1",
        "client-classes": [ "SKIP_DDNS", "foo", "bar" ]
    }]
}

The 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 kea-dhcp4 to bypass sending DDNS updates. A similar workflow is supported for kea-dhcp6:

{
    "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:

{
    "client-classes":[
    {
        "name": "SKIP_DDNS",
        "test": "member('KNOWN')"
    }]
}

Note

The libdhcp_ddns_tuning.so hook library must be loaded for the "SKIP_DDNS" class to have an effect.

16.9. 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

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 kea-dhcp4 or kea-dhcp6 process.

libdhcp_flex_id.so allows the definition of an expression, using notation initially used only for client classification. (See Using Expressions in Classification 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.

16.9.1. The replace-client-id Flag

When replace-client-id is set to false (which is the default setting), 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).

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 Using Client Identifier and Hardware Address 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 libdhcp_lease_cmds.so: Lease Commands for Easier Lease Management section describes commands used to retrieve, update, and delete leases using various identifiers, such as hw-address and client-id. 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
    }
}

16.9.2. The ignore-iaid Flag

When ignore-iaid is set to true (the default value is false), 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.

16.10. 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

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 Using Expressions in Classification or libdhcp_flex_id.so: Flexible Identifier for Host Reservations 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.

libdhcp_flex_option.so can be loaded by either the kea-dhcp4 or 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.

{
   "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, as all ingress packets identified by the gateway address 192.168.0.1 are met with a /32 subnet mask in the response:

{
    "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.

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 is encoded into DNS binary format.

Since Kea 2.1.4, the client-class parameter specifies a class guard, and takes a client-class name. If not empty, the client's packet needs to belong to tne specified class for this entry to be used.

It is also possible to have multiple entries for the same option, but each entry must have exactly one action. If the option is not defined in dhcp4 for DHCPv4 or dhcp6 for DHCPv6, the location of the option definition can be specified 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 parameter takes a list of sub-option entries, each containing:

  • code - specifies the sub-option code; either the code or name must be specified. If 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. If 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 - a boolean value that specifies whether the container option should be created, if it does not exist in the add and supersede action. If not specified, it defaults to true.

  • container-remove - a boolean value that specifies whether the container option should be deleted, if it remains empty after the removal of a sub-option by the remove action. If not specified, it defaults to true.

  • csv-format - a boolean value that specifies whether the raw value of the evaluated expression is used (false, default) or parsed using the sub-option definition (true).

  • client-class - specifies whether the sub-option entry must be skipped when the query does not belong to the specified client class. Note that 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. This option encapsulates the vendor-encapsulated-options space.

{
   "Dhcp4": {
       "hooks-libraries": [
           {
               "library": "/usr/local/lib/libdhcp_flex_option.so",
               "parameters": {
                   "options": [
                       {
                           "code": 43,
                           "sub-options": [
                               {
                                  "code": 1,
                                  "add": "'foobar'"
                               }
                           ]
                       }
                   ]
               }
           }
       ]
   }
}

16.11. libddns_gss_tsig.so: Sign DNS Updates With GSS-TSIG

This hook library allows the kea-dhcp-ddns server to use GSS-TSIG to sign DNS updates. For a full discussion of GSS-TSIG in Kea, please see GSS-TSIG.

Note

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.

16.12. 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

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 kea-dhcp4 or 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.

16.12.1. 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, 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 Load-Balancing Configuration 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.

16.12.2. 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 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 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. A restarted server remains in the waiting state until the partner is also restarted. If the partner is not restarted within 10 minutes, the restarted server transitions back to the terminated state to continue serving the DHCP clients. Restart both servers to resume the normal HA service.

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.

16.12.3. HTTPS Support

Since Kea 1.9.7, the High Availability hook library supports HTTPS via TLS, as described in TLS/HTTPS Support.

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 TLS/HTTPS Support 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:

{
  "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:

{
  "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
    }
}

16.12.4. 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 ha-heartbeat command sent over the RESTful API. If the partner server does not respond to the 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 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 Load-Balancing Configuration, 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 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 ha-maintenance-start command from the administrator. The server in this state becomes responsible for responding to all DHCP requests. The server sends a 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 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 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.

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 secondary (load-balancing mode only)

enabled

"HA_server1" or "HA_server2"

hot-standby

primary or standby (hot-standby mode)

enabled

"HA_server1" if primary, none otherwise

load-balancing

primary or secondary (load-balancing mode)

enabled

"HA_server1" or "HA_server2"

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 Load Balancing With Advanced Classification for more details).

16.12.5. 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.

16.12.6. 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 Supported Configurations highlighting differences between the load-balancing and hot-standby modes. The semantics of pool partitioning is explained further in this section. The Load Balancing With Advanced Classification 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-classes": [ "HA_server1" ]
         }, {
            "pool": "192.0.3.200 - 192.0.3.250",
            "client-classes": [ "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: libdhcp_lease_cmds.so and 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 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.

16.12.7. 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.

{
  "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-classes": [ "phones_server1" ]
        }, {
            "pool": "192.0.3.126 - 192.0.3.150",
            "client-classes": [ "laptops_server1" ]
        }, {
            "pool": "192.0.3.200 - 192.0.3.225",
            "client-classes": [ "phones_server2" ]
        }, {
            "pool": "192.0.3.226 - 192.0.3.250",
            "client-classes": [ "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 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 Client Classification for details on how to use the member expression and class dependencies.

16.12.8. 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-classes": [ "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 Load-Balancing Configuration, 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.

16.12.9. Passive-Backup Configuration

The following is an example configuration file for the primary server in a passive-backup 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": "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 Kea Messages Manual) 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.

16.12.10. 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.

16.12.11. Controlling Lease-Page Size Limit

An HA-enabled server initiates synchronization of the lease database after downtime or upon receiving the ha-sync command. The server uses the commands lease4-get-page and 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.

16.12.12. 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 Controlling Lease-Page Size Limit. Before the page of leases is fetched, the synchronizing server sends a 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.

16.12.13. Pausing the HA State Machine

The high-availability state machine includes many different states described in detail in 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 ha-continue command must be sent to the paused server. This command does not take any arguments. See Control Commands for High Availability for details about commands specific to 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 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.

16.12.14. Control Agent Configuration

The The Kea Control 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.

16.12.15. Multi-Threaded Configuration (HA+MT)

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 the 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 improves considerably over earlier versions of Kea 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 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 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 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.

16.12.16. Parked-Packet Limit

Refer to Parked-Packet Limit for a basic introduction to packet parking.

The HA hook library uses this mechanism. When an HA server needs to send a lease update to its peers to notify them of the change to the lease, it parks the client response until the peers acknowledge the lease update. At that point, the server unparks the response and sends it to the client. This applies to client queries that cause lease changes, such as DHCPREQUEST for DHCPv4 and Request, Renew, and Rebind for DHCPv6. It does not apply to DHCPDISCOVERs (v4) or Solicits (v6).

16.12.17. 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 Scope Transition in a Partner-Down Case 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 ha-maintenance-start command allows the administrator to put the pairs of the active servers into 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 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 ha-maintenance-start request was already sent to the other server.

Upon receiving the ha-maintenance-start command, server1 sends the 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 ha-maintenance-start command to server2.

If the 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 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 ha-maintenance-notify to all partner servers. If this step fails for any server, an error is returned. If that happens, the ha-maintenance-cancel command can be used to resume normal operations and fix the issue.

16.12.18. 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.

16.12.18.1. The ha-sync Command

The 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 ha-sync command must be issued to that peer.

Database synchronization may be triggered for both active and backup server types. The 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 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 lease4-get-page commands. When the lease-database synchronization is complete, the synchronizing server sends the 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.

16.12.18.2. The ha-scopes Command

This command allows an administrator to modify the HA scopes being served. It can be useful when recovering from a failure or when performing maintenance. Consult Load-Balancing Configuration and Hot-Standby Configuration to learn which scopes are available for the different HA modes of operation.

Warning

The ha-scopes command can put Kea servers into conflicting states, which can lead to unexpected behavior. Changing scopes does not automatically change the state of the server or its relationship with a partner.

For example, when we add primary scopes to the standby server it will start responding to DHCP traffic for those scopes. This can lead to a situation where both servers are responding to the same traffic, which can lead to IP address collisions.

The ha-scopes command has the following structure; using an example in DHCPv4.:

{
    "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 the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its configuration.

16.12.18.3. The ha-continue Command

This command is used to resume the operation of the paused HA state machine, as described in Pausing the HA 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 the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its configuration.

16.12.18.4. The ha-heartbeat Command

The Server States section describes how the 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 ha-heartbeat command takes no arguments:

{
    "command": "ha-heartbeat",
    "service": [ "dhcp4" ],
    "arguments": {
        "scopes": [ ],
        "server-name": "server2"
    }
}

The optional server-name parameter specifies the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its 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 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 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 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 Scope Transition in a Partner-Down Case section describes the algorithm which the surviving server follows before it transitions to the partner-down state. If the 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.

16.12.18.5. The status-get Command

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 status-get command, including the HA status of two load-balancing servers:

{
    "result": 0,
    "text": "",
    "arguments": {
        "pid": 1234,
        "uptime": 3024,
        "reload": 1111,
        "high-availability": [
            {
                "ha-mode": "load-balancing",
                "ha-servers": {
                    "local": {
                        "role": "primary",
                        "scopes": [ "server1" ],
                        "server-name": "server1",
                        "state": "load-balancing",
                        "system-time": "2024-01-01 12:00:00"
                    },
                    "remote": {
                        "age": 10,
                        "analyzed-packets": 8,
                        "clock-skew": 0,
                        "communication-interrupted": true,
                        "connecting-clients": 2,
                        "in-touch": true,
                        "last-scopes": [ "server2" ],
                        "last-state": "load-balancing",
                        "role": "secondary",
                        "server-name": "server2",
                        "system-time": "2024-01-01 12:00:00",
                        "unacked-clients": 1,
                        "unacked-clients-left": 2
                    }
                }
            }
        ],
        "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 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 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 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 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 Load-Balancing Configuration.

The system-time parameter holds the UTC time when skew between local and partner node was last calculated. It is displayed in %Y-%m-%d %H:%M:%S format for each active node: local, and remote, respectively. The clock-skew parameter is available in the remote map and holds the difference in seconds between the two times. Local time is subtracted from the partner's time. A positive value means that the partner is ahead, while a negative value means that the partner is behind. Both system-time and clock-skew parameters can be null if the clock skew was not calculated yet.

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 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.

16.12.18.6. The ha-maintenance-start Command

This command initiates 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 Controlled Shutdown and Maintenance of DHCP Servers section for details.

{
    "command": "ha-maintenance-start",
    "service": [ "dhcp4" ]
}

16.12.18.7. The ha-maintenance-cancel Command

This command is used to cancel the maintenance previously initiated using the ha-maintenance-start command. The server receiving this command first sends 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 Controlled Shutdown and Maintenance of DHCP Servers section for details.

{
    "command": "ha-maintenance-cancel",
    "service": [ "dhcp4" ]
}

16.12.18.8. The ha-maintenance-notify Command

This command is sent by the server receiving the ha-maintenance-start or the 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 Controlled Shutdown and Maintenance of DHCP Servers section for details.

{
    "command": "ha-maintenance-notify",
    "service": [ "dhcp4" ],
    "arguments": {
        "cancel": false,
        "state": "ready",
        "server-name": "server2"
    }
}

The state argument informs the recipient about the state of the sending server. The recipient can instantly resume the operation of the state machine without sending a heartbeat to check the partner's state.

The optional server-name parameter specifies the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its configuration.

Warning

The 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.

16.12.18.9. 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 the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its 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.

16.12.18.10. 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 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-id": 2000,
        "server-name": "server2"
    }
}

The optional server-name parameter specifies the name of one of the partners in the HA relationship that this command pertains to. This parameter can be omitted if the server receiving this command has only one HA relationship in its configuration.

The origin-id 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. The origin-id parameter deprecates the origin parameter used in some earlier Kea versions.

It elicits the response:

{
    "result": 0,
    "text": "Server successfully notified about the synchronization completion."
}

Warning

The 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.

16.12.19. Hub and Spoke Configuration

A hub-and-spoke arrangement, with one central server and multiple branch servers, is a common way to ensure resiliency of the DHCP 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, 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, if multiple branch servers stop, the central server takes responsibility for all their traffic, and potentially all DHCP traffic in the entire network if every branch server is 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 includes all subnets of the branch servers, so that it can respond to DHCP traffic directed to any branch servers that fail. The subnets in the central server must be grouped into relationships as in the snippet below:

{
    "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. For example, if a relationship contains peer names server1 and server2, it does not 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:

{
    "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 possible to omit 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 the 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.

Note

The hub-and-spoke configuration is currently incompatible with the reselect-subnet-address and reselect-subnet-pool parameters of the libdhcp_radius.so. The High Availability hook library uses an originally selected subnet for choosing an HA relationship to process a packet. The subnet reselection may interfere with this choice. See the RADIUS Hook Library Configuration for details.

16.13. 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

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 kea-dhcp4 or 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 Using the Control Channel) or the RESTful API (see Overview of the Kea Control Agent). An example RESTful API client is described in Overview of the Kea Shell. The following sections describe the commands available.

16.13.1. 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 cache-clear instead. The hosts are stored in FIFO (first-in, first-out) order, so the oldest entries are always removed.

16.13.2. 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 cache-flush instead.

16.13.3. The cache-size Command

This command returns the number of host entries. An example usage looks as follows:

{
    "command": "cache-size"
}

16.13.4. 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 cache-load command or processed by any other tool that is able to understand JSON format.

16.13.5. 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 cache-load command or processed by any other tool that is able to understand JSON format.

16.13.6. The cache-get Command

This command is similar to 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.

16.13.7. The cache-get-by-id Command

This command is similar to 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.

16.13.8. 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 Host Reservations in DHCPv4 or Host Reservations in DHCPv6), 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
    }
}

16.13.9. 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 cache-remove command can solve this problem by removing a cached entry after administrative changes.

The cache-remove command works similarly to the 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
    }
}

16.14. 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

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 kea-dhcp4 or kea-dhcp6 process.

Currently, the following commands are supported:

To use the commands that change reservation information (i.e. reservation-add, reservation-del, and 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 DHCPv4 Hosts Database Configuration and DHCPv6 Hosts Database Configuration). If the hosts-databases are not specified or are running in read-only mode, libdhcp_host_cmds.so will load, but any attempts to use reservation-add, reservation-del, and 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 config-write command.

For a description of proposed future commands, see the Control API Requirements document.

All host commands use JSON syntax. They can be issued either using the control channel (see Management API) or via the Control Agent (see The Kea Control 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"
        },
        ...
    ]
}

16.14.1. 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 reservation-get-by-hostname and reservation-get-by-address, where it is optional. subnet-id is also optional in reservation-get-page, and it is forbidden in 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. See also the note in The reservation-add Command about the reservation-add command for an empty (i.e. with no reserved address or prefix) reservation.

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 the DHCPv4 server or IPv4 in the DHCPv6 server) and this entry is ignored.

16.14.2. The operation-target Parameter

Most host commands accept the operation-target parameter, which 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 (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. reservation-add, reservation-del, and 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

16.14.3. The reservation-add Command

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 Host Reservations in DHCPv4; for IPv6 reservations, see Host Reservations in DHCPv6. 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:

{
    "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 as in this example:

{
    "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, such as:

{
    "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:

{
    "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.

{
    "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:

{
    "result": 0,
    "text": "Host added."
}

And here's an example of a failure:

{
    "result": 1,
    "text": "Mandatory 'subnet-id' parameter missing."
}

As 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.

Note

Since kea version 2.7.0 an empty reservation is implicitly global, i.e. if no subnet-id entry is present and for DHCPv4 ip-address or for DHCPv6 ip-addresses and prefixes do not specify a reserved address or prefix the command is valid and adds a global (subnet-id 0) host reservation.

16.14.4. The reservation-get Command

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 the JSON configuration and the hosts database.

{
    "command": "reservation-get",
    "arguments": {
        "subnet-id": 1,
        "ip-address": "192.0.2.202",
        "operation-target": "alternate"
    }
}

Command 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." }

16.14.5. The reservation-get-all Command

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 reservation-get-all can be very long. The DHCP server does not handle DHCP traffic while preparing a response to 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 reservation-get-page instead.

The command accepts the operation-target argument. By default, it gets the reservation from both the JSON configuration and the hosts database.

{
    "command": "reservation-get-all",
    "arguments": {
        "subnet-id": 1,
        "operation-target": "alternate"
    }
}

For more information, see The reservation-get-all Command.

16.14.6. The reservation-get-page Command

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:

{
    "arguments": {
        "count": 0,
        "hosts": [ ]
    },
    "result": 3,
    "text": "0 IPv4 host(s) found."
}

The command does not accept the operation-target argument.

This command is more complex than reservation-get-all, but it lets users retrieve larger host reservations lists in smaller chunks. For small deployments with few reservations, it is easier to use reservation-get-all.

16.14.7. The reservation-get-by-address Command

reservation-get-by-address can be used to query the host database and retrieve all reservations for a 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 could 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. Thus, searching by an IP address 2001:db8:2:cafe:: can return host reservations with delegated prefixes of different lengths matching this search. 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 the JSON configuration and the hosts database.

{
    "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 Multiple Reservations for the Same IPv4 or Multiple Reservations for the Same IPv6. That's why this command comes in handy when the ip-reservations-unique boolean parameter is set to false. Another use case of this command is having overlapping subnets with the same IP address reservations (but with different identifiers) in different subnets.

16.14.8. The reservation-get-by-hostname Command

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 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 the JSON configuration and the hosts database.

{
    "command": "reservation-get-by-hostname",
    "arguments": {
        "hostname": "foobar.example.org",
        "subnet-id": 1,
        "operation-target": "alternate"
    }
}

For more information, see The reservation-get-by-hostname Command.

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 MySQL section of Kea Database Administration.

16.14.9. The reservation-get-by-id Command

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 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 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 the JSON configuration and the hosts database.

{
    "command": "reservation-get-by-id",
    "arguments": {
        "identifier-type": "hw-address",
        "identifier": "01:02:03:04:05:06",
        "operation-target": "alternate"
    }
}

For more information, see The reservation-get-by-id Command.

16.14.10. The reservation-del Command

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 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.

{
    "command": "reservation-del",
    "arguments": {
        "subnet-id": 4,
        "identifier-type": "hw-address",
        "identifier": "01:02:03:04:05:06",
        "operation-target": "primary"
    }
}

16.14.11. The reservation-update Command

reservation-update allows for the update of an existing host. It takes the same set of arguments as reservation-add, and also 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:

{
    "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 as in this example:

{
    "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, such as:

{
    "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:

{
    "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:

{
    "result": 0,
    "text": "Host updated."
}

And here's an example of a failure:

{
    "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 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 reservation-update command is missing the resource, it is deleted from the database. If an incremental update of the host is desired, this can be achieved by issuing a reservation-get-by-id to get the current state of the host, selecting the host from the response, modifying it to the required outcome, and then issuing the reservation-update command with the resulting host attached.

16.14.12. General Mentions

Note

The host backends for the host cache and RADIUS hook libraries do not respond to commands that return a collection of host reservations, such as reservation-get-all. Commands returning one host entry or dedicated host cache commands should be used instead.

16.15. 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

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 kea-dhcp4 or the 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:

  • lease4-add - adds a new IPv4 lease.

  • lease6-add - adds a new IPv6 lease.

  • lease6-bulk-apply - creates, updates, and/or deletes multiple IPv6 leases in a single transaction.

  • lease4-get - checks whether an IPv4 lease with the specified parameters exists and returns it if it does.

  • lease6-get - checks whether an IPv6 lease with the specified parameters exists and returns it if it does.

  • lease4-get-all - returns all IPv4 leases or all IPv4 leases for the specified subnets.

  • lease6-get-all - returns all IPv6 leases or all IPv6 leases for the specified subnets.

  • 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.

  • 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.

  • lease4-get-by-hw-address - returns all IPv4 leases with the specified hardware address.

  • lease4-get-by-client-id - returns all IPv4 leases with the specified client-id.

  • lease6-get-by-duid - returns all IPv6 leases with the specified DUID.

  • lease4-get-by-hostname - returns all IPv4 leases with the specified hostname.

  • lease6-get-by-hostname - returns all IPv6 leases with the specified hostname.

  • lease4-del - deletes an IPv4 lease with the specified parameters.

  • lease6-del - deletes an IPv6 lease with the specified parameters.

  • lease4-update - updates (replaces) an existing IPv4 lease.

  • lease6-update - updates (replaces) an existing IPv6 lease.

  • lease4-wipe - removes all leases from a specific IPv4 subnet or from all subnets. This command is deprecated and it will be removed in the future.

  • lease6-wipe - removes all leases from a specific IPv6 subnet or from all subnets. This command is deprecated and it will be removed in the future.

  • lease4-resend-ddns - resends a request to update DNS entries for an existing lease.

  • lease6-resend-ddns - resends a request to update DNS entries for an existing lease.

  • lease4-write - writes the IPv4 memfile lease database into a file.

  • 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 Management API) or Control Agent (see The Kea Control 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"
        },
        ...
    ]
}

16.15.1. The lease4-add, lease6-add Commands

The lease4-add and 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 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 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 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 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, 2 for expired-reclaimed, and 3 for the released 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)" }

16.15.2. The lease6-bulk-apply Command

The 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 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 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).

16.15.3. The lease4-get, lease6-get Commands

lease4-get and lease6-get can be used to query the lease database and retrieve existing leases. There are two types of parameters the lease4-get command supports: (address) or (subnet-id, identifier-type, identifier). There are also two types for 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 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 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": "lease6-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.

lease4-get and 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 \(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. \(cltt = expire\) when \(valid\_lft = 4294967295\) and the lease backend is MySQL or PostgreSQL.

16.15.4. The lease4-get-all, lease6-get-all Commands

lease4-get-all and 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 lease4-get-all and 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.

16.15.5. The lease4-get-page, lease6-get-page Commands

The lease4-get-all and 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. lease4-get-page and 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 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 lease4-get-page or 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.

16.15.6. 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 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 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 lease4-get-all or lease6-get-all. This list can be empty and is usually not large.

16.15.7. The lease4-del, lease6-del Commands

lease4-del and 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 lease4-get and 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 an IPv4 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
  }
}

The IPv6 address leases are deleted the same way, but using lease6-del. The IPv6 prefix leases are also deleted using lease6-del, but with some extra steps. The prefix should be referenced by its address and prefix length should be ignored. For example, to delete 2001:db8:1::/48, the following command can be used. The subnet-id parameter is optional.

{
    "command": "lease6-del",
    "arguments": {
        "ip-address": "2001:db8:1::",
        "type": "IA_PD",
        "subnet-id": 1
    }
}

Another parameter called update-ddns, when true, instructs the server to queue a request to 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 lease4-del and 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.

16.15.8. The lease4-update, lease6-update Commands

The lease4-update and 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 lease4-del / lease6-del followed by lease4-add / 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 lease4-update / 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 lease4-update / 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 issuing a lease4-get / lease6-get command to get the current state of the lease, selecting the lease from the response, modifying it to the required outcome, and then issuing the lease4-update / lease6-update command with the resulting lease attached.

16.15.9. The lease4-wipe, lease6-wipe Commands

Warning

The lease4-wipe and lease6-wipe commands are deprecated and they will be removed in the future.

lease4-wipe and 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 lease4-wipe is:

{
  "command": "lease4-wipe",
  "arguments": {
    "subnet-id": 44
  }
}

An example of 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.

16.15.10. The lease4-resend-ddns, lease6-resend-ddns Commands

lease4-resend-ddns and lease6-resend-ddns can be used to generate a request to 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 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 lease6-resend-ddns query is:

{
  "command": "lease6-resend-ddns",
  "arguments": {
    "ip-address": "2001:db8:1::1"
  }
}

Commands lease4-resend-ddns and 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 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."
}

16.15.11. The lease4-write, lease6-write Commands

lease4-write and 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 and the server PID number are 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.

16.16. libdhcp_lease_query.so: Leasequery Support

This library provides support for DHCPv4 Leasequery as described in RFC 4388; and for DHCPv6 Leasequery as described in (RFC 5007).

Note

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 kea-dhcp4 or kea-dhcp6 process.

Kea version 2.3.4 added support for DHCPv6 Bulk Leasequery (RFC 5460); Kea version 2.3.5 added support for DHCPv4 Bulk Leasequery (RFC 6926) using the memfile lease backend.

16.16.1. 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:

DHCPLEASEACTIVE options

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 Storing Extended Lease Information)

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.

16.16.2. 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.

16.16.3. 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 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.

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:

DHCPV6_LEASEQUERY_REPLY status option values per query outcome

Query Outcome

Status Label

Status Code

Status Text

Invalid query type field

STATUS_UnknownQueryType

7

"unknown query-type"

Query by IP address that does not contain an address option

STATUS_Malformed

10

"missing D6O_IAADDR"

Query by IP address for an address that does fall within any configured pools

STATUS_NotConfigured

9

"address not in a configured pool"

Query by IP address which found only an inactive lease (e.g. expired, declined, reclaimed-expired)

STATUS_Success

0

"inactive lease exists"

Query by IP address that found no leases (active or otherwise)

STATUS_Success

0

"no active lease"

Query by IP address that found an active lease for the address

STATUS_Success

0

"active lease found"

Query by Client ID that does not contain a client ID option

STATUS_Malformed

10

"missing D6O_CLIENTID"

Query by Client ID with a link address that does not match any configured subnets

STATUS_NotConfigured

9

"not a configured link"

Query by client ID which found no matching leases

STATUS_Success

0

"no active leases"

Query by client ID which found one or more active leases

STATUS_Success

0

"active lease(s) found"

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) 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). The client-data option encapsulates the following options:

OPTION_CLIENT_DATA returned when active lease(s) are found

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 Storing Extended Lease Information), then an OPTION_LQ_RELAY_DATA option is added to the reply (see RFC 5007, 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.

16.16.4. 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. The resulting list contains unique values of delegated-len, gleaned from the currently configured set of PD pools.

There is an optional parameter, prefix-lengths, 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 is restricted to a single pass, using a length of 72, regardless of whether 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.

16.16.5. 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.

16.16.6. 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.

16.16.7. Bulk Leasequery Configuration

Bulk Leasequery configuration is specified 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 the 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
              }
          }
      }
  ],
  ...
}

16.16.8. Updating Existing Leases in SQL Lease Backends

Bulk Leasequery requires additions to the lease data that is stored. With SQL lease backends, leases created prior to the server being configured for bulk lease query do not contain the new data required. In order to populate this data, it is necessary to run these API commands:

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.

For DHCPv4 lease data, the command is:

{
    "command": "extended-info4-upgrade"
}

For DHCPv6 lease data, the command is:

For extended info used by relay ID and by remote ID, the command is:

{
    "command": "extended-info6-upgrade"
}

In all cases, the response indicates whether it succeeded or failed and includes 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 2.4.1 or older version. extended-info4-upgrade can be used when upgrading from 2.3.8 or older version.

  • Bulk Leasequery was not enabled; tables are maintained only when v6 BLQ is enabled.

  • data in tables does 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 the extended info command is governed by the extended-info-checks parameter, under the sanity-checks element. Please see Sanity Checks in DHCPv4 or Sanity Checks in DHCPv6.

For large numbers of leases, this command may take some time to complete.

Note

Both the extended-info4-upgrade and extended-info6-upgrade commands are intended for one-time use after upgrading to a version of Kea that fully supports Bulk Leasequery in database backends. These commands are not meant for regular use and will be removed in future Kea versions.

16.18. 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

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.

16.18.1. Configuration

The following examples are for kea-dhcp6, but they apply equally to 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 kea-dhcp4 and kea-dhcp6 servers by adding its path in the "hooks-libraries" element of the server's configuration.

{
  "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:

{
  "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:

{
  "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:

{
  "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.

16.18.2. 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-in-additional-list" is "true" cannot be lease-limited. Please refer to the 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 in ISC's GitLab instance.

16.18.3. 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-in-additional-list": true, cannot be rate limited. See the 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.

16.19. libdhcp_mysql.so: Database Backend for MySQL

This hook library implements MySQL database storage for:
  • Lease Backend

  • Host Backend

  • Configuration Backend

16.19.1. MySQL Configuration Backend

This hook library works in conjunction with libdhcp_cb_cmds.so to implement the API to create, read, update, and delete (CRUD) the configuration in a MySQL database. Please see libdhcp_cb_cmds.so: Configuration Backend Commands for more details.

Note

libdhcp_mysql.so is part of the open source code and is available to every Kea user. However, this hook library only works with libdhcp_cb_cmds.so, which allows easy configuration management with the use of API commands. 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.

16.20. libdhcp_perfmon.so: Performance Monitoring

The Performance Monitoring (perfmon) hook library gives the Kea DHCPv4 and DHCPv6 server the ability to track and report performance-related data.

Note

This library is experimental and not recommended for use in production environments.

Note

libdhcp_perfmon.so is part of the open source code and is available to every Kea user.

16.20.1. Overview

The perfmon library, added in Kea 2.5.6, can be loaded by the kea-dhcp4 or kea-dhcp6 daemon by adding it to the hooks-libraries element of the server's configuration:

{
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_perfmon.so",
            "parameters": {
                ...
            }
        },
        ...
    ],
    ...
}

The library tracks the lifecycle of client query packets as they are processed by Kea, from when the query was received by the kernel to when the response is ready to be sent. This tracking is driven by a packet event stack, which contains a list of event/timestamp pairs for significant milestones that occur during the processing of a client query. The list of possible events is shown below:

  1. socket_received - kernel placed the client query into the socket buffer

  2. buffer_read - server read the client query from the socket buffer

  3. mt_queued - server placed the client query into its thread-pool work queue (multi-threaded mode only)

  4. process_started - server has begun processing the query

  5. process_completed - server has constructed the response and is ready to send it

This list is likely to expand over time; it will also be possible for hook developers to add their own events. This will be detailed in future releases.

16.20.2. Passive Event Logging

When the perfmon hook library is loaded, it logs the packet event stack contents for each client query that generates a response packet. The log entry contains client query identifiers, followed by the list of event/timestamp pairs in the order that they occurred.

For kea-dhcp4, the log is identified by the label PERFMON_DHCP4_PKT_EVENTS, and emitted at logger debug level 50 or higher. For a DHCPDISCOVER it is emitted once the DHCPOFFER is ready to send, and looks similar to the following (see the second entry):

2024-03-20 10:52:20.069 INFO  [kea-dhcp4.leases/50033.140261252249344] DHCP4_LEASE_OFFER [hwtype=1 08:00:27:25:d3:f4], cid=[no info], tid=0xc288f9: lease 178.16.2.0 will be offered
2024-03-20 10:52:20.070 DEBUG [kea-dhcp4.perfmon-hooks/50033.140261252249344] PERFMON_DHCP4_PKT_EVENTS query: [hwtype=1 08:00:27:25:d3:f4], cid=[no info], tid=0xc288f9 events=[2024-Mar-20 14:52:20.067563 : socket_received, 2024-Mar-20 14:52:20.067810 : buffer_read, 2024-Mar-20 14:52:20.067897 : mt_queued, 2024-Mar-20 14:52:20.067952 : process_started, 2024-Mar-20 14:52:20.069614 : process_completed]

For kea-dhcp6, the log is identified by the label PERFMON_DHCP6_PKT_EVENTS, and emitted at logger debug level 50 or higher. For a DHCPV6_SOLICIT it is emitted once the DHCPV6_ADVERTISE is ready to send, and looks similar to the following (see the second entry):

2024-03-20 10:22:14.030 INFO  [kea-dhcp6.leases/47195.139913679886272] DHCP6_LEASE_ADVERT duid=[00:03:00:01:08:00:27:25:d3:f4], [no hwaddr info], tid=0xb54806: lease for address 3002:: and iaid=11189196 will be advertised
2024-03-20 10:22:14.031 DEBUG [kea-dhcp6.perfmon-hooks/47195.139913679886272] PERFMON_DHCP6_PKT_EVENTS query: duid=[00:03:00:01:08:00:27:25:d3:f4], [no hwaddr info], tid=0xb54806 events=[2024-Mar-20 14:22:14.028729 : socket_received, 2024-Mar-20 14:22:14.028924 : buffer_read, 2024-Mar-20 14:22:14.029005 : process_started, 2024-Mar-20 14:22:14.030566 : process_completed]

16.20.3. Duration Monitoring

When monitoring is enabled, stack event data is aggregated over a specified interval. These aggregates are referred to as "monitored durations" or simply "durations" for ease. Durations are uniquely identified by a "duration key" which consists of the following values:

  • query message type - message type of the client query (e.g.DHCPDISCOVER, DHCPV6_REQUEST)

  • response message type - message type of the server response (e.g. DHCPOFFER, DHCPV6_REPLY)

  • start event label - event that defines the beginning of the task (e.g. socket_received, process_started)

  • stop event label - event that defines the end of the task (e.g. buffer_read, process_completed)

  • subnet id - subnet selected during message processing (or 0 for global durations)

Once the server has finished constructing a response to a query, the query's event stack is processed into a series of updates to monitored durations. If, upon updating, a duration's sample interval is found to have been completed, it is sent to reporting and a new sample interval is begun. The interval width is dictated by configuration parameter interval-width-secs.

The event stack for the multi-threaded mode DHCPDISCOVER/DHCPOFFER cycle shown above contains the following events:

Event Timestamp

Event Label

2024-Mar-20 14:52:20.067563

socket_received

2024-Mar-20 14:52:20.067810

buffer_read

2024-Mar-20 14:52:20.067897

mt_queued

2024-Mar-20 14:52:20.067952

process_started

2024-Mar-20 14:52:20.069614

process_completed

Assuming the selected subnet's ID was 100, the duration updates created by perfmon from these events are shown below:

Duration Keys for SubnetID 100

Update in microseconds

DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.100

247

DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.100

87

DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.100

55

DHCPDISCOVER.DHCPOFFER.process_started-process_completed.100

1662

DHCPDISCOVER.DHCPOFFER.composite-total_response.100

2051

Notice that in addition to the adjacent event updates, there is an additional duration update for the total duration of the entire stack whose key contains the event-pair composite-total_response. This tracks the total time to respond from when the query is received until the response is ready to send. Finally, there are also global duration updates for each of the above:

Global Duration Keys

Update in microseconds

DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.0

247

DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.0

87

DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.0

55

DHCPDISCOVER.DHCPOFFER.process_started-process_completed.0

1662

DHCPDISCOVER.DHCPOFFER.composite-total_response.0

2051

16.20.4. Statistics Reporting

When enabled, perfmon reports a duration's data each time the duration completes a sampling interval (see stats-mgr-reporting under Configuration). Each statistic employs the following naming convention:

{subnet-id[x]}.perfmon.<query type>-<response type>.<start event>-<end event>.<value-name>

There is both a global and a subnet-specific value for each. Currently, the only value reported for a given duration key is mean-usecs; this statistic is the mean time between the duration's event pair over the most recently completed interval. In other words, if during a given interval there were seven occurrences (i.e. updates) totaling 3500us, the mean-usecs reported would be 500us. Continuing with the example above, the statistics reported are named as follows for the subnet-level values:

subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.mean-usecs
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.mean-usecs
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.mean-usecs
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.mean-usecs
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.mean-usecs

and as shown for global values:

perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.mean-usecs
perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.mean-usecs
perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.mean-usecs
perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.mean-usecs
perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.mean-usecs

The results are reported to StatsMgr, an internal Kea component that reports data as statistics that can be retrieved using statistics commands. They can be fetched using the commands statistic-get-all or statistic-get.

16.20.5. Alarms

Alarms may be defined to watch specific durations. Each alarm defines a high-water mark, high-water-ms, and a low-water mark, low-water-ms. If the reported mean value for the duration exceeds the high-water mark a WARN level alarm log is emitted, at which point the alarm is considered "triggered." Once triggered, the WARN level log is repeated at the alarm report interval specified by alarm-report-secs, as long as the reported mean for the duration remains above the low-water mark. Once the mean falls below the low-water mark the alarm is cleared and an INFO level log is emitted.

The alarm-triggered WARN log looks similar to the following:

2024-03-20 10:22:14.030 WARN [kea-dhcp6.leases/47195.139913679886272] PERFMON_ALARM_TRIGGERED Alarm for DHCPDISCOVER.DHCPOFFER.composite-total_response.0 has been triggered since 2024-03-20 10:18:20.070000, reported mean duration 00:00:00.700000 exceeds high-water-ms: 500

The alarm-cleared INFO log looks like this:

2024-03-20 10:30:14.030 INFO [kea-dhcp6.leases/47195.139913679886272] PERFMON_ALARM_CLEARED Alarm for DHCPDISCOVER.DHCPOFFER.composite-total_response.0 has been cleared, reported mean duration 00:00:00.010000 is now below low-water-ms: 25

16.20.6. API Commands

16.20.6.1. The perfmon-control Command

This command can be used to enable or disable active monitoring and statistics reporting at runtime without altering or reloading configuration.

{
     "command": "perfmon-control",
     "arguments": {
         "enable-monitoring": true,
         "stats-mgr-reporting": false
     }
}

Regardless of the arguments (if any) supplied, the resulting values of both flags are always returned:

{
    "result": 0,
    "text": "perfmon-control success",
    "arguments": {
         "enable-monitoring": true,
         "stats-mgr-reporting": false
    }
}

16.20.6.2. The perfmon-get-all-durations Command

This command fetches all monitored duration data currently held in memory by the Perfmon hook library.

{
    "command": "perfmon-get-all-durations",
    "arguments": {
        "result-set-format": true
    }
}

A result of 0 is returned if command succeeds along with monitored duration data, while a result of 1 is returned if command is invalid or command processing encounters an error.

The format of the monitored duration data returned is determined by the optional argument, result-set-format. When false, (the default), the list of durations will be returned as a list of individual elements as shown below:

{
    "arguments": {
       "durations": [{
           "duration-key": {
               "query-type": "DHCPDISCOVER",
               "response-type": "DHCPOFFER",
               "start-event": "buffer_read",
               "stop-event": "mt_queued",
               "subnet-id": 0
           },
           "max-duration-usecs": 118,
           "min-duration-usecs": 31,
           "occurrences": 501,
           "start-time": "2024-06-12 17:52:06.814884",
           "total-duration-usecs": 23951,
           "mean-duration-usecs": 47
        },
        ...
       ],
       "result-set-format": false,
       "interval-width-secs": 5,
       "timestamp": "2024-06-12 17:52:22.397233"
   },
"result": 0,
"text": "perfmon-get-all-durations: n found"
}

When result-set-format is true, the list of durations will be returned in a format similar to an SQL result set as follows:

{
    "arguments": {
        "durations-result-set": {
            "columns": [
                "query-type",
                "response-type",
                "start-event",
                "end-event",
                "subnet-id",
                "interval-start",
                "occurrence",
                "min-duration-usecs",
                "max-duration-usecs",
                "total-duration-usecs",
                "mean-duration-usecs"
            ],
            "rows": [ [
                "DHCPDISCOVER",
                "DHCPOFFER",
                "buffer_read",
                "mt_queued",
                0,
                "2024-06-12 17:52:06.814884",
                501,
                31,
                118,
                23951,
                47
                ],
                ...
            ]
        },
        "result-set-format": true,
        "interval-width-secs": 5,
        "timestamp": "2024-06-12 17:52:22.397233"
    },
    "result": 0,
    "text": "perfmon-get-all-durations: n found"
}

The data values for each duration will be from the duration's last completed data interval. If a duration has no such interval, interval-start will be reported as "<none>" and the remaining values will be zero.

16.20.7. Configuration

Use of the performance monitoring hook library is configured via several parameters:

  • enable-monitoring

    This parameter enables event data aggregation for reporting, statistics, and alarms. It defaults to false.

  • interval-width-secs

    This specifies the amount of time, in seconds, that individual task durations are accumulated into an aggregate before they are reported. The default is 60 seconds.

  • stats-mgr-reporting

    This enables the reporting of aggregates to StatsMgr. It defaults to true.

  • alarm-report-secs

    This specifies the amount of time, in seconds, between logging instances for an alarm once it has been triggered. It defaults to 300 seconds.

  • alarms

    This is an optional list of alarms that monitor specific duration aggregates. Each alarm is defined by these four parameters:

    • duration-key

      Identifies the monitored duration for the following:

      • query-type - message type of the client query (e.g.DHCPDISCOVER, DHCPV6_REQUEST)

      • response-type - message type of the server response (e.g. DHCPOFFER, DHCPV6_REPLY)

      • start-event - event that defines the beginning of the task (e.g. socket_received, process_started)

      • stop-event - event that defines the end of the task

      • subnet-id - subnet selected during message processing (or 0 for global durations)

    • enable-alarm

      Enables or disables this alarm; defaults to true.

    • high-water-ms

      Specifies the value, in milliseconds, over which the duration must occur to trigger this alarm; must be greater than zero.

    • low-water-ms

      Specifies the value, in milliseconds, under which the duration must fall to clear this alarm; must be greater than zero but less than high-water-ms.

Note

Passive event logging is always enabled, even without specifying the "parameters" section.

A sample configuration is shown below:

{
    "hooks-libraries": [
    {
        "library": "lib/kea/hooks/libdhcp_perfmon.so",
        "parameters": {
            "enable-monitoring": true,
            "interval-width-secs": 5,
            "stats-mgr-reporting": true,
            "alarm-report-secs": 600,
            "alarms": [
            {
                "duration-key": {
                    "query-type": "DHCPDISCOVER",
                    "response-type": "DHCPOFFER",
                    "start-event": "process-started",
                    "stop-event": "process-completed",
                    "subnet-id": 0
                },
                "enable-alarm": true,
                "high-water-ms": 500,
                "low-water-ms": 25
            }]
        }
    }]
}

16.21. 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, section 3.1, item 2.

Note

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.

16.21.1. Overview

The Ping Check library, added in Kea 2.5.4, can be loaded by the kea-dhcp4 daemon by adding it to the hooks-libraries element of the server's configuration:

{
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_ping_check.so",
            "parameters": {
                ...
            }
        },
        ...
    ],
    ...
}

When the library is loaded, kea-dhcp4 conducts a ping check prior to offering a lease to a client if all of the following conditions are true:

  1. The 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 whether prior offers were made.

    1. 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 the number of seconds specified by ping-cltt-secs have elapsed since the CLTT of the original lease.

When the ping check library is loaded, the kea-dhcp4 server responds to a DHCPDISCOVER by:

1. Selecting a candidate IPv4 address through normal processes and using it to construct a DHCPOFFER.

2. Parking the DHCPOFFER and requesting a ping check from the ping check hook library, via its lease4_offer callout. Refer to Parked-Packet Limit for a basic introduction to packet parking.

3. Testing the callout conditions described above: if they are not satisfied, it returns without conducting a check, and the server sends the DHCPOFFER to the client. Otherwise, the callout initiates a ping check for the lease address.

4. Upon conclusion of the ping check, the server either sends the DHCPOFFER to the client, if the check concluded that the address is available, or discards the DHCPFOFFER and creates 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.

  1. Upon receipt of an ICMP ECHO REPLY, conclude that the lease is NOT available.

  2. If any of the following occur:

    1. Receipt of an ICMP DESTINATION UNREACHABLE message

    2. Send failure of an ICMP ECHO REQUEST due to a network error (e.g. network is unreachable)

    3. Send failure of an ICMP ECHO REQUEST due to a permissions error (e.g. lease address is a broadcast address)

    4. Send failure of an ICMP ECHO REQUEST with socket buffer full error

    skip the address check and treat it as available.

Note

"Socket buffer full" errors indicate that the OS rate limits on ICMP are being exceeded. The server does 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.

16.21.2. 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 - This parameter enables or disables ping checking at a given scope.

  • min-ping-requests - This is the minimum number of ECHO REQUESTs sent without receiving a reply, before an address is declared available. The default is 1; it must be greater than zero.

  • reply-timeout - This is the maximum amount of time to wait for a reply to a single ECHO REQUEST. Specified in milliseconds, it must be greater than zero; the default is 100.

  • ping-cltt-secs - This specifies the number of seconds that must elapse after the lease's CLTT before a ping check is conducted, when the client is the lease's previous owner. The default value is 60 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 the Kea core. This value is ignored if given when Kea is in single-threaded mode.

The following configuration excerpt illustrates a global-level configuration:

{
    "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 a subnet-level configuration:

 {
 "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
     }
 }]
}

16.22. libdhcp_pgsql.so: Database Backend for PostgreSQL

This hook library implements PostgreSQL database storage for:
  • Lease Backend

  • Host Backend

  • Configuration Backend

16.22.1. PostgreSQL Configuration Backend

This hook library works in conjunction with libdhcp_cb_cmds.so to implement the API to create, read, update, and delete (CRUD) the configuration in a PostgreSQL database. Please see libdhcp_cb_cmds.so: Configuration Backend Commands for more details.

Note

libdhcp_pgsql.so is part of the open source code and is available to every Kea user. However, this hook library only works with libdhcp_cb_cmds.so, which allows easy configuration management with the use of API commands. 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.

16.23. 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 RADIUS.

Note

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.

16.24. libdhcp_rbac.so: Role-Based Access Control

16.24.1. Role-Based Access Control (RBAC) Overview

Before the processing of commands in received HTTP requests, libdhcp_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

libdhcp_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.

Note

Since Kea 2.7.2 the RBAC is no longer limited to the Control Agent: it can be used by any other server supporting HTTP/HTTPS control sockets e.g. DHCPv4, DHCPv6 and DDNS servers.

16.24.2. Role-Based Access Control Configuration

16.24.2.1. Role Assignment

Role assignment is governed by the configured role-assignment method.

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

16.24.2.2. Role Configuration

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 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.

16.24.2.3. 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. libdhcp_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 server or 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 server or 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.

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.

16.24.2.4. Access Control Lists

Access control lists can be specified using a name (string) or a single entry map.

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.

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)

16.24.2.5. Response Filters

Predefined response filters

Name

Description

list-commands

Removes not-allowed commands from the list-commands response

16.24.2.6. 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).

16.24.3. Sample Configuration

A sample configuration is available in doc/examples/agent/rbac.json in the Kea source and is copied below.

 1 {
 2 "Control-agent": {
 3     // We need to specify where the agent should listen to incoming HTTP
 4     // queries.
 5     "http-host": "127.0.0.1",
 6
 7     // If enabling HA and multi-threading, the 8000 port is used by the HA
 8     // hook library http listener. When using HA hook library with
 9     // multi-threading to function, make sure the port used by dedicated
10     // listener is different (e.g. 8001) than the one used by CA. Note
11     // the commands should still be sent via CA. The dedicated listener
12     // is specifically for HA updates only.
13     "http-port": 8000,
14
15     // TLS trust anchor (Certificate Authority). This is a file name or
16     // (for OpenSSL only) a directory path.
17     "trust-anchor": "my-ca",
18
19     // TLS server certificate file name.
20     "cert-file": "my-cert",
21
22     // TLS server private key file name.
23     "key-file": "my-key",
24
25     // TLS require client certificates flag. Default is true and means
26     // require client certificates. False means they are optional.
27     "cert-required": true,
28
29     // Add hooks here.
30     "hooks-libraries": [
31     {
32         "library": "/opt/lib/libdhcp_rbac.so",
33         "parameters": {
34             // This section configures the RBAC hook library.
35             // Mandatory parameters.
36             "assign-role-method": "cert-subject",
37             "api-files": "/opt/share/kea/api",
38             // Optional parameters.
39             "require-tls": true,
40             "commands": [
41             {
42                 "name": "my-command",
43                 "access": "read",
44                 "hook": "my-hook"
45             } ],
46             "access-control-lists": [
47             {
48                 "my-none": { "not": "ALL" }
49             },{
50                 "another-none": { "and": [ "ALL", "NONE" ] }
51             },{
52                 "my-read": { "access": "read" }
53             } ],
54             "roles": [
55             {
56                 "name": "kea-client",
57                 "accept-commands":
58                 {
59                     "commands": [ "list-commands", "status-get" ]
60                 },
61                 "reject-commands": "NONE",
62                 "other-commands": "reject",
63                 "list-match-first": "accept",
64                 "response-filters": [ "list-commands" ]
65             },{
66                 "name": "admin",
67                 "accept-commands": "ALL",
68                 "reject-commands":
69                 {
70                     "hook": "cb_cmds"
71                 },
72                 "list-match-first": "reject"
73             } ],
74             "default-role":
75             {
76                 "accept-commands": "NONE",
77                 "reject-commands": "ALL"
78             },
79             "unknown-role":
80             {
81                 "accept-commands": "READ",
82                 "reject-commands": "WRITE"
83             }
84         }
85     } ]
86
87     // Additional parameters, such as logging and others
88     // omitted for clarity.
89
90 }
91 }

16.24.4. Accept/Reject Algorithm

This is the pseudo-code of the accept/reject decision algorithm which returns true (accept) or false (reject).

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

16.24.5. 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:

{
"commands": [
        {
            "name": "my-new-command",
            "access": "write",
            "hook": "my-custom-hook"
        }
    ],
...
}

The new command can then be specified in roles:

{
"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:

{
"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.

16.24.6. Extensive Example

Here is an extensive example for a role accepting all read commands, with the exception of 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:

{
"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.

{
"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:

{
"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.

{
"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:

{
"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"
},
...
}

16.25. 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

libdhcp_run_script.so is part of the open source code and is available to every Kea user.

Note

This library can only be loaded by the kea-dhcp4 or kea-dhcp6 process.

{
    "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.

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/sh

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

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

The leases4_committed hook point needs for loops to handle the list of addresses. This can be achived in the following way:

leases4_committed() {
    for i in $(seq 0 $((LEASES4_SIZE-1))); do
        LEASE4_ADDRESS=$(eval "echo \$LEASES4_AT${i}_ADDRESS")
        ...
    done

    for i in $(seq 0 $((DELETED_LEASES4_SIZE-1))); do
        DELETED_LEASE4_ADDRESS=$(eval "echo \$DELETED_LEASES4_AT${i}_ADDRESS")
        ...
    done
    exit 0
}

The leases6_committed hook point needs for loops to handle the list of addresses. This can be achived in the following way:

leases6_committed() {
    for i in $(seq 0 $((LEASES6_SIZE-1))); do
        LEASE6_ADDRESS=$(eval "echo \$LEASES6_AT${i}_ADDRESS")
        ...
    done

    for i in $(seq 0 $((DELETED_LEASES6_SIZE-1))); do
        DELETED_LEASE6_ADDRESS=$(eval "echo \$DELETED_LEASES6_AT${i}_ADDRESS")
        ...
    done
    exit 0
}

16.26. 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 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

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 kea-dhcp4 or kea-dhcp6 process.

The commands provided by this library are:

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 Management API) or the Control Agent (see The Kea Control 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 stat-lease4-get / 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.

16.26.1. The stat-lease4-get, stat-lease6-get Commands

The stat-lease4-get and 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 kea-dhcp4 server:

{
  "command": "stat-lease4-get"
}

The following command fetches lease statistics for subnet ID 10 from a 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 kea-dhcp4 server:

{
  "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"
    }
  }
}

16.27. 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

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 kea-dhcp4 or kea-dhcp6 process.

The following commands are currently supported:

16.27.1. 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 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.

16.27.2. 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 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.

16.27.3. The subnet4-get Command

This command is used to retrieve detailed information about the specified subnet. This command usually follows 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 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": [
                    {
                        ...
                    },
                    ...
                ],
                ...
            }
        ]
    }
}

16.27.4. The subnet6-get Command

This command is used to retrieve detailed information about the specified subnet. This command usually follows 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 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": [
                    {
                        ...
                    },
                    ...
                ],
                ...
            }
        ]
    }
}

16.27.5. 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 subnet4-add. The commands described in libdhcp_host_cmds.so: Host Commands 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"
            }
        ]
    }
}

16.27.6. 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 subnet6-add. The commands described in libdhcp_host_cmds.so: Host Commands 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"
            }
        ]
    }
}

As of Kea 2.6.0, Kea no longer automatically generates subnet IDS; they must be specified for subnet4-add and subnet6-add. If not specified, Kea tries 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 subnet4-add is called five times, each without an ID, Kea will assign IDs 1, 2, 3, 4, and 5 and everything will work properly. However, if 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 an 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.

16.27.7. 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 subnet4-update. The commands described in libdhcp_host_cmds.so: Host Commands 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 subnet4-update command is missing the resource, it is deleted from the server configuration. If an incremental update of the subnet is desired, use subnet4-delta-add.

16.27.8. 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 subnet6-update. The commands described in libdhcp_host_cmds.so: Host Commands 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 subnet6-update command is missing the resource, it is deleted from the server configuration. If an incremental update of the subnet is desired, use subnet6-delta-add.

16.27.9. 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 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 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"
            }
        ]
    }
}

16.27.10. 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 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 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"
        }
    ]
}

16.27.11. 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 subnet4-delta-add. The commands described in libdhcp_host_cmds.so: Host Commands 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").

16.27.12. 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 subnet6-delta-add. The commands described in libdhcp_host_cmds.so: Host Commands 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").

16.27.13. 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 subnet4-delta-del. The commands described in libdhcp_host_cmds.so: Host Commands 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.

16.27.14. 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 subnet6-delta-del. The commands described in libdhcp_host_cmds.so: Host Commands 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.

{
    "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.

16.27.15. 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 network4-get or 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 network4-list looks as follows:

{
    "arguments": {
        "shared-networks": [
            { "name": "floor1" },
            { "name": "office" }
        ]
    },
    "result": 0,
    "text": "2 IPv4 network(s) found"
}

The network6-list command uses exactly the same syntax for both the command and the response.

16.27.16. 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,
            # 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 config-get, just limited to returning the shared network's information.

16.27.17. 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 Shared Networks in DHCPv4 and Shared Networks in DHCPv6.

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 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.

16.27.18. 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 network4-del command looks as follows:

{
    "command": "network4-del",
    "arguments": {
        "name": "floor13"
    }
}

Assuming such a network was configured, the response looks similar to the following:

{
    "arguments": {
        "shared-networks": [
            {
                "name": "floor13"
            }
        ]
    },
    "result": 0,
    "text": "IPv4 shared network 'floor13' deleted"
}

The 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 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 subnet4-del or subnet6-del commands.

16.27.19. 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 network4-add or 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 network4-add or network6-add, and then add an existing subnet to this newly created shared network using network4-subnet-add or network6-subnet-add.

The network4-subnet-add and 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 network4-subnet-del or network6-subnet-del command commands first.

An example invocation of the 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 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.

16.27.20. 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 subnet4-del or subnet6-del commands instead. The network4-subnet-del and 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 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 network6-subnet-del command uses exactly the same syntax for both the command and the response.

16.28. 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

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 for information on how the code works internally. That, together with the Hooks Framework section of the Kea Developer's Guide should give users some pointers on how to extend this library and perhaps even write one from scratch.