15. Hooks Libraries

15.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 “hooks libraries”) and, at various points in its processing (“hook points”), call functions in them. Those functions perform whatever custom processing is required.

The hooks concept allows the core Kea code to remain reasonably small by moving features to external libraries that some, but not all, users find useful. Those with no need for specific functions can simply choose not to load the libraries.

Hooks 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 DHCP4 server and a different set with the DHCP6 server.

Another point to note is that it is possible for a process to load multiple libraries. When processing reaches a hook point, Kea calls the hooks 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.

The next section describes how to configure hooks libraries. Users who are interested in writing their own hooks 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, e.g. the RADIUS library introduced in Kea 1.4 requires the FreeRadius-client library to be present. If –with-free-radius option is not specified, the RADIUS library will not be built.

15.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 separately on how to get it. The package will be a file with a name similar to kea-premium-1.7.1-git.tar.gz. (The name may vary depending on the package purchased.)

2. Administrators who still have the sources for the corresponding version of the open-source Kea package still 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 1.7.1-git., there should be a tarball called kea-1.7.1-git.tar.gz on the system. Unpack this tarball:

$ tar zxvf kea-1.7.1-git.tar.gz

This will unpack the tarball into the kea-1.7.1-git subdirectory of the current working directory.

3. Unpack the Kea premium tarball into the directory into which Kea was unpacked. Once Kea 1.7.1-git has been unpacked into a kea-1.7.1-git 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-1.7.1-git
$ tar xvf ../kea-premium-1.7.1-git.tar.gz

Note that unpacking the Kea premium package will put the files into a directory named “premium”. Regardless of the name of the package, the directory will always be called “premium”, although its contents will vary depending on the premium package.

4. Run 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 configure 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:          1.7.1-git
  Extended version: 1.7.1-git (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, e.g. the RADIUS hook requires extra switches for FreeRADIUS. 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 will eventually venture into the premium/ directory and will install additional hook libraries and associated files.

The installation location of the hooks libraries depends on whether the –prefix parameter was specified in the configure script. If not, the default location will be /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_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 will depend on the packages installed. If the directory was specified via –prefix, the hooks libraries will be located in {prefix directory}/lib/kea/hooks.

15.3. Configuring Hooks Libraries

The hooks 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 hooks library. For example, to set up two hooks libraries for the DHCPv4 server, the configuration would be:

"Dhcp4": {
    :
    "hooks-libraries": [
        {
            "library": "/opt/charging.so"
        },
        {
            "library": "/opt/local/notification.so",
            "parameters": {
                "mail": "spam@example.com",
                "floor": 13,
                "debug": false,
                "users": [ "alice", "bob", "charlie" ],
                "languages": {
                    "french": "bonjour",
                    "klingon": "yl'el"
                }
            }
        }
    ]
    :
}

Note

This syntax is effective as of Kea 1.1.0, to facilitate the specification of library-specific parameters. Libraries should allow a parameter entry for comments, as is the case with many configuration scopes.

Note

In all versions of Kea since 1.1.0, 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 a specific library there is often a specific 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 has no parameters. The second library 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.

Notes:

  • The full path to each library should be given.

  • As noted above, the order in which the hooks are called may be important; consult the documentation for each library for specifics.

  • An empty list has the same effect as omitting the hooks-libraries configuration element altogether.

    Note

    There is one case where this is not true: if Kea is running with a configuration that contains a hooks-libraries item, and that item is removed and the configuration reloaded, the removal will be ignored and the libraries remain loaded. As a workaround, instead of removing the hooks-libraries item, change it to an empty list. This will be fixed in a future version of Kea.

At the present time, only the kea-dhcp4 and kea-dhcp6 processes support hooks libraries.

15.4. Available Hooks Libraries

As described above, the hooks 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 hooks libraries, discussed in the following sections.

Note

Some of these libraries are available with the base code, while others will be shared with organizations supporting development of Kea. Users who would like to get access to those premium libraries should consider purchasing a support contract from ISC. This includes professional support, advance security notifications, input into ISC’s roadmap planning, and many other benefits, while helping make Kea sustainable in the long term.

The following table provides a list of 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.

Warning

While the Kea Control Agent includes the “hooks” functionality, (i.e. hooks libraries can be loaded by this process), none of ISC’s current hooks libraries should be loaded by the Control Agent.

List of Available Hooks Libraries
Name Availability Description
User Check Kea sources (since 0.8) 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 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.
Forensic Logging Support customers (since 1.1) This library provides hooks that record a detailed log of lease assignments and renewals into 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 your jurisdiction requires that you save a different set of information, you may use it as a template or example and create your own custom logging hooks.
Flexible Identifier Support customers (since 1.2) 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 using hardware address or DUID in DHCPv6. However, there are sometimes scenarios where the reservation is more complex, e.g. uses other options that mentioned above, uses part of specific options or perhaps even a combination of several options and fields to uniquely identify a client. Those scenarios are addressed by the Flexible Identifiers 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.
Host Commands Support customers (since 1.2) 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 will be rejected. Those commands are exposed via command channel (JSON over unix sockets) and Control Agent (JSON over RESTful interface). Additional commands and capabilities related to host reservations will be added in the future.
Subnet Commands Support customers (since 1.3) 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 hooks library allows for incremental changes to the subnet configuration such as: adding a subnet, 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.
Lease Commands Kea sources (since 1.3) The lease commands hook library offers a number of new commands used to manage leases. Kea provides a way to store lease information in various backends: memfile, MySQL, PostgreSQL and Cassandra. This library provides a unified interface that can manipulate leases in an unified, safe way. In particular, it allows: manipulate leases in memfile while Kea is running, sanity check changes, check lease existence and remove all leases belonging to specific subnet. It can also catch more obscure errors, like adding a lease with 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. It provides a way to manage user contexts associated with leases.
High Availability Kea sources (since 1.4) Minimizing a risk of DHCP service unavailability is achieved by setting up a pair of the 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 group of clients in this network or all clients, if it detects that its partner has became 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 referenced to as active-passive. This server will activate its DHCP function 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 server, making it much easier to have a replacement that is almost up to date. The “libdhcp_ha” library provides such functionality for Kea DHCP servers.
Statistics Commands Kea sources (since 1.4) The Statistics Commands library provides additional commmands 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. A feature was introduced in Kea 1.4.0 that allows tracking lease allocations within the lease database, thus making the statistics accessible to all connected DHCP servers. The Statistics Commands hooks library utilizes this feature and returns lease statistics for all subnets respectively.
RADIUS Support customers (since 1.4) The RADIUS Hook library allows Kea to interact with the 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 RADIUS server to keep track of device activity over time.
Host Cache Support customers (since 1.4) Some of the database backends, such as RADIUS, are considered slow and may take a long time to respond. Since Kea in general is synchronous, the backend performance directly affects the DHCP performance. To minimize the impact and improve performance, the Host Cache 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.
Class Commands Support customers (since 1.5) This Class Cmds hooks library allows for adding, updating deleting and fetching configured DHCP client classes without the need to restart the DHCP server.
MySQL Configuration Backend Kea sources (since 1.6) The MySQL CB hooks library is an implementation of the Kea Configuration Backend for MySQL. It uses MySQL database as a repository for the Kea configuration information. The Kea servers use this library to fetch their configurations.
Configuration Backend Commands Support customers (since 1.6) The Configuration Backend Commands (CB Commands) hooks library implements a collection of commands to manage the configuration information of the Kea servers in the database. This library may only be used in conjuction with one of the supported configuration backend implementations.

ISC hopes to see more hooks 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 this link: https://gitlab.isc.org/isc-projects/kea/wikis/Hooks-available. Developers or others who are aware of any hooks libraries not listed there are asked to please send a note to the kea-users or kea-dev mailing lists for updating.

The libraries developed by ISC are described in detail in the following sections.

15.5. user_chk: Checking User Access

The user_chk library is the first hooks library published by ISC. It 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.

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 will be treated as unknown and will be 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 user_chk capability 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 hooks 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.

15.7. flex_id: Flexible Identifiers for Host Reservations

This section describes a hook application dedicated to generate flexible identifiers 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.

Currently this library is only available to ISC customers with a paid support contract.

Note

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

The library 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 in a similar way as other hook libraries. It takes a mandatory parameter identifier-expression and optional boolean parameter replace-client-id:

"Dhcp6": {
    "hooks-libraries": [
        {
            "library": "/path/libdhcp_flex_id.so",
            "parameters": {
                "identifier-expression": "expression",
                "replace-client-id": 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 remaining bytes are either randomly changed or not unique between devices. Therefore, the customer decided 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 expression is confirmed to do what is desired of it, 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. bar string 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"
            }
        },
        ...
    ]
}

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

The flex-id library 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 lease_cmds: Lease Commands section describes commands used to retrieve, update, and delete leases using various identifiers, such as “hw-address” and “client-id”. The lease_cmds library 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 the DHCPv4 case, the query will look 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 the DHCPv6 case, the corresponding query will look similar to this:

{
    "command": "lease6-get",
    "arguments": {
        "identifier-type": "duid",
        "identifier": "00:00:54:64:45:66",
        "subnet-id": 10
    }
}

15.8. host_cmds: Host Commands

This section describes a hook application that offers a number of new commands used to query and manipulate host reservations. 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 - such as adding a host with a conflicting identifier in the same subnet - will be rejected. Those commands are exposed via the command channel (JSON over UNIX sockets) and the Control Agent (JSON over a RESTful interface). Additional commands and capabilities related to host reservations will be added in the future.

Currently this library is only available to ISC customers with a paid support contract.

Note

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

Currently, five commands are supported: reservation-add (which adds a new host reservation), reservation-get (which returns an existing reservation if specified criteria are matched), reservation-get-all (which returns all reservations in a specified subnet), reservation-get-page (a variant of reservation-get-all which returns all reservations in a specified subnet by pages), and reservation-del (which attempts to delete a reservation matching specified criteria). To use commands that change the reservation information (currently these are reservation-add and reservation-del, but this rule applies to other commands that may be implemented in the future), the hosts database must be specified and it must not operate in read-only mode (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, the host_cmds library will load, but any attempts to use reservation-add or reservation-del will fail.

Additional host reservation commands are planned in future releases of Kea. For a description of envisaged commands, see the Control API Requirements document.

All 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 DHCPv4 and DHCPv6 servers.

"Dhcp6": {
    "hooks-libraries": [
        {
            "library": "/path/libdhcp_host_cmds.so"
        }
        ...
    ]
}

15.8.1. The subnet-id Parameter

Prior to diving into 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. In previous versions of Kea, reservations had to belong to a specific subnet; as of Kea 1.5.0, reservations may be specified globally. In other words, they are not 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.

15.8.2. 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 Reservation in DHCPv4; for IPv6 reservations, see Host Reservation 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. An example command can be as simple as:

{
    "command": "reservation-add",
    "arguments": {
        "reservation": {
            "subnet-id": 1,
            "hw-address": "1a:1b:1c:1d:1e:1f",
            "ip-address": "192.0.2.202"
        }
    }
}

but it can also take many more parameters, for example:

{
    "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 returns a status that indicates either a success (result 0) or a failure (result 1). A failed command always includes a text parameter that explains the cause of the failure. Example results:

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

Example 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. In future versions of Kea, it will be possible to modify the reservations read from a configuration file. Interested parties are encouraged to contact ISC for more information on developing this functionality.

15.8.3. The reservation-get Command

reservation-get can be used to query the host database and retrieve existing reservations. There are two types of parameters this command supports: (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 case of 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”, but additional types may be added in the future. If any new identifier types are defined in the future, the reservation-get command will support them automatically. 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"
    }
}

reservation-get typically returns the result 0 when the query was conducted properly. In particular, 0 is returned when the host was not found. If the query was successful, a number of host parameters will be returned. An example of a query that did not find the host looks as follows:

{ "result": 0, "text": "Host not found." }

An example result returned when the host was found looks like this:

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

15.8.4. 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"
            },
            ...
            {
                "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"
            }
        ]
    },
    "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 when 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 (see The reservation-get-page command).

For a reference, see The reservation-get-all Command.

15.8.5. 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. Optional source-index and from host id, both defaulting to 0, are used to chain page queries.

The usage of from and source-index parameters requires additional explanation. For the first call, those parameters should not be specified (or 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 are reflecting the internal state of the search. There is no need to understand what they represent; it is simply a value that is supposed to 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 will iterate 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 will default 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,
    "0 IPv4 host(s) found."
}

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

Note

Currently reservation-get-page is not supported by the Cassandra host backend.

15.8.6. The reservation-del Command

reservation-del can be used to delete a reservation from the host database. There are two types of parameters this command supports: (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 case of 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”, but additional types may be added in the future. If any new identifier types are defined in the future, the reservation-get command will support them automatically. 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"
    }
}

reservation-del returns a result 0 when the host deletion was successful or 1 if it was not. Descriptive text is provided in the event of an error. Example results look as follows:

{
    "result": 1,
    "text": "Host not deleted (not found)."
}
{
    "result": 0,
    "text": "Host deleted."
}
{
    "result": 1,
    "text": "Unable to delete a host because there is no hosts-database
             configured."
}

15.9. lease_cmds: Lease Commands

This section describes the hook library with commands used to manage leases. Kea provides a way to store lease information in several backends (memfile, MySQL, PostgreSQL, and Cassandra), and this library provides an interface that can manipulate leases in a unified, safe way. In particular, it allows things 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

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

There are many use cases 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. 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-del - deletes an IPv4 lease with the specified parameters.
  • lease6-del - deletes an IPv6 lease with the specified parameters.
  • lease4-update - updates an IPv4 lease.
  • lease6-update - updates an IPv6 lease.
  • lease4-wipe - removes all leases from a specific IPv4 subnet or from all subnets.
  • lease6-wipe - removes all leases from a specific IPv6 subnet or from all subnets.

The lease 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 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 DHCPv4 and DHCPv6 servers.

"Dhcp6": {
    "hooks-libraries": [
        {
            "library": "/path/libdhcp_lease_cmds.so"
        }
        ...
    ]
}

15.9.1. The lease4-add, lease6-add Commands

The lease4-add and lease6-add commands allow for the creation of a new lease. 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 will try 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 will try 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
    }
}

lease6-add 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 value of “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 now + 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. Note 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. Note this only affects the 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 fwdn-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.
  • user-context - specifies the user context to be associated with this lease. It must be a JSON map.

Here is an example of a more 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,
        "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)" }

15.9.2. The lease6-bulk-apply Command

The lease6-bulk-apply was implemented to address the performance penalty in the High Availability 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. That may result in allocation of 4 leases. In addition, the DHCPv6 may assign different address than requested by the client during the renew or rebind and delete the leases previously used by this client. The are 6 of lease changes sent between the HA partners is in this case. Sending these updates in individual commands, e.g. lease6-update is highly inefficient and produces unnecessary delays in communication 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 in a single command. Both deleted leases and new/updated leases are conveyed 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 the High Avialability is the major application for this command, it can be freely used in all cases when it is desired to send multiple lease changes in a single command.

In the following example, we ask to delete two leases and to 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 is malformed, no leases 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 will continue to be processed for other leases. All the leases for which the command was unable to apply the changes in the database will be 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 hooks 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 meaning 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 lease doesn’t exist (empty result).

15.9.3. The lease4-get, lease6-get Commands

lease4-get or 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": "lease4-get",
    "arguments": {
        "identifier-type": "duid",
        "identifier": "08:08:08:08:08:08",
        "iaid": 1234567,
        "type": "IA_NA",
        "subnet-id": 44
    }
}

The type is an optional parameter. Supported values are: IA_NA (non-temporary address) and IA_PD (IPv6 prefix). If not specified, IA_NA is assumed.

leaseX-get returns a result that indicates a result of the operation and lease details, if found. It has one of the following values: 0 (success), 1 (error), or 2 (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.

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

15.9.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 the leases should be returned. For example, in order 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.

15.9.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 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. In cases of highly distributed databases, such as Cassandra, ordering may be inefficient or even impossible.

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.

15.9.6. The lease4-del, lease6-del Commands

leaseX-del can be used to delete a lease from the lease database. There are two types of parameters this command supports, similar to the leaseX-get commands: (address) for both v4 and v6, (subnet-id, identifier-type, identifier) for v4, and (subnet-id, identifier-type, identifier, type, IAID) for v6. The first type of query is used when the address (either IPv4 or IPv6) is known, but the details of the lease are not. One common use case is where an administrator wants a specified address to no longer be used. The second form of the command uses identifiers. For maximum flexibility, this interface uses identifiers as a pair of values: the type and the actual identifier. The currently supported identifiers are “hw-address” (IPv4 only), “client-id” (IPv4 only), and “duid” (IPv6 only).

An example command for deleting a lease by address is:

{
    "command": "lease4-del",
    "arguments": {
        "ip-address": "192.0.2.202"
    }
}

An example IPv4 lease deletion by “hw-address” is:

{
  "command": "lease4-del",
  "arguments": {
    "identifier": "08:08:08:08:08:08",
    "identifier-type": "hw-address",
    "subnet-id": 44
  }
}

leaseX-del returns 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.

15.9.7. 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 leaseX-del followed by leaseX-add.

The subnet-id parameter is optional. If not specified, or if the specified value is 0, Kea will try 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 as a result of 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 leaseX-update.

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

15.9.8. The lease4-wipe, lease6-wipe Commands

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. Note that 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 2 (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: not all backends support this command.

15.10. subnet_cmds: Subnet Commands

This section describes a hook application that offers some new commands used to query and manipulate subnet and shared network configurations in Kea. This application is 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 a need 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.

Currently this library is only available to ISC customers with a paid support contract.

Note

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

The following commands are currently supported:

  • subnet4-list/subnet6-list - lists all configured subnets.
  • subnet4-get/subnet6-get - retrieves detailed information about a specified subnet.
  • subnet4-add/subnet6-add - adds a new subnet into the server’s configuration.
  • subnet4-update/subnet6-update - updates a subnet in the server’s configuration.
  • subnet4-del/subnet6-del - removes a subnet from the server’s configuration.
  • network4-list/network6-list - lists all configured shared networks.
  • network4-get/network6-get - retrieves detailed information about a specified shared network.
  • network4-add/network6-add - adds a new shared network to the server’s configuration.
  • network4-del/network6-del - removes a shared network from the server’s configuration.
  • network4-subnet-add/network6-subnet-add - adds an existing subnet to an existing shared network.
  • network4-subnet-del/network6-subnet-del - removes a subnet from an existing shared network and demotes it to a plain subnet.

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

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

15.10.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 be then 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": [
                    ....
                ]
                ...
            }
        ]
    }
}

15.10.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": [
                    ...
                ]
                ....
            }
        ]
    }
}

15.10.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 must not be specified within subnet4-add. The commands described in host_cmds: 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"
            }
        ]
    }
}

15.10.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 must not be specified within subnet6-add. The commands described in host_cmds: 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"
            }
        ]
    }
}

It is recommended, but not mandatory, to specify the subnet ID. If not specified, Kea will try to assign the next subnet-id value. This automatic ID value generator is simple; it returns a previously automatically assigned value, increased by 1. This works well, unless a subnet is manually created with a value bigger 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 it will work just fine. 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 id of 1; the third will use a value of 2; and finally the fourth will have the 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 use explicit values, so the auto-generated values will always work; or always use explicit values, so the 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.

15.10.7. The subnet4-update Command

This command is used to update a 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 must not be specified within subnet4-update. The commands described in host_cmds: 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"
            }
        ]
    }
}

15.10.8. The subnet6-update Command

This command is used to update a 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 must not be specified within subnet6-update. The commands described in host_cmds: 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"
            }
        ]
    }
}

15.10.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 has certain implications which the server’s administrator should be aware of.

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 the 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
    }
}

The example 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"
            }
        ]
    }
}

15.10.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 has certain implications which the server’s administrator should be aware of.

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 the 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
    }
}

The example 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"
        }
    ]
}

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

network6-list follows exactly the same syntax for both the query and the response.

15.10.12. The network4-get, network6-get Commands

These commands are used to retrieve detailed information about shared networks, including subnets that are currently part of a given network. Both commands take one mandatory parameter, name, which specifies the name of the shared network. An example command to retrieve details about an IPv4 shared network with the name “floor13” looks as follows:

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

An example response could look as follows:

{
    "result": 0,
    "text": "Info about IPv4 shared network 'floor13' returned",
    "arguments": {
        "shared-networks": [
        {
            "match-client-id": true,
            "name": "floor13",
            "option-data": [ ],
            "rebind-timer": 90,
            "relay": {
                "ip-address": "0.0.0.0"
            },
            "renew-timer": 60,
            "reservation-mode": "all",
            "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
        }
        ]
    }
}

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

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

15.10.14. 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 there was such a network configured, the response will look similar to the following:

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

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

15.10.15. 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 better 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 subnet-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, please use the network4-subnet-del or network6-subnet-del 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 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.

15.10.16. 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 subnet-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 equal to 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.

15.11. class_cmds: Class Commands

This section describes the Class Commands hooks library, which 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 client classes configured for a given server.

Note

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

The Class Commands hooks library is currently available only to ISC customers with a paid support contract.

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

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

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

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

15.11.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-if-required": true,
                "test": "option[vendor-class-identifier].text == 'PXEClient'",
                "option-def": [
                    {
                        "name": "configfile",
                        "code": 209,
                        "type": "string"
                    }
                ],
                "option-data": [ ],
                "next-server": "0.0.0.0",
                "server-hostname": "xfce",
                "boot-file-name": "/dev/null"
            }
        ]
    }
}

Note that the example above is DHCPv4-specific; the last three parameters are only returned by the DHCPv4 server and are never returned by the DHCPv6 server. Also, some of the parameters provided in this example may not be returned if they are not specified for the class. Specifically, only-if-required, test, and option-def are not returned if they are not specified for the class.

15.12. cb_cmds: Configuration Backend Commands

This section describes the cb_cmds hooks library, which is used to manage Kea servers’ configurations in the Configuration Backends. This library must be used in conjunction with the available CB hooks libraries implementing the common APIs to create, read, update, and delete (CRUD) the configuration information in the respective databases. For example: the mysql_cb hooks library, released in Kea 1.6.0, implements this API for MySQL. In order to manage the configuration information in the MySQL database, both the mysql_cb and cb_cmds libraries must be loaded by the server used for the configuration management.

The cb_cmds library is only available to ISC customers with a paid support contract.

Note

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

15.12.1. Commands Structure

There are 5 types of commands supported by this library:

  • del - delete the selected object from the database, e.g. remote-global-parameter4-del.
  • get - fetch the selected object from the database, e.g. remote-subnet4-get.
  • get-all - fetch all objects of the particular type from the database, e.g. remote-option-def4-get-all.
  • list - list all objects of the particular type in the database, e.g. remote-network4-list; this class of commands returns brief information about each object comparing to the output of get-all.
  • set - creates or replaces an object of the given type in the database, e.g. remote-option4-global-set.

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

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

As of the Kea 1.6.0 release, it is possible to configure the Kea server to use only one configuration backend. Strictly speaking, it is possible to point the Kea server to at most one MySQL database using the config-control parameter. That’s why, in this release, the remote parameter may be omitted in the commands and the cb_cmds hooks library will use the sole backend by default.

15.12.2. Control Commands for DHCP Servers

This section describes and gives some examples of the control commands implemented by the cb_cmds hooks library, 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 the following sections, various commands are described and some usage examples are provided. In the sections jointly describing the DHCPv4 and DHCPv6 variants of the particular command, we sometimes use the following notation: the remote-subnet[46]-set is the wildcard name for the two commands: remote-subnet4-set and remote-subnet6-set.

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.

15.12.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 the administrator, but which is not part of the object specification from the DHCP server standpoint. In the Kea 1.6.0 release, the metadata is limited to the server-tag, which 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, this map will be extended with additional information, e.g. object modification time, log message created during the last modification, etc.

15.12.4. 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": "mysql"
        }
    }
}

As a result of this command, the user defined server called server1 is removed from the database. All associations of the configuration information with this server are automatically removed from the database. The non-shareable configuration information, such as: global parameters, option definitions and global options associated with the server are removed from the database. The 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 the server1 using the remote-subnet4-set command and the server1 is subsequently deleted, the subnet remains in the database but none of the servers can use this subnet. The subnet can be updated using the remote-subnet4-set and associated with some other server or with all servers using the special server tag “all”. Such subnet can be also deleted from the database using the remote-subnet4-del-by-id or remote-subnet4-del-by-prefix, 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
    }
}

Note

The remote-server4-del and remote-server6-del commands must be used with care, because an accidental deletion of the server causes 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.

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

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

15.12.7. 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 accross 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. The maximum length of the server tag is 256 characters. The following keywords are reserved and must not 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."
            }
        ]
    }
}

15.12.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 will use 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 the 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.

15.12.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 the “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. Therefore, the value shared by all servers is returned. If there was the server1 specific value in the database this 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
    }
}

15.12.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 if this parameter is specific to the “server1” or 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 the 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.

15.12.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 are stored successfully and some fail. If an error occurs when processing this command, it is recommended to use remote-global-parameter[46]-get-all to check which of the parameters have been stored/updated successfully and which have failed.

The server-tags list is mandatory and it must contain a single server tag or the keyword “all”. In the example above, all specified parameters are associated with the “server1” server.

15.12.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 network[46]-del commands with respect to the subnets-action parameter.

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

15.12.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 must not be used for this command.

15.12.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 the “server1” and “server2”:

{
    "command": "remote-network4-list"
    "arguments": {
        "remote": {
            "type": "mysql"
        },
        "server-tags": [ "server1", "server2" ]
    }
}

The server-tags parameter is mandatory and it 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. In order to fetch the detailed information about the selected shared network, use the remote-network[46]-get command.

The example response above contains three shared networks. One of the shared networks is associated will all servers, so it is included in the list of shared networks to be used by the “server1” and “server2”. The remaining two shared networks are returned because one of them is associated with the “server1” and another one is associated with the “server2”.

When listing unassigned shared networks, the response will look 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.

15.12.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 will result in an error.

These commands are intended to be used for managing the shared network-specific information and DHCP options. In order to associate and disassociate the subnets with the shared networks, the remote-subnet[46]-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 will use the global values for unspecified parameters or, if the global values are not specified, the default values will be used.

The server-tags list is mandatory for this command and it 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.

15.12.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 the “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 the server1, no option is deleted. In order to delete an option belonging to “all” servers, the keyword “all” must be used as server tag. The server-tags list must contain exactly one tag. It must not include the null value.

15.12.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”. It must not contain the null value.

15.12.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 particular 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 it must include exactly one server tag or the keyword “all”. It must not include the null value.</para>

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.

15.12.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 in the top-level “dhcp4” option space and associates it with the “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”. It must not contain the null value.</para>

15.12.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” is the top-level option space where the standard DHCPv4 options belong. The server-tags is mandatory and it must include a single option tag or the keyword “all”. If the explicit server tag is specified then 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. In order to delete the option associated with all servers, the keyword “all” must be specified.

15.12.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 is mandatory and it must include exactly one server tag or the keyword “all”. It must not contain the null value.

15.12.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 particular server or for all servers. The following command fetches all global DHCPv4 options for the “server1”:

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

The server-tags list is mandatory for this command and it must contain exactly one server tag or a keyword “all”. It must not contain the null value. The following is the example response to this command with a single option being associated with the “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
    }
}

15.12.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 it must include exactly one server tag or the keyword “all”. It must not 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 the standard DHCP options. When specifying a value for the user-defined DHCP option, the option code should be specified 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" ]
    }
}

15.12.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 option instance is not affected by this command as this command merely deletes shared network level option. In order to delete subnet level option the remote-option[46]-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 the shared network “fancy”.

{
    "command": "remote-option4-network-del",
    "arguments": {
        "shared-networks": [
            {
                "name": "fancy"
            }
        ],
        "options": [
            {
                "code": 5,
                "space": "dhcp4"
            }
        ],
        "remote": {
            "type": "mysql"
        }
    }
}

The “dhcp4” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.

15.12.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 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 sever-tags parameter must not 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 specified instead of the name.

15.12.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 option instance is not affected by this command as this command merely deletes a prefix delegation pool level option. In order to delete 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” is the top-level option space where the standard DHCPv6 options belong. The server-tags parameter must not be specified for this command.

15.12.27. The remote-option6-pd-pool-set Command

This command creates a new prefix delefation 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 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 sever-tags parameter must not 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 specified instead of the name.

15.12.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 option instance is not affected by this command as this command merely deletes a pool level option. In order to delete subnet level option the remote-option[46]-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” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.

15.12.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 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 sever-tags parameter must not 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 specified instead of the name.

15.12.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 identifer of 123.

{
    "command": "remote-option4-subnet-del",
    "arguments": {
        "subnets": [
            {
                "id": 123
            }
        ],
        "options": [
            {
                "code": 5,
                "space": "dhcp4"
            }
        ],
        "remote": {
            "type": "mysql"
        }
    }
}

The “dhcp4” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.

15.12.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 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 sever-tags parameter must not 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 specified instead of the name.

15.12.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 must not be used with this command.

15.12.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 must not be used with this command.

15.12.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 must not be used with this command.

15.12.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 must not be used with this command.

15.12.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 the “server1” and “server2”:

{
    "command": "remote-subnet4-list"
    "arguments": {
        "remote": {
            "type": "mysql"
        },
        "server-tags": [ "server1", "server2" ]
    }
}

The server-tags parameter is mandatory and it contains one or more server tags. It may contain the keyword “all” to fetchg 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 subnet identifier, prefix and associated shared network name. In order to retrieve full information about the selected subnet use the remote-subnet[46]-get-by-id or remote-subnet[46]-get-by-prefix.

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, thus it is also present in the configuration for the “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.

15.12.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-subnet[46]-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 it 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.</para>

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.

15.13. ha: High Availability

This section describes the High Availability hooks library, which 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 of one of the servers. This library was previously only available to ISC’s paid subscribers, but is now part of the open source Kea, available to all users.

Note

This library may 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, difficult to use, has significant operational constraints, and is different than its v4 counterpart. Although it may be useful for some users to use a “standard” failover protocol, it seems that 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.

15.13.1. Supported Configurations

The Kea HA hook library supports two configurations, also known as HA modes: load-balancing and hot-standby. 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 (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. 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 also designated as “primary” and the second as “secondary.” However, during normal operation, the primary server is the only one that responds to DHCP requests. The secondary or 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 secondary considers the primary to be offline. If the secondary server detects the failure of the primary, it starts responding to all DHCP queries.

In the configurations described above, 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 server. 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 increases the latency of DHCP responses, because not only do active servers send lease updates to each other, but also to the backup servers.

15.13.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. The lease information includes 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 heartbeat command. This gives a good approximation of the clock skew, although it doesn’t take into account the time between sending the response by the partner and receiving this response by the server which sent the 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.

15.13.3. 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 doesn’t 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 and 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 servers.
  • 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.
  • 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.
  • 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 will also start 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 is completed, the syncing server issues the dhcp-enable command to re-enable the DHCP service of its partner. 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 will transition directly from the waiting state to the ready state.
  • terminated - an active server transitions to this state when the High Availability hooks 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 the lease updates are not exchanged and the heartbeats are not sent. Once a server has entered the “terminated” state, it will remain 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. The 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 the 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 Server Scopes denote what group of received DHCP queries the server responds to in the given state. 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
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
partner-down 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

The DHCP service scopes require some explanation. 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.

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 of the servers 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 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 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).

15.13.4. 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 will respond 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 will receive the rebinding request and will typically extend 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 not respond to them anymore; the client will eventually transition back to the correct server via the rebinding mechanism.

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

"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": 10000,
                "max-ack-delay": 5000,
                "max-unacked-clients": 5,
                "peers": [{
                    "name": "server1",
                    "url": "http://192.168.56.33:8080/",
                    "role": "primary",
                    "auto-failover": true
                }, {
                    "name": "server2",
                    "url": "http://192.168.56.66:8080/",
                    "role": "secondary",
                    "auto-failover": true
                }, {
                    "name": "server3",
                    "url": "http://192.168.56.99:8080/",
                    "role": "backup",
                    "auto-failover": false
                }]
            }]
        }
    }],

    "subnet4": [{
        "subnet": "192.0.3.0/24",
        "pools": [{
            "pool": "192.0.3.100 - 192.0.3.150",
            "client-class": "HA_server1"
         }, {
            "pool": "192.0.3.200 - 192.0.3.250",
            "client-class": "HA_server2"
         }],

         "option-data": [{
            "name": "routers",
            "data": "192.0.3.1"
         }],

         "relay": { "ip-address": "10.1.2.3" }
    }]
}

Two hooks 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 hooks libraries locations must be updated accordingly.

The HA configuration is specified within the scope of libdhcp_ha.so. Note that the top-level parameter high-availability is a list, even though it currently contains only one entry.

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 with one of the servers specified within the peers list.
  • mode - specifies an HA mode of operation. 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. The 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. Usually it is greater than the duration of multiple heartbeat-delay values. 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 “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 can’t 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.

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. Note that the server in question may not respond to some DHCP clients because these clients are not to be serviced by this server according to administrative policy. The server may also 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 nighttime), 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 the max-unacked-clients to 0.

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.

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.
  • 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, 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. When either of the servers is in the partner-down state, it can serve leases from both pools and 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 will allocate the lease from the pool of “192.0.3.200 - 192.0.3.250”.

15.13.6. 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 will be 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 the 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": [{
        "subnet": "192.0.3.0/24",
        "pools": [{
            "pool": "192.0.3.100 - 192.0.3.125",
            "client-class": "phones_server1"
        }, {
            "pool": "192.0.3.126 - 192.0.3.150",
            "client-class": "laptops_server1"
        }, {
            "pool": "192.0.3.200 - 192.0.3.225",
            "client-class": "phones_server2"
        }, {
            "pool": "192.0.3.226 - 192.0.3.250",
            "client-class": "laptops_server2"
        }],

        "option-data": [{
            "name": "routers",
            "data": "192.0.3.1"
        }],

        "relay": { "ip-address": "10.1.2.3" }
    }],
}

The configuration provided above splits the address range into four pools: two pools dedicated to server1 and two to 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.

15.13.7. Hot-Standby Configuration

The following is an example configuration of the primary server in the 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": 10000,
                "max-ack-delay": 5000,
                "max-unacked-clients": 5,
                "peers": [{
                    "name": "server1",
                    "url": "http://192.168.56.33:8080/",
                    "role": "primary",
                    "auto-failover": true
                }, {
                    "name": "server2",
                    "url": "http://192.168.56.66:8080/",
                    "role": "standby",
                    "auto-failover": true
                }, {
                    "name": "server3",
                    "url": "http://192.168.56.99:8080/",
                    "role": "backup",
                    "auto-failover": false
                }]
            }]
        }
    }],

    "subnet4": [{
        "subnet": "192.0.3.0/24",
        "pools": [{
            "pool": "192.0.3.100 - 192.0.3.250",
            "client-class": "HA_server1"
        }],

        "option-data": [{
            "name": "routers",
            "data": "192.0.3.1"
        }],

        "relay": { "ip-address": "10.1.2.3" }
    }]
}

This configuration is very similar to the load-balancing configuration described in 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 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 one server responding to DHCP queries, there is only one scope - HA_server1 - in use within pools 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.

15.13.8. 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, PostgreSQL, and Cassandra. 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:8080/",
                            "role": "primary"
                        },
                        {
                            "name": "server2",
                            "url": "http://192.168.56.66:8080/",
                            "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 hooks library configuration is designed to maximize flexibility of administration.

15.13.9. 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 commands described in The lease4-get-page, lease6-get-page Commands 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 hooks 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.

15.13.10. 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 will reset the timeout for the DHCP service being disabled. This timeout value is by default set to 60 seconds. If fetching a single page of leases takes longer than the specified time, the partner server will assume that the synchronizing server died and will resume 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:8080/",
                            "role": "primary"
                        },
                        {
                            "name": "server2",
                            "url": "http://192.168.56.66:8080/",
                            "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.

15.13.11. 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 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 will rebuild 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 hooks library provides configuration parameters and a command to control when the HA state machine should be paused and resumed. 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:8080/",
                            "role": "primary"
                        },
                        {
                            "name": "server2",
                            "url": "http://192.168.56.66:8080/",
                            "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 the HA hooks library.

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:8080/",
                            "role": "primary"
                        },
                        {
                            "name": "server2",
                            "url": "http://192.168.56.66:8080/",
                            "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 for the backup and 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, it must be taken into account that 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.

15.13.12. Control Agent Configuration

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 hooks 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 will not be able to communicate with the 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",
    "http-port": 8080,

    "control-sockets": {
        "dhcp4": {
            "socket-type": "unix",
            "socket-name": "/tmp/kea-dhcp4-ctrl.sock"
        },
        "dhcp6": {
            "socket-type": "unix",
            "socket-name": "/tmp/kea-dhcp6-ctrl.sock"
        }
    }
}
}

15.13.13. 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 when required, it may be useful for the administrator to have more control over the server behavior. In particular, it may be useful to be able to trigger lease-database synchronization on demand. It may also be useful to manually set the HA scopes that are being served.

Note that the backup server can sometimes be used to handle DHCP traffic if both active servers are down. The backup server does not perform 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 hooks library which are available for the administrator.

15.13.13.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 those 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. In order 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 (DHCPv4 server case):

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

15.13.13.2. The ha-scopes Command

This command allows modification of the HA scopes that the server is serving. Consult Load-Balancing Configuration and Hot-Standby Configuration to learn what scopes are available for different HA modes of operation. The ha-scopes command has the following structure (DHCPv4 server case):

{
    "command": "ha-scopes",
    "service": [ "dhcp4" ],
    "arguments": {
        "scopes": [ "HA_server1", "HA_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": [ ]
    }
}

15.13.13.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 as simple as:

{
    "command": "ha-continue"
}

15.14. stat_cmds: Supplemental Statistics Commands

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 four lease backends were extended to support retrieving lease statistics for all subnets, a single subnet, or a range of subnets. Finally, this library was constructed to provide commands for retrieving these statistics.

Note

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

The commands currently provided by this library are:

  • stat-lease4-get - fetches DHCPv4 lease statistics.
  • stat-lease6-get - fetches DHCPv6 lease statistics.

The stat 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 may be loaded by both the kea-dhcp4 and kea-dhcp6 servers. It 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 hooks library may be loaded by any or all of the servers. However, one thing to keep in mind is that a server’s response to a stat-lease[46]-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.

15.14.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. Use this 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 will only output 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 large numbers of 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 will be the “text” element; or
    • 2 - the fetch found no matching data.
  • text - an explanation of the command outcome. When the command succeeds it will contain 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 sum of all addresses in all the configured pools in the subnet.
      • 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 sum of all the NA addresses in all the configured NA pools in the subnet.
      • assigned-nas - the number of NA addresses in the subnet that are currently assigned to a client.
      • declined-nas - the number of NA addresses that are currently declined and are thus unavailable for assignment.
      • total-pds - the total number of prefixes available of DHCPv6 management in the subnet. In other words, this is the sum of all prefixes in all the configured prefix pools in the subnet.
      • assigned-pds - the number of 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", "assigned-addresses", "declined-addresses" ]
      "rows": [
        [ 10, 256, 111, 0 ],
        [ 20, 4098, 2034, 4 ]
      ],
    "timestamp": "2018-05-04 15:03:37.000000"
    }
  }
}

The response to a DHCPv6 command might look as follows (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", "assigned-nas", "declined-nas", "total-pds", "assigned-pds" ]
      "rows": [
        [ 10, 4096, 2400, 3, 0, 0],
        [ 20, 0, 0, 0, 1048, 233 ]
        [ 30, 256, 60, 0, 1048, 15 ]
      ],
    "timestamp": "2018-05-04 15:03:37.000000"
    }
  }
}

15.15. radius: RADIUS Server Support

The RADIUS hooks library allows Kea to interact with two types of RADIUS servers: access and accounting. Although the most common DHCP and RADIUS integration is done on the DHCP relay-agent level (DHCP clients send DHCP packets to DHCP relays; those relays contact the RADIUS server and depending on the response either send the packet to the DHCP server or drop it), it does require DHCP relay hardware to support RADIUS communication. Also, even if the relay has the necessary support, it is often not flexible enough to send and receive additional RADIUS attributes. As such, the alternative looks more appealing: to extend the DHCP server to talk to RADIUS directly. That is the goal this library intends to fulfill.

Note

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

The major feature of this hooks library is the ability to use RADIUS authorization. When a DHCP packet is received, the Kea server sends an Access-Request to the RADIUS server and waits for a response. The server then sends back either an Access-Accept with specific client attributes, or an Access-Reject. There are two cases supported here: first, the Access-Accept includes a Framed-IP-Address (for DHCPv4) or Framed-IPv6-Address (for DHCPv6), which will be interpreted by Kea as an instruction to assign that specified IPv4 or IPv6 address. This effectively means RADIUS can act as an address-reservation database.

The second case supported is the ability to assign clients to specific pools based on a RADIUS response. In this case, the RADIUS server sends back an Access-Accept with a Framed-Pool (IPv4) or Framed-IPv6-Pool (IPv6). In both cases, Kea interprets those attributes as client classes. With the addition of the ability to limit access to pools to specific classes (see Configuring Pools With Class Information), RADIUS can be used to force the client to be assigned a dynamic address from a specific pool. Furthermore, the same mechanism can be used to control what kind of options the client will get if there are DHCP options specified for a particular class.

15.15.1. Compilation and Installation of the RADIUS Hook

The following section describes how to compile and install the software on CentOS 7.0. Other systems may differ slightly.

STEP 1: Install dependencies

Several tools are needed to build the dependencies and Kea itself. The following commands should install them:

$ sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
$ sudo yum install gcc-g++ openssl-devel log4cplus-devel wget git

STEP 2: Install FreeRADIUS

The Kea RADIUS hooks library uses the FreeRADIUS client library to conduct RADIUS communication. Unfortunately, the standard 1.1.7 release available from the project website https://freeradius.org/sub_projects/ has several serious deficiencies; ISC engineers observed a segmentation fault during testing. Also, the base version of the library does not offer asynchronous transmissions, which are essential for effective accounting implementation. Both of these issues were addressed by ISC engineers, and the changes have been reported to the FreeRADIUS client project. Acceptance of those changes is outside of ISC’s control, so until those are processed, it is strongly recommended to use the FreeRADIUS client with ISC’s patches. To download and compile this version, please use the following steps:

$ git clone https://github.com/fxdupont/freeradius-client.git
$ cd freeradius-client/
$ git checkout iscdev
$ ./configure
$ make
$ sudo make install

Additional parameters may be passed to the configure script, if needed. Once installed, the FreeRADIUS client will be installed in /usr/local. This is the default path where Kea will be looking for it. It can be installed in a different directory; if so, make sure to add that path to the configure script when compiling Kea.

STEP 3: Install recent BOOST version

Kea requires a reasonably recent Boost version. Unfortunately, the version available in CentOS 7 is too old, so a newer Boost version is necessary. Furthermore, CentOS 7 has an old version of the g++ compiler that does not handle the latest Boost versions. Fortunately, Boost 1.65 meets both requirements; it is both recent enough for Kea and able to be compiled using the g++ 4.8 version in CentOS.

To download and compile Boost 1.65, please use the following commands:

$ wget -nd https://dl.bintray.com/boostorg/release/1.65.1/source/boost_1_65_1.tar.gz
$ tar zxvf boost_1_65_1.tar.gz
$ cd boost_1_65_1/
$ ./bootstrap.sh
$ ./b2 --without-python
$ sudo ./b2 install

Note that the b2 script may optionally take extra parameters; one of them specifies the destination path where the sources are to be compiled.

STEP 4: Compile and install Kea

Obtain the Kea sources either by downloading them from the git repository or extracting the tarball. Use one of those commands to obtain the Kea sources.

Choice 1: get from github

$ git clone https://github.com/isc-projects/kea

Choice 2: get a tarball and extract it

$ tar zxvf kea-1.7.1-git.tar.gz

The next step is to extract the premium Kea package that contains the RADIUS repository into the Kea sources. After the tarball is extracted, the Kea sources should have a premium/ subdirectory.

$ cd kea
$ tar zxvf ../kea-premium-radius-1.7.1-git.tar.gz

Once this is done, verify that the Kea sources look similar to this:

$ ls -l
total 952
-rw-r--r--   1 thomson  staff    6192 Apr 25 17:38 AUTHORS
-rw-r--r--   1 thomson  staff   29227 Apr 25 17:38 COPYING
-rw-r--r--   1 thomson  staff  360298 Apr 25 20:00 ChangeLog
-rw-r--r--   1 thomson  staff     645 Apr 25 17:38 INSTALL
-rw-r--r--   1 thomson  staff    5015 Apr 25 17:38 Makefile.am
-rw-r--r--   1 thomson  staff     587 Apr 25 17:38 README
-rw-r--r--   1 thomson  staff   62323 Apr 25 17:38 configure.ac
drwxr-xr-x  12 thomson  staff     408 Apr 26 19:04 doc
drwxr-xr-x   7 thomson  staff     238 Apr 25 17:38 examples
drwxr-xr-x   5 thomson  staff     170 Apr 26 19:04 ext
drwxr-xr-x   8 thomson  staff     272 Apr 26 19:04 m4macros
drwxr-xr-x  20 thomson  staff     680 Apr 26 11:22 premium
drwxr-xr-x  10 thomson  staff     340 Apr 26 19:04 src
drwxr-xr-x  14 thomson  staff     476 Apr 26 19:04 tools

The makefiles must be regenerated using autoreconf.

The next step is to configure Kea, and there are several essential steps necessary here. Running autoreconf -if is necessary to compile the premium package that contains RADIUS. Also, the –with-freeradius option is necessary to tell Kea where the FreeRADIUS client sources can be found. Also, since the non-standard Boost is used, the path to it must be specified.

$ autoreconf -i
$ ./configure --with-freeradius=/path/to/freeradius --with-boost-include=/path/to/boost --with-boost-lib-dir=/path/to/boost/state/lib

For example, assuming the FreeRADIUS client was installed in the default directory (/usr/local) and the Boost 1.65 sources were compiled in /home/thomson/devel/boost1_65_1, the configure path should look as follows:

$ ./configure --with-freeradius=/usr/local \
      --with-boost-include=/home/thomson/devel/boost_1_65_1 \
      --with-boost-lib-dir=/home/thomson/devel/boost_1_65_1/stage/lib

After some checks, the configure script should print a report similar to the following:

       Kea source configure results:
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Package:
  Name:              kea
  Version:           1.7.1-git
  Extended version:  1.7.1-git (tarball)
  OS Family:         Linux

  Hooks directory:   /usr/local/lib/kea/hooks
  Premium hooks:     yes
  Included Hooks:    forensic_log flex_id host_cmds subnet_cmds radius host_cache

C++ Compiler:
  CXX:             g++ --std=c++11
  CXX_VERSION:     g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
  CXX_STANDARD:    201103
  DEFS:            -DHAVE_CONFIG_H
  CPPFLAGS:         -DOS_LINUX  -DBOOST_ASIO_HEADER_ONLY
  CXXFLAGS:        -g -O2
  LDFLAGS:          -lpthread
  KEA_CXXFLAGS:     -Wall -Wextra -Wnon-virtual-dtor -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare -pthread -Wno-missing-field-initializers -fPIC

Python:
  PYTHON_VERSION:  not needed (because kea-shell is disabled)

Boost:
  BOOST_VERSION:   1.65.1
  BOOST_INCLUDES:  -I/home/thomson/devel/boost_1_65_1
  BOOST_LIBS:      -L/home/thomson/devel/boost_1_65_1/stage/lib  -lboost_system

OpenSSL:
  CRYPTO_VERSION:  OpenSSL 1.0.2k  26 Jan 2017
  CRYPTO_CFLAGS:
  CRYPTO_INCLUDES:
  CRYPTO_LDFLAGS:
  CRYPTO_LIBS:     -lcrypto

Botan: no

Log4cplus:
  LOG4CPLUS_VERSION:  1.1.3
  LOG4CPLUS_INCLUDES: -I/usr/include
  LOG4CPLUS_LIBS:     -L/usr/lib -L/usr/lib64 -llog4cplus

Flex/bison:
  FLEX:  flex
  BISON: bison -y

MySQL:
  no

PostgreSQL:
  no

Cassandra CQL:
  no
Google Test:
  no
Google Benchmark:
  no

FreeRADIUS client:
  FREERADIUS_INCLUDE:    -I/usr/local/include
  FREERADIUS_LIB:        -L/usr/local/lib -lfreeradius-client
  FREERADIUS_DICTIONARY: /usr/local/etc/radiusclient/dictionary

Developer:
  Enable Debugging:       no
  Google Tests:           no
  Valgrind:               not found
  C++ Code Coverage:      no
  Logger checks:          no
  Generate Documentation: no
  Parser Generation:      no
  Kea-shell:              no
  Perfdhcp:               no

Please make sure that the compilation includes the following:

  • RADIUS listed in Included Hooks;
  • FreeRADIUS client directories printed and pointing to the right directories;
  • Boost version at least 1.65.1. The versions available in CentOS 7 (1.48 and and 1.53) are too old.

Once the configuration is complete, compile Kea using make. If the system has more than one core, using the “-j N” option is recommended to speed up the build.

$ make -j5
$ sudo make install

15.15.2. RADIUS Hook Configuration

The RADIUS hook is a library that has to be loaded by either DHCPv4 or DHCPv6 Kea servers. Unlike some other available hooks libraries, this one takes many parameters. For example, this configuration could be used:

"Dhcp4": {

# Your regular DHCPv4 configuration parameters here.

"hooks-libraries": [
{
    # Note that RADIUS requires host-cache for proper operation,
    # so that library is loaded as well.
    "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so"
},
{
    "library": "/usr/local/lib/kea/hooks/libdhc_radius.so",
    "parameters": {

        # Specify where FreeRADIUS dictionary could be located
        "dictionary": "/usr/local/etc/freeradius/dictionary",

        # Specify which address to use to communicate with RADIUS servers
        "bindaddr": "*",

        # more RADIUS parameters here
    }
} ]

RADIUS is a complicated environment. As such, it is not feasible to provide a default configuration that works for everyone. However, we do have one example that showcases some of the more common features. Please see doc/examples/kea4/hooks-radius.json in the Kea sources.

The RADIUS hook library supports the following global configuration flags, which correspond to FreeRADIUS client library options:

  • bindaddr (default “*”) - specifies the address to be used by the hooks library in communication with RADIUS servers. The “*” special value tells the kernel to choose the address.
  • canonical-mac-address (default false) - specifies whether MAC addresses in attributes follow the canonical RADIUS format (lowercase pairs of hexadecimal digits separated by ‘-‘).
  • client-id-pop0 (default false) - used with flex-id, removes the leading zero (or pair of zeroes in DHCPv6) type in client-id (aka duid in DHCPv6). Implied by client-id-printable.
  • client-id-printable (default false) - checks whether the client-id/duid content is printable and uses it as is instead of in hexadecimal. Implies client-id-pop0 and extract-duid as 0 and 255 are not printable.
  • deadtime (default 0) is a mechanism to try unresponsive servers after responsive servers. Its value specifies the number of seconds after which a server is considered not to have answered, so 0 disables the mechanism. As the asynchronous communication does not use locks or atomics, it is recommended that you do not use this feature when running in this mode.
  • dictionary (default set by configure at build time) - is the attribute and value dictionary. Note that it is a critical parameter.
  • extract-duid (default true) - extracts the embedded duid from an RFC 4361-compliant DHCPv4 client-id. Implied by client-id-printable.
  • identifier-type4 (default client-id) - specifies the identifier type to build the User-Name attribute. It should be the same as the host identifier, and when the flex-id hook library is used the replace-client-id must be set to true; client-id will be used with client-id-pop0.
  • identifier-type6 (default duid) - specifies the identifier type to build the User-Name attribute. It should be the same as the host identifier, and when the flex-id hook library is used the replace-client-id must be set to true; duid will be used with client-id-pop0.
  • realm (default “”) - is the default realm.
  • reselect-subnet-address (default false) - uses the Kea reserved address/RADIUS Framed-IP-Address or Framed-IPv6-Address to reselect subnets where the address is not in the subnet range.
  • reselect-subnet-pool (default false) - uses the Kea client-class/RADIUS Frame-Pool to reselect subnets where no available pool can be found.
  • retries (default 3) - is the number of retries before trying the next server. Note that it is not supported for asynchronous communication.
  • session-history (default “”) - is the name of the file providing persistent storage for accounting session history.
  • timeout (default 10) - is the number of seconds during which a response is awaited.

When reselect-subnet-pool or reselect-subnet-address is set to true at the reception of RADIUS Access-Accept, the selected subnet is checked against the client-class name or the reserved address; if it does not match, another subnet is selected among matching subnets.

Two services are supported:

  • access - the authentication service.
  • accounting - the accounting service.

Configuration of services is divided into two parts:

  • Servers that define RADIUS servers that the library is expected to contact. Each server may have the following items specified:

    • name - specifies the IP address of the server (it is possible to use a name which will be resolved, but it is not recommended).
    • port (default RADIUS authentication or accounting service) - specifies the UDP port of the server. Note that the FreeRADIUS client library by default uses ports 1812 (authorization) and 1813 (accounting). Some server implementations use 1645 (authorization) and 1646 (accounting). The “port” parameter may be used to adjust as needed.
    • secret - authenticates messages.

    There may be up to eight servers. Note that when no server is specified, the service is disabled.

  • Attributes which define additional information that the Kea server will send to a RADIUS server. The parameter must be identified either by a name or type. Its value can be specified in one of three possible ways: data (which defines a plain text value), raw (which defines the value in hex), or expr (which defines an expression, which will be evaluated for each incoming packet independently).

    • name - the name of the attribute.
    • type - the type of the attribute. Either the type or the name must be provided, and the attribute must be defined in the dictionary.
    • data - the first of three ways to specify the attribute content. The data entry is parsed by the FreeRADIUS library, so values defined in the dictionary of the attribute may be used.
    • raw - the second of three ways to specify the attribute content; it specifies the content in hexadecimal. Note that it does not work with integer-content attributes (date, integer, and IPv4 address); a string-content attribute (string, IPv6 address, and IPv6 prefix) is required.
    • expr - the last way to specify the attribute content. It specifies an evaluation expression which must return a not-empty string when evaluated with the DHCP query packet. Currently this is restricted to the access service.

For example, to specify a single access server available on localhost that uses “xyz123” as a secret, and tell Kea to send three additional attributes (Password, Connect-Info, and Configuration-Token), the following snippet could be used:

"parameters": {

    # Other RADIUS parameters here

    "access": {

        # This starts the list of access servers
        "servers": [
        {
            # These are parameters for the first (and only) access server
            "name": "127.0.0.1",
            "port": 1812,
            "secret": "xyz123"
        }
        # Additional access servers could be specified here
        ],

        # This defines a list of additional attributes Kea will send to each
        # access server in Access-Request.
        "attributes": [
        {
            # This attribute is identified by name (must be present in the
            # dictionary) and has static value (i.e. the same value will be
            # sent to every server for every packet)
            "name": "Password",
            "data": "mysecretpassword"
        },
        {
            # It is also possible to specify an attribute using its type,
            # rather than a name. 77 is Connect-Info. The value is specified
            # using hex. Again, this is a static value. It will be sent the
            # same for every packet and to every server.
            "type": 77,
            "raw": "65666a6a71"
        },
        {
            # This example shows how an expression can be used to send dynamic
            # value. The expression (see Section 13) may take any value from
            # the incoming packet or even its metadata (e.g. the interface
            # it was received over from)
            "name": "Configuration-Token",
            "expr": "hexstring(pkt4.mac,':')"
        }
        ] # End of attributes
    } # End of access

    # Accounting parameters.
    "accounting": {
        # This starts the list of accounting servers
        "servers": [
        {
            # These are parameters for the first (and only) accounting server
            "name": "127.0.0.1",
            "port": 1813,
            "secret": "sekret"
        }
        # Additional accounting servers could be specified here
        ]
    }

}

For the RADIUS hooks library to operate properly in DHCPv4, the Host Cache hooks library must also be loaded. The reason for this is somewhat complex. In a typical deployment, the DHCP clients send their packets via DHCP relay which inserts certain Relay Agent Information options, such as circuit-id or remote-id. The values of those options are then used by the Kea DHCP server to formulate the necessary attributes in the Access-Request message sent to the RADIUS server. However, once the DHCP client gets its address, it then renews by sending packets directly to the DHCP server. As a result, the relays are not able to insert their RAI options, and the DHCP server cannot send the Access-Request queries to the RADIUS server by using just the information from incoming packets. Kea needs to keep the information received during the initial Discover/Offer exchanges and use it again later when sending accounting messages.

This mechanism is implemented based on user context in host reservations. (See User Contexts for details.) The host cache mechanism allows the information retrieved by RADIUS to be stored and later used for sending accounting and access queries to the RADIUS server. In other words, the host-cache mechanism is mandatory, unless administrators do not want RADIUS communication for messages other than Discover and the first Request from each client.

15.16. host_cache: Caching Host Reservations

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

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

In principle, this hooks library can be used with any backend that may introduce performance degradation (MySQL, PostgreSQL, Cassandra, or RADIUS). Host Cache must be loaded for the RADIUS accounting mechanism to work.

The Host Cache hooks library is currently 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 hooks library can be loaded the same way as any other hooks library; for example, this configuration could be used:

"Dhcp4": {

# Your regular DHCPv4 configuration parameters here.

"hooks-libraries": [
{
    "library": "/usr/local/lib/kea/hooks/libdhc_host_cache.so",
    "parameters": {

        # Tells Kea to never cache more than 1000 hosts.
        "maximum": 1000

    }
} ]

Once loaded, the Host Cache hooks 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.

15.16.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 will remove 1000 hosts. To delete all cached hosts, please use cache-clear instead. The hosts are stored in FIFO (first-in, first-out) order, so the oldest entries are always removed.

15.16.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 will remove all hosts. To delete only a certain number of cached hosts, please use cache-flush instead.

15.16.3. The cache-size Command

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

{
    "command": "cache-size"
}

15.16.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 will then be 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.

15.16.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 will store 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.

15.16.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 will return all the cached hosts. Note that the response may be large.

15.16.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 will return all the cached hosts with the given hardware address.

15.16.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 Reservation in DHCPv4 or Host Reservation in DHCPv6), with one difference: the subnet-id value must be specified explicitly.

An example command that will 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 that will 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
    }
}

15.16.9. The cache-remove Command

Sometimes it is useful to remove a single entry from the host cache. A good use case is a situation where the device is up, 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 perhaps been upgraded to better service), the information in the backend (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 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
    }
}

15.17. User Contexts

Hooks libraries can have their own configuration parameters, which is convenient if the parameter applies to the whole library. However, sometimes it is very 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 are 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 hooks 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. The pretty print of a configuration does the opposite operation and puts “comment” entries at the beginning of maps, as that seems to be the common usage.

As of Kea 1.3, the structures that allow user contexts are pools of all types (addresses and prefixes) and subnets. Kea 1.4 extended user context support to the global scope, interfaces config, shared networks, subnets, client classes, option datas and definitions, host reservations, control socket, dhcp ddns, loggers and server id. These are supported in both DHCPv4 and DHCPv6, with the exception of server id which is DHCPv6 only.