dhcp4.dox 16.9 KB
Newer Older
1
// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7 8 9
/**
 @page dhcp4 DHCPv4 Server Component

10 11 12 13 14 15 16 17 18 19 20 21 22 23
Kea includes the "kea-dhcp4" component, which is the DHCPv4 server
implementation. This component is built around the
@ref isc::dhcp::Dhcpv4Srv class which controls all major operations
performed by the server such as: DHCP messages processing, callouts
execution for many hook points, FQDN processing and interactions with the
"kea-dhcp-ddns" component, lease allocation, system signals handling etc.

The "kea-dhcp4" component requires linking with many different libraries
to obtain access to common functions like: interfaces and sockets
management, configuration parsing, leases management and allocation,
hooks infrastructure, statistics management etc.

The following sections walk through some of the details of the "kea-dhcp4"
component implementation.
24

25
@section dhcpv4ConfigParser Configuration Parser in DHCPv4
26

27 28 29 30 31
The common configuration parsers for the DHCP servers are located in the
src/lib/dhcpsrv/parsers/ directory. Parsers specific to the DHCPv4 component
are located in the src/bin/dhcp4/json_config_parser.cc. These parsers derive
from the common configuration parsers and customize their behavior. For
example: the @c Subnet4ConfigParser is used to parse parameters
32
describing a single subnet. It derives from the @c
33
isc::dhcp::SubnetConfigParser, which implements the common base for both
34
DHCPv4 and DHCPv6 subnets. The @ref Subnet4ConfigParser
35 36 37 38 39 40 41 42
implements the @c initSubnet abstract method, which creates an instance of
the DHCPv4 subnet. This method is invoked by the parent class.

Some parsers for the DHCPv4 server derive from the isc::dhcp::DhcpConfigParser
class directly. This is an abstract class, defining a basic interface for
all configuration parsers. All DHCPv4 parsers deriving from this class
directly have their entire implementation in the
src/bin/dhcp4/json_config_parser.cc.
43

44
@section dhcpv4ConfigInherit DHCPv4 configuration inheritance
45

46
One notable useful feature of DHCP configuration is its parameter inheritance.
47
For example, the "renew-timer" value may be specified at a global scope and it then
48 49 50 51
applies to all subnets. However, some subnets may have it overwritten with subnet
specific values that takes precedence over global values that are considered
defaults. The parameters inheritance is implemented by means of the "global
context". The global context is represented by the @ref isc::dhcp::ParserContext
52
class and it holds pointers to storage of different kinds, e.g. text parameters,
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
numeric parameters etc. When the server is parsing the top level configuration
parameters it passes pointers to the storages of the appropriate kind, to the
parsers being invoked to parse the global values. Parsers will store the
parsed values into these storages. Once the global parameters are stored in the
global context, the parsers for the nested configuration parameters are invoked.
These parsers check the presence of the parameters overriding the values of
the global parameters. If a value is not present, the values from the global
context is used.

A good example of inheritance is the implementation of the @ref
isc::dhcp::SubnetConfigParser. The @c getParam method is used throughout the
class to obtain values of the parameters defining a subnet. It first checks
if the specific value is present in the local values storage. If it is not
present, it uses the value from the global context.

 @code
 isc::dhcp::Triplet<uint32_t>
 SubnetConfigParser::getParam(const std::string& name) {
     uint32_t value = 0;
     try {
         // look for local value
          value = uint32_values_->getParam(name);
     } catch (const DhcpConfigError &) {
         try {
             // no local, use global value
             value = global_context_->uint32_values_->getParam(name);
         } catch (const DhcpConfigError &) {
             isc_throw(DhcpConfigError, "Mandatory parameter " << name
                       << " missing (no global default and no subnet-"
                       << "specific value)");
         }
     }

     return (Triplet<uint32_t>(value));
}
@endcode

Note that if the value is neither present in the local storage nor in the global
91
context an error is signaled.
92 93 94 95 96 97 98 99

Parameter inheritance is done once, during the reconfiguration phase.
Reconfigurations are rare, so extra logic here is not a problem. On the other
hand, values of those parameters may be used thousands times per second, so
access to these parameters must be as efficient as possible. In fact,
currently the code has to only call @c Subnet4::getT1(), regardless if the
"renew-timer" has been specified as a global or subnet specific value.

100
Debugging a configuration parser may be confusing. Therefore there is a special
101 102 103
class called DebugParser. It does not configure anything, but just
accepts any parameter of any type. If requested to commit configuration, it will
print out received parameter name and its value. This class is not currently used,
104
but it is convenient to have it every time a new parameter is added to the DHCP
105
configuration. For that purpose it should be left in the code.
106

107 108
@section dhcpv4OptionsParse Custom functions to parse message options

109 110 111 112 113 114
The DHCPv4 server implementation provides a generic support to define option
formats and set option values. A number of options formats have been defined
for standard options in libdhcp++. However, the formats for vendor specific
options are dynamically configured by the server's administrator and thus can't
be stored in libdhcp++. Such option formats are stored in the
@ref isc::dhcp::CfgMgr. The libdhcp++ provides functions for recursive parsing
115 116
of options which may be encapsulated by other options up to any level of
encapsulation, but these functions are unaware of the option formats defined
117 118
in the @ref isc::dhcp::CfgMgr because they belong to a different library.
Therefore, the generic functions @ref isc::dhcp::LibDHCP::unpackOptions4 and
119 120
@ref isc::dhcp::LibDHCP::unpackOptions6 are only useful to parse standard
options whose definitions are provided in the libdhcp++. In order to overcome
121
this problem a callback mechanism has been implemented in @c Option and @c Pkt4
122
classes. By installing a callback function on an instance of @c Pkt4, the
123 124
server may provide a custom implementation of the options parsing algorithm.
This callback function will take precedence over the @c LibDHCP::unpackOptions4
125
and @c LibDHCP::unpackOptions6 functions. With this approach, the callback is
126 127 128
implemented within the context of the server and it has access to all objects
which define its configuration (including dynamically created option
definitions).
129

130
@section dhcpv4DDNSIntegration DHCPv4 Server Support for the Dynamic DNS Updates
131 132
The DHCPv4 server supports processing of the DHCPv4 Client FQDN option (RFC4702)
and the DHCPv4 Host Name option (RFC2132). A client may send one of these options
133 134 135 136 137 138
to convey its fully qualified or partial name to the server. The server may use
this name to perform DNS updates for the client. If server receives both options
in the same message, the DHCPv4 Client FQDN %Option is processed and the Host
Name option is ignored. If only Host Name Option is present in the client's
message, it is used to update DNS.

139
The server may be configured to use a different name to perform DNS update for the
140 141 142 143
client. In this case the server will return one of the DHCPv4 Client FQDN or
Host Name %Option in its response with the name which was selected for the
client to indicate that this name will be used to perform DNS update.

144 145
The kea-dhcp-ddns process is responsible for the actual communication with the
DNS, i.e. to send DNS update messages. The kea-dhcp4 module is responsible for
146
generating @ref isc::dhcp_ddns::NameChangeRequest and sending it to
147
the kea-dhcp-ddns module. The @ref isc::dhcp_ddns::NameChangeRequest object
148
represents changes to the DNS bindings, related to acquisition, renewal or
149
release of the DHCP lease. The kea-dhcp4 module implements the simple FIFO queue
150 151 152 153 154 155
of the NameChangeRequest objects. The module logic, which processes the incoming
DHCPv4 Client FQDN and Host Name Options puts these requests into the FIFO queue.

@todo Currently the FIFO queue is not processed after the NameChangeRequests are
generated and added to it. In the future implementation steps it is planned to
create a code which will check if there are any outstanding requests in the queue
156
and send them to the kea-dhcp-ddns module when server is idle waiting for DHCP
157 158 159 160 161 162 163
messages.

When client gets an address from the server, a DHCPv4 server may generate 0, 1
or 2 NameChangeRequests during single message processing. Server generates no
NameChangeRequests if it is not configured to update DNS or it rejects the DNS
update for any other reason.

164 165
The server may generate one NameChangeRequest in the case where a client acquires a new
lease or it releases an existing one. In the former case, the NameChangeRequest
166
type is CHG_ADD, which indicates that the kea-dhcp-ddns module should add a new
167 168
DNS binding for the client, and it is assumed that there is no DNS binding for
this client already. In the latter case, the NameChangeRequest type is CHG_REMOVE
169
to indicate to the kea-dhcp-ddns module that an existing DNS binding should be
170 171 172 173 174 175 176
removed from the DNS. The binding consists of the forward and reverse mapping.
The server may only remove the mapping which it had added. Therefore, the lease
database holds the information which updates (no update, reverse only update,
forward only update or both reverse and forward update) have been performed when
the lease was acquired or renewed. Server checks this information to make a
decision which mapping it is supposed to remove when lease is released.

177 178 179 180 181 182 183 184 185
The server may generate two NameChangeRequests in the case where client is
renewing a lease and it already has a DNS binding for that lease. The DHCPv4
server will check if there is an existing lease for the client which has sent a
message and if DNS Updates had been performed for this lease. If the notion of
client's FQDN changes, comparing to the information stored in the lease
database, the DHCPv4 has to remove an existing binding from the DNS and then add
a new binding according to the new FQDN information received from the client. If
the client's FQDN information (including the client's name and type of update
performed) doesn't change comparing to the NameChangeRequest is not generated.
186 187 188

The DHCPv4 Client FQDN %Option comprises flags which communicate to the server
what updates (if any) client expects the server to perform. Server may be
189
configured to obey client's preference or to do FQDN processing in a different way.
190 191 192 193
If the server overrides client's preference it will communicate it by sending
the DHCPv4 Client FQDN %Option in its responses to a client, with the appropriate
flags set.

194
@todo Note: the current implementation doesn't allow configuration of the
195
server's behavior with respect to DNS Updates. This is planned for the future.
196
The default behavior is constituted by the set of constants defined in the
197 198 199
(upper part of) dhcp4_srv.cc file. Once the configuration is implemented,
these constants will be removed.

200 201
@section dhcpv4Classifier DHCPv4 Client Classification

202 203 204 205 206 207 208
The Kea DHCPv4 currently supports two classification modes: simplified client
classification (that was an early implementation that used values of vendor class option)
and full client classification.

@subsection dhcpv4ClassifierSimple Simple Client Classification in DHCPv4

The Kea DHCPv4 server supports simplified client classification. It is called
209
"simplified", because the incoming packets are classified based on the content
210 211
of the vendor class (60) option. More flexible classification was added in 1.0
and is described in @ref dhcpv4ClassifierFull .
212 213 214 215 216 217 218 219 220 221

For each incoming packet, @ref isc::dhcp::Dhcpv4Srv::classifyPacket() method is called.
It attempts to extract content of the vendor class option and interpret as a name
of the class. For now, the code has been tested with two classes used in cable modem
networks: eRouter1.0 and docsis3.0, but any other content of the vendor class option will
be interpreted as a class name.

In principle any given packet can belong to zero or more classes. As the current
classifier is very modest, there's only one way to assign a class (based on vendor class
option), the ability to assign more than one class to a packet is not yet exercised.
Francis Dupont's avatar
Francis Dupont committed
222
Nevertheless, there is such a possibility and it will be used in a near future. To
223 224 225
check whether a packet belongs to given class, isc::dhcp::Pkt4::inClass method should
be used.

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
The code sometimes refers to this classification as "simple" or 'built-in", because
it does not require any configuration and thus is built into the server logic.

@subsection dhcpv4ClassifierFull Full Client Classification in DHCPv4

Kea 1.0 introduced full client classification. Each client class consists of a name
and an expression that can be evaluated on an incoming packet. If it evaluates to
true, this packet is considered a member of said class. Class definitions are stored
in isc::dhcp::ClientClassDef objects that are kept in isc::dhcp::ClientClassDictionary.
This is convenient as there are often multiple classes associated with a given scope.
As of Kea 1.0, the only supported scope is global, but there are plans to support
class definitions that are subnet specific.

Client classification is done in isc::dhcp::Dhcpv4Srv::classifyPacket. First, the old
"built-in" (see @ref dhcpv4ClassifierSimple) classification is called. Then the code
iterates over all class definitions and for each class definition it calls
isc::dhcp::evaluate, which is implemented in libeval (see @ref dhcpEval). If the
evaluation is successful, the class name is added to the packet (by calling
isc::dhcp::pkt::addClass).

If packet belongs to at least one class, this fact is logged. If there are any
exceptions raised during class evaluation, an error is logged and the code attempts
to evaluate the next class.

@subsection dhcpv4ClassifierUsage How client classification information is used in DHCPv4

252 253 254
The classification code has been revamped in Kea 1.1. The old code that did specific
things for cable modems can now be achieved with the general classification code. Users
can simply define the class with next-address and/or filename in it.
255

256
It is possible to define class restrictions in subnet, so a given subnet is only
257 258 259 260 261 262 263 264 265 266 267
accessible to clients that belong to a given class. That is implemented as
isc::dhcp::Pkt4::classes_ being passed in isc::dhcp::Dhcpv4Srv::selectSubnet()
to isc::dhcp::CfgMgr::getSubnet4().  Currently this capability is usable, but
the number of scenarios it supports is limited.

Finally, it is possible to define client class-specific options, so clients belonging
to a class foo, will get options associated with class foo. This is implemented in
isc::dhcp::Dhcpv4Srv::buildCfgOptionList.

@section dhcpv4ConfigBackend Configuration backend for DHCPv4

268
Earlier Kea versions had a concept of backends, which were implementations of
269 270 271
different ways how configuration could be delivered to Kea. It seems that the
concept of backends didn't get much enthusiasm from users and having multiple
backends was cumbersome to maintain, so it was removed in 1.0.
272

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
@section dhcpv4SignalBasedReconfiguration Reconfiguring DHCPv4 server with SIGHUP signal

Online reconfiguration (reconfiguration without a need to restart the server) is an
important feature which is supported by all modern DHCP servers. When using the JSON
configuration backend, a configuration file name is specified with a command line
option of the DHCP server binary. The configuration file is used to configure the
server at startup. If the initial configuration fails, the server will fail to start.
If the server starts and configures successfully it will use the initial configuration
until it is reconfigured.

The reconfiguration request can be triggered externally (from other process) by editing
a configuration file and sending a SIGHUP signal to DHCP server process. After receiving
the SIGHUP signal, the server will re-read the configuration file specified at startup.
If the reconfiguration fails, the server will continue to run and use the last good
configuration.

The signal handler for SIGHUP (also for SIGTERM and SIGINT) are installed in the
290
kea_controller.cc using the @c isc::util::SignalSet class. The
291
@c isc::dhcp::Dhcp4Srv calls @c isc::dhcp::Daemon::handleSignal on each pass
292 293 294 295
through the main loop. This method fetches the last received signal and calls
a handler function defined in the kea_controller.cc. The handler function
calls a static function @c configure defined in the kea_controller.cc.

296
The signal handler reconfigures the server using the configuration file
297
specified at server startup. The location of this file is held in the
298
@c Daemon class.
299

300 301
@section dhcpv4Other Other DHCPv4 topics

302
For hooks API support in DHCPv4, see @ref dhcpv4Hooks.
303

304
For a description of how DHCPv4-over-DHCPv6 is implemented, see @subpage dhcpv4o6Dhcp4.
305

306
*/