Kea DHCP

(Kea lease allocation, client classification and option assignment)

Carsten Strotmann and the ISC KEA Team

Created: 2020-10-14 Wed 10:40

About this Webinar

  • Lease allocation
  • Client classification
  • DHCP options
  • DHCP reservations
  • Shared subnets
  • Questions & Answers

Lease allocation

Kea lease allocation (simplified)

kea-lease-allocation.png

(without shared-networks or reservations)

Kea lease allocation details

kea-lease-allocation-02.png

Kea lease allocation details

  • When searching for a new lease
    • Kea 1.8 iterates over all subnets by subnet-id
    • Previous versions iterated over subnets in configuration file order

Client classification

DHCP client classes

  • Kea DHCP can assign one or more client classes to client requests
  • Depending on the client classes, different DHCP information can be send to the client:
    • DHCP-Options
    • IP-Addresses
    • BOOTP-Parameter inside DHCP responses
  • Kea can select from multiple subnets / pools with the help of client classes

DHCP client classes

  • Client classes can be build from various DHCP identifier
    • information from the client host
    • information from the DHCP relay
    • information from the DHCP packet path towards the DHCP server
  • Client classification examines the incoming DHCP packet's contents and selects one or more class(es) based on configuration criteria

Where do DHCP identifiers come from (1/4)

DHCP-identifiers-01.png

Where do DHCP identifiers come from (2/4)

DHCP-identifiers-02.png

Where do DHCP identifiers come from (3/4)

DHCP-identifiers-03.png

Where do DHCP identifiers come from (4/4)

DHCP-identifiers-04.png

Automatic vendor classing

  • Kea DHCP automatically assigns a vendor client class if a vendor option (DHCPv4 option 60 or DHCPv6 option 16) is set in the DHCP request
  • the content of that option is prepended with VENDOR_CLASS_ and the result is interpreted as a class
    • For example, modern cable modems send this option with value docsis3.0, so the packet belongs to class VENDOR_CLASS_docsis3.0

Automatic vendor classing example

  • example subnet selection based on the vendor option
    • a client must be in any of the client classes listed to get a lease from this subnet
    • The vendor options used in this exercise are examples and not the real-world vendor option values:
        "shared-networks": [
            {
                "name": "kea-net01",
                "relay": { "ip-address": "192.0.2.1" },
                "subnet4": [
                    {
                        "subnet": "192.0.2.0/24",
                        "client-class": "VENDOR_CLASS_windowsCE", # <-- Windows CE Clients will get
			                                          # an IP from this subnet
                        "option-data": [{
                                "name": "routers", "data": "192.0.2.1" }],
                        "pools": [{
                                "pool": "192.0.2.60 - 192.0.2.220" }]
                    },
                    {
                        "subnet": "10.0.0.0/24",
                        "client-class": "VENDOR_CLASS_fedoraLinux", # <-- Fedora-Linux Clients will 
			                                            # get an IP from this subnet
                        "option-data": [
[...]

The KNOWN and UNKNOWN classes

  • Kea automatically assigns classes based on host reservations
    • all clients with a host reservation will be in the KNOWN class
    • all client without reservation will be in the UNKNOWN class
  • for example, these classes can be used to separate guests from staff clients
{
    "client-classes": [{
            "name": "dependent-class",
            "test": "member('KNOWN')",
            "only-if-required": true
    }]
}

Dynamic client classing based on expressions

  • DHCP requests can be assigned one or more client classes
    • Expressions can be used to extract information from the DHCP request message
    • Logical and conditional expressions can be used to assign classes to the DHCP request
  • List of available expressions
    https://kea.readthedocs.io/en/kea-1.8.0/arm/classify.html#using-expressions-in-classification

Dynamic client classing based on expressions

Kea-list-of-expressions.png

Client classification example (1/2)

  • configuration for dynamic client classing based on the vendor option (Option 60) content
"Dhcp4": {
   "client-classes": [
        {   "name": "windows",
            "test": "substring(option[60].hex,0,3) == 'win'",
            "option-data": [{
                    "name": "domain-name", "data": "win.example.com" }]
        },
        {   "name": "other",
            "test": "not(substring(option[60].hex,0,3) == 'win')",
            "option-data": [{
                    "name": "domain-name", "data": "other.example.com" }]
        }
    ],
[...]

Client classification example (2/2)

  • the client class is used to select a subnet inside a shared network
    • windows clients get IP addresses from the 1st subnet
    • client with other operating systems get IP addresses from the 2nd subnet
        "shared-networks": [
            {
                "name": "kea-lab01",
                "relay": { "ip-address": "192.0.2.1" },
                "subnet4": [
                    {
                        "subnet": "192.0.2.0/24",
                        "client-class": "windows", # <-- all Windows Clients will 
			                           # get IP addresses from this subnet
                        "option-data": [{
                                "name": "routers", "data": "192.0.2.1" }],
                        "pools": [{
                                "pool": "192.0.2.60 - 192.0.2.250" }]
                    },
                    {
                        "subnet": "10.0.0.0/24",
                        "client-class": "other", # <-- non Windows Clients will 
			                         # get IP addresses from this subnet
                        "option-data": [
[...]

Classification via hooks

  • Client classification via complex expressions can hurt the DHCP server performance
  • Alternative: writing a custom hook for client classification

Debugging client classing (1/3)

  • to debug client classing based on expressions, enable debug logging inside the Kea DHCP server
  • quick option: start KEA DHCP4 in debug mode from the command line. This will automatically enable the highest debugging level
    • on a busy server, this will create too much debug information (see next slide for an alternative)
[kea-server]# systemctl stop kea-dhcp4
[kea-server]# kea-dhcp4 -d -c /etc/kea/kea-dhcp4.conf

Debugging client classing (2/3)

  • Alternative: enable the special kea-dhcp4.eval or kea-dhcp6.eval debug logger in the Kea configuration file
"Logging": {
    "loggers": [ {
        "name": "kea-dhcp4.eval",
        "output_options": [ {
            "output": "/var/log/kea-dhcp4-eval.log"
        } ],
        "severity": "DEBUG",
        "debuglevel": 55
    } ]
}

Debugging client classing (3/3)

  • watch for the test evaluation results in the Kea Eval DHCP4 log file
[kea-server]# tail -f /var/log/kea-dhcp4-eval.log

DHCP options

DHCP options

  • DHCP options can be configured in different scopes in the Kea configuration
    • global
    • class
    • subnet
    • pools
    • reservations

Global DHCP options (1/2)

"Dhcp4": {
    "option-data": [{
	   "name": "domain-name-servers",
	   "code": 6,
	   "space": "dhcp4",
	   "csv-format": true,
	   "data": "192.0.2.1, 192.0.2.2"
	},
	...
    ]}

Global DHCP options (2/2)

  • if the default values are used, the fields code, space and csv-format can be obmitted
"Dhcp4": {
    "option-data": [{
           "name": "domain-name-servers",
           "data": "192.0.2.1, 192.0.2.2"
        },
        ...
    ]}

Subnet specific DHCP option

[...]
   "subnet4": [ {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.100 - 192.0.2.200" } ],
            "option-data": [{
                    "name": "routers",
                    "data": "192.0.2.1" },
                {
                    "name": "domain-name",
                    "data": "a.example.com" }
            ]},
[...]

Client class options

"client-classes": [{
        "name": "Zimbutsio-Server",
        "test": "option[vendor-class-identifier].text == 'Zimbutsio'",
        "option-data": [ {
                "name": "log-servers",
                "data": "192.0.2.42"
            }]
    }],
[...]

Defining custom DHCPv4 options (1/2)

  • sometimes it is required to define custom DHCP options that are not part pf the DHCP standards.
    • These can be vendor specific options, or new DHCP options that are not yet implemented in Kea DHCP

Defining custom DHCPv4 options (2/2)

{
    "Dhcp4": {
        "option-def": [{
                "name": "my-message",
                "code": 234,
                "type": "string",
                "array": false,
                "record-types": "",
                "space": "dhcp4",
                "encapsulate": "" }],
        "option-data": [{
                "name": "my-message",
                "space": "dhcp4",
                "csv-format": true,
                "data": "Hello World" }],
[...]

Option assignment order

DHCP-Option-Order.png

(Client-class options are assigned in the order in which the client classes are evaluated (specified in the configuration) )

DHCP reservations

Why DHCP reservations

  • Security policies
  • stable addressing (server)
  • IP bound licenses
  • captive portal (KNOWN vs. UNKNOWN clients)

DHCP reservations

  • Kea DHCP supports reservations of client leases based on
    • hardware interface address (MAC-Address)
    • DHCP Unique ID (DUID)
    • Relay-Circut-ID (DHCPv4)
    • Client-ID / Hostname (DHCPv4)
    • flex.id

DHCP reservation parameter

  • Alongside IP-Address leases, reservations can also reserve a number of DHCP parameters for a client
    • hostname
    • DHCP options
    • reservation-client-classes
    • boot-file-name (BOOTP/DHCPv4)
    • next-server (BOOTP/DHCPv4)
    • server-hostname (BOOTP/DHCPv4)

Global vs. Subnet reservations

  • DHCP reservations can optionally be defined on a global scope
    • global reservations can be used to assign a fixed hostname or other options to a client
    • Kea does not prevent the definition of DHCP parameters on the global level that are only useful in an subnet scope (like IP address or IPv4 default route). Be careful!
  • The common case is to have reservations in the subnet or shared-subnet scope
    • Kea 1.9 will allow for reservations to be defined on a global and subnet level

Example of global reservation

"Dhcp4:" {
    # This specifies global reservations. They will apply to all subnets that
    # have global reservations enabled.

    "reservations": [
    {  "hw-address": "aa:bb:cc:dd:ee:ff",  "hostname": "hw-host-dynamic"  },
    {  "hw-address": "01:02:03:04:05:06",  "hostname": "hw-host-fixed",  "ip-address": "192.0.1.77"  }, # risky!
    {  "circuit-id": "'office042'",        "hostname": "circuit-id-host"  },
[...]

in-pool vs out-of-pool reservations

Dynamically manage DHCP reservations

  • Small Kea deployments (small = a few hundred client machines) can have the DHCP reservations inside the Kea configuration file
  • Larger deployments might want to change the DHCP reservations dynamically and programatically via the API
    • The Host Commands hook (part of the Premium hooks package) adds a number of new commands to Kea used to query and manipulate host reservations

Dynamically manage DHCP reservations

  • the Host Commands hook requires a database (-> next webinar) for storing the host reservations
  • If reservations are specified in both file and database, file reservations take precedence over the ones in the database.

Host Commands

Command Description
reservation-add add a new reservation to the Kea DB
reservation-get-all get all reservation information (can be huge)
reservation-get get information on a single reservation (by address or identifier)
reservation-get-page get all reservation information from a subnet by pages (used for GUI display)
reservation-get-by-hostname get the reservation information for one host by its hostname
reservation-get-by-id get the reservation information for one host by its identifier (global, since 1.9.0)
reservation-del delete a reservation from the database

Example command file to add a reservation (1/2)

  • this command snippet can be used to create a new reservation inside the Kea Host database
$ cat reservation-add.json
{
  "command": "reservation-add",
  "service": [ "dhcp6" ],
  "arguments": {
    "reservation": {
      "duid": "01:02:03:04:05:06:07:08:09:0A",
      "hostname": "foo.example.com",
      "ip-addresses": [ "2001:db8:1::1" ],
      "option-data": [{
          "data": "4491",
          "name": "vendor-opts"
        },{
          "data": "3000:1::234",
          "name": "tftp-servers",
          "space": "vendor-4491"
        }],
      "subnet-id": 1
    }
  }
}

Example command file to add a reservation (2/2)

  • the curl command can be used to send the request towards the Kea API
$ curl -s -X POST -H "Content-Type: application/json" \
  -d @reservation-add.json http://127.0.0.1:8000/ | jq
[
  {
    "result": 0,
    "text": "Host added."
  }
]

Example command file retrieving all reservations

  • this command snippet can be used to retrieve all reservations from the Kea Host database
$ cat reservation-get-all.json
{
  "service": [
    "dhcp6"
  ],
  "command": "reservation-get-all",
  "arguments": {
    "subnet-id": 1
  }
}
$ curl -s -X POST -H "Content-Type: application/json" \
  -d @reservation-get-all.json http://127.0.0.1:8000/ | jq

Client classing in reservations

  • clients can be associated to a client-class using a reservation (using the Hardware-Address, DUID, Client-ID, Relay-ID)
[...] 
  "subnet4": [
  {
     "subnet": "10.0.0.0/24",
     "pools": [ { "pool": "10.0.0.10-10.0.0.200" } ], 
     "reservations": [{
          "hw-address": "01:02:03:04:05:06", 
          "client-classes": [ "windows", "staff" ]
      }]
  }],
[...]

Performance tuning DHCP reservations (1/4)

  • Kea DHCP must check for every lease request for conflicts with reservations. This can slow down the DHCP lease assignment process
    • in some cases, where reservations are not in use or used only in certain scopes, some of these checks can be disabled with the reservation-mode configuration parameter
    • the parameter can be specified at global, subnet, and shared-network levels.
"Dhcp4": {
    "subnet4": [{
        "subnet": "192.0.2.0/24",
        "reservation-mode": "disabled",
        ...
    }]
}

Performance tuning DHCP reservations (2/4)

reservation-mode description
all reservations can be on global, subnet or inside pool scope, all checks enabled
out-of-pool reservations in subnets are always outside the pool
global only global reservations allowed, not subnet/pool reservations
disabled(*) host reservation support is disabled, no checks for collisions

(*) the best performance is achieved when host reservations are disabled (if no reservations are used). In that case Kea can skip all the checks and lookups.

Performance tuning DHCP reservations (3/4)

  • Kea currently supports four types of identifiers:
    • hw-address
    • duid
    • client-id
    • circuit-id
    • flex-id
  • For each incoming packet, Kea has to extract each identifier type and then query the database to see if there is a reservation by this particular identifier.

Performance tuning DHCP reservations (4/4)

  • A parameter called host-reservation-identifiers takes a list of identifier types that Kea will check
    • For best performance the number of identifier types should be kept to a minimum, ideally one.
"host-reservation-identifiers": [ "circuit-id", "hw-address" ],
"subnet4": [{
        "subnet": "192.0.2.0/24",
        ...
    }]

Shared subnets

Shared subnets

  • a shared subnet is a physical subnet with multiple IP networks
    • one shared subnet definition can contain two or more subnet definitions
    • options can be defined on the shared-network, subnet and pool level
    • without client classification, Kea might choose an IP address from any pool of all subnets inside the shared network

When to use Shared Subnets

  • Shared Subnets are adding complexity to a DHCP server configuration and should only be used if there is a good use case
    • shared subnet are sometimes created if a larger number of IP addresses are needed in a network, but because of IPv4 address shortage no continuous range of IPv4 addresses are available
    • another use case of shared subnets is a network where addresses from different IPv4 subnets (and possibly different network configuration) should be given to different network devices

Kea configuration shared subnet example

[...]
        "shared-networks": [
            {
                "name": "kea-lab01",
                "relay": { "ip-address": "192.0.2.1" },
                "subnet4": [{
                        "subnet": "192.0.2.0/24",
                        "option-data": [
                            { "name": "routers", "data": "192.0.2.1" }],
                        "pools": [{ "pool": "192.0.2.20 - 192.0.2.190" }]
                    }, {
                        "subnet": "10.0.0.0/24",
                        "option-data": [
                            { "name": "routers", "data": "10.0.0.1" }],
                        "pools": [{ "pool": "10.0.0.10 - 10.0.0.200"  }]
                    }]
	],
[...]

Next Webinars

  • 28th October - Kea DHCP - High Availability and Database Backends
  • 18th November - Kea DHCP - Monitoring, Logging, and Stork
  • 2nd December - Kea DHCP - Migrating to Kea from ISC DHCP

Resources

Questions and Answers

Bonus: Kea configuration in YAML

JSON and YAML

Convert JSON to YAML

  • The yq tool can be used to convert if JSON file (or JSON coming from STDIN via shell pipe) into YAML
$ yq r --prettyPrint add-reservation.json
service:
  - dhcp6
command: reservation-add
arguments:
  reservation:
    subnet-id: 1
    duid: 01:02:03:04:05:06:07:08:09:0A
    ip-addresses:
      - 2001:db8:1::1
    hostname: foo.example.com
    option-data:
      - name: vendor-opts
        data: "4491"
      - name: tftp-servers
        space: vendor-4491
        data: 3000:1::234

Convert YAML to JSON

  • yq also supports the reverse, converting YAML back to JSON
# yq r --prettyPrint -j add-reservation.yaml
{
  "arguments": {
    "reservation": {
      "duid": "01:02:03:04:05:06:07:08:09:0A",
      "hostname": "foo.example.com",
      "ip-addresses": [
        "2001:db8:1::1"
      ],
      "option-data": [
        {
          "data": "4491",
          "name": "vendor-opts"
        },
        {
          "data": "3000:1::234",
          "name": "tftp-servers",
          "space": "vendor-4491"
        }
      ],
      "subnet-id": 1
    }
  },
  "command": "reservation-add",
  "service": [
    "dhcp6"
  ]
}

Kea-cmd script

  • a simple shell script kea-cmd can aid to convert YAML command-files into JSON and send them to the DHCP server via the Kea control channel
#!/bin/sh
curl -s -X POST -H "Content-Type: application/json" \
  -d "$(yq r -j ${1})" http://127.0.0.1:8000/ | yq r -P -

Example use of kea-cmd

successful command

# kea-cmd add-reservation.yaml
- result: 0
  text: Host added.

error case

# kea-cmd add-reservation.yaml
- result: 1
  text: specified reservation '2001:db8:1:cafe::1' is not matching the IPv6 subnet prefix '2001:db8:1::/64'

Example command file retrieving all reservations

  • these command snippets can be used to retrieve all reservations from the Kea Host database
  • YAML
service:
  - dhcp6
command: reservation-get-all
arguments:
    subnet-id: 1
  • JSON
{
  "service": [
    "dhcp6"
  ],
  "command": "reservation-get-all",
  "arguments": {
    "subnet-id": 1
  }
}