Kea 3.3.3
ha_config.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <asiolink/io_address.h>
11#include <asiolink/io_error.h>
13#include <dhcpsrv/cfgmgr.h>
14#include <dhcpsrv/network.h>
19#include <util/str.h>
20
21#include <sstream>
22
23#include <ha_log.h>
24
25using namespace isc::asiolink;
26using namespace isc::data;
27using namespace isc::dhcp;
28using namespace isc::http;
29using namespace isc::util;
30using namespace isc::dhcp;
31
32namespace isc {
33namespace ha {
34
36 : tls_context_(), name_(), url_(""), trust_anchor_(), cert_file_(),
37 key_file_(), role_(STANDBY), auto_failover_(false), basic_auth_(),
38 basic_auth_config_() {
39}
40
41void
42HAConfig::PeerConfig::setName(const std::string& name) {
43 // We want to make sure that someone didn't provide a name that consists of
44 // a single space, tab etc.
45 const std::string& s = util::str::trim(name);
46 if (s.empty()) {
47 isc_throw(BadValue, "peer name must not be empty");
48 }
49 name_ = s;
50}
51
52void
53HAConfig::PeerConfig::setRole(const std::string& role) {
54 role_ = stringToRole(role);
55}
56
57std::string
59 std::ostringstream label;
60 label << getName() << " (" << getUrl().toText() << ")";
61 return (label.str());
62}
63
65HAConfig::PeerConfig::stringToRole(const std::string& role) {
66 if (role == "primary") {
68
69 } else if (role == "secondary") {
71
72 } else if (role == "standby") {
74
75 } else if (role == "backup") {
77
78 }
79
80 // Invalid value specified.
81 isc_throw(BadValue, "unsupported value '" << role << "' for role parameter");
82}
83
84std::string
86 switch (role) {
88 return ("primary");
90 return ("secondary");
92 return ("standby");
94 return ("backup");
95 default:
96 ;
97 }
98 return ("");
99}
100
101void
103 const BasicHttpAuthPtr& auth = getBasicAuth();
104 if (!request || !auth) {
105 return;
106 }
107 request->context()->headers_.push_back(BasicAuthHttpHeaderContext(*auth));
108}
109
111 : state_(state), pausing_(STATE_PAUSE_NEVER) {
112}
113
114void
115HAConfig::StateConfig::setPausing(const std::string& pausing) {
116 pausing_ = stringToPausing(pausing);
117}
118
120HAConfig::StateConfig::stringToPausing(const std::string& pausing) {
121 if (pausing == "always") {
122 return (STATE_PAUSE_ALWAYS);
123
124 } else if (pausing == "never") {
125 return (STATE_PAUSE_NEVER);
126
127 } else if (pausing == "once") {
128 return (STATE_PAUSE_ONCE);
129 }
130
131 isc_throw(BadValue, "unsupported value " << pausing << " of 'pause' parameter");
132}
133
134std::string
136 switch (pausing) {
138 return ("always");
139
141 return ("never");
142
143 case STATE_PAUSE_ONCE:
144 return ("once");
145
146 default:
147 ;
148 }
149
150 isc_throw(BadValue, "unsupported pause enumeration " << static_cast<int>(pausing));
151}
152
155 // Return config for the state if it exists already.
156 auto state_config = states_.find(state);
157 if (state_config != states_.end()) {
158 return (state_config->second);
159 }
160
161 // Create config for the state and store its pointer.
162 StateConfigPtr new_state_config(new StateConfig(state));
163 states_[state] = new_state_config;
164
165 return (new_state_config);
166}
167
179
182 return (boost::make_shared<HAConfig>());
183}
184
186HAConfig::selectNextPeerConfig(const std::string& name) {
187 // Check if there is a configuration for this server name already. We can't
188 // have two servers with the same name.
189 if (peers_.count(name) > 0) {
190 isc_throw(BadValue, "peer with name '" << name << "' already specified");
191 }
192
193 // Name appears to be unique, so let's add it.
194 PeerConfigPtr cfg(new PeerConfig());
195 cfg->setName(name);
196 peers_[name] = cfg;
197
198 // Return this to the caller so as the caller can set parsed configuration
199 // for this peer.
200 return (cfg);
201}
202
203void
204HAConfig::setThisServerName(const std::string& this_server_name) {
205 // Avoid names consisting of spaces, tabs etc.
206 std::string s = util::str::trim(this_server_name);
207 if (s.empty()) {
208 isc_throw(BadValue, "'this-server-name' value must not be empty");
209 }
210
212}
213
214
215void
216HAConfig::setHAMode(const std::string& ha_mode) {
217 ha_mode_ = stringToHAMode(ha_mode);
218}
219
221HAConfig::stringToHAMode(const std::string& ha_mode) {
222 if (ha_mode == "load-balancing") {
223 return (LOAD_BALANCING);
224
225 } else if (ha_mode == "hot-standby") {
226 return (HOT_STANDBY);
227
228 } else if (ha_mode == "passive-backup") {
229 return (PASSIVE_BACKUP);
230 }
231
232 isc_throw(BadValue, "unsupported value '" << ha_mode << "' for mode parameter");
233}
234
235std::string
237 switch (ha_mode) {
238 case LOAD_BALANCING:
239 return ("load-balancing");
240 case HOT_STANDBY:
241 return ("hot-standby");
242 case PASSIVE_BACKUP:
243 return ("passive-backup");
244 default:
245 ;
246 }
247 return ("");
248}
249
251HAConfig::getPeerConfig(const std::string& name) const {
252 auto peer = peers_.find(name);
253 if (peer == peers_.end()) {
254 isc_throw(InvalidOperation, "no configuration specified for server " << name);
255 }
256
257 return (peer->second);
258}
259
263 for (auto const& peer : servers) {
264 if (peer.second->getRole() != HAConfig::PeerConfig::BACKUP) {
265 return (peer.second);
266 }
267 }
268
269 isc_throw(InvalidOperation, "no failover partner server found for this"
270 " server " << getThisServerName());
271}
272
277
281 copy.erase(getThisServerName());
282 return (copy);
283}
284
285void
287 // Peers configurations must be provided.
288 if (peers_.count(getThisServerName()) == 0) {
289 isc_throw(HAConfigValidationError, "no peer configuration specified for the '"
290 << getThisServerName() << "'");
291 }
292
293 // Gather all the roles and see how many occurrences of each role we get.
294 std::map<PeerConfig::Role, unsigned> peers_cnt;
295 for (auto const& p : peers_) {
296 if (!p.second->getUrl().isValid()) {
297 isc_throw(HAConfigValidationError, "invalid URL: "
298 << p.second->getUrl().getErrorMessage()
299 << " for server " << p.second->getName());
300 }
301
302 // The hostname must be an address, not a name.
303 IOAddress addr("::");
304 try {
305 addr = IOAddress(p.second->getUrl().getStrippedHostname());
306 } catch (const IOError& ex) {
308 << p.second->getUrl().toText()
309 << "': " << ex.what()
310 << " for server " << p.second->getName());
311 }
312
313 // Check TLS setup.
314 Optional<std::string> ca = p.second->getTrustAnchor();
315 Optional<std::string> cert = p.second->getCertFile();
316 Optional<std::string> key = p.second->getKeyFile();
317 // When not configured get the value from the global level.
318 if (ca.unspecified()) {
319 ca = trust_anchor_;
320 }
321 if (cert.unspecified()) {
322 cert = cert_file_;
323 }
324 if (key.unspecified()) {
325 key = key_file_;
326 }
327 bool have_ca = (!ca.unspecified() && !ca.get().empty());
328 bool have_cert = (!cert.unspecified() && !cert.get().empty());
329 bool have_key = (!key.unspecified() && !key.get().empty());
330 bool use_tls = (have_ca || have_cert || have_key);
331 if (use_tls) {
332 try {
333 // TLS is used: all 3 parameters are required.
334 if (!have_ca) {
335 isc_throw(HAConfigValidationError, "trust-anchor parameter"
336 << " is missing or empty: all or none of"
337 << " TLS parameters must be set");
338 }
339 if (!have_cert) {
340 isc_throw(HAConfigValidationError, "cert-file parameter"
341 << " is missing or empty: all or none of"
342 << " TLS parameters must be set");
343 }
344 if (!have_key) {
345 isc_throw(HAConfigValidationError, "key-file parameter"
346 << " is missing or empty: all or none of"
347 << " TLS parameters must be set");
348 }
349 TlsRole tls_role = TlsRole::CLIENT;
350 bool cert_required = true;
351 // The peer entry for myself will be used for the server side.
352 if (p.second->getName() == getThisServerName()) {
353 tls_role = TlsRole::SERVER;
354 cert_required = getRequireClientCerts();
355 }
356 TlsContext::configure(p.second->tls_context_,
357 tls_role,
358 ca.get(),
359 cert.get(),
360 key.get(),
361 cert_required);
362 } catch (const isc::Exception& ex) {
363 isc_throw(HAConfigValidationError, "bad TLS config for server "
364 << p.second->getName() << ": " << ex.what());
365 }
366 } else {
367 // Refuse HTTPS scheme when TLS is not enabled.
368 if (p.second->getUrl().getScheme() == Url::HTTPS) {
370 << p.second->getUrl().toText()
371 << "': https scheme is not supported"
372 << " for server " << p.second->getName()
373 << " where TLS is disabled");
374 }
375 }
376
377 ++peers_cnt[p.second->getRole()];
378 }
379
380 // Only one primary server allowed.
381 if (peers_cnt.count(PeerConfig::PRIMARY) && (peers_cnt[PeerConfig::PRIMARY] > 1)) {
382 isc_throw(HAConfigValidationError, "multiple primary servers specified");
383 }
384
385 // Only one secondary server allowed.
386 if (peers_cnt.count(PeerConfig::SECONDARY) && (peers_cnt[PeerConfig::SECONDARY] > 1)) {
387 isc_throw(HAConfigValidationError, "multiple secondary servers specified");
388 }
389
390 // Only one standby server allowed.
391 if (peers_cnt.count(PeerConfig::STANDBY) && (peers_cnt[PeerConfig::STANDBY] > 1)) {
392 isc_throw(HAConfigValidationError, "multiple standby servers specified");
393 }
394
395 if (ha_mode_ == LOAD_BALANCING) {
396 // Standby servers not allowed in load balancing configuration.
397 if (peers_cnt.count(PeerConfig::STANDBY) > 0) {
398 isc_throw(HAConfigValidationError, "standby servers not allowed in the load "
399 "balancing configuration");
400 }
401
402 // Require one secondary server in the load balancing configuration.
403 if (peers_cnt.count(PeerConfig::SECONDARY) == 0) {
404 isc_throw(HAConfigValidationError, "secondary server required in the load"
405 " balancing configuration");
406 }
407
408 // Require one primary server in the load balancing configuration.
409 if (peers_cnt.count(PeerConfig::PRIMARY) == 0) {
410 isc_throw(HAConfigValidationError, "primary server required in the load"
411 " balancing configuration");
412 }
413
414 // In the load-balancing mode the wait-backup-ack must be false.
415 if (wait_backup_ack_) {
416 isc_throw(HAConfigValidationError, "'wait-backup-ack' must be set to false in the"
417 " load balancing configuration");
418 }
419
420 } else if (ha_mode_ == HOT_STANDBY) {
421 // Secondary servers not allowed in the hot standby configuration.
422 if (peers_cnt.count(PeerConfig::SECONDARY) > 0) {
423 isc_throw(HAConfigValidationError, "secondary servers not allowed in the hot"
424 " standby configuration");
425 }
426
427 // Require one standby server in the hot standby configuration.
428 if (peers_cnt.count(PeerConfig::STANDBY) == 0) {
429 isc_throw(HAConfigValidationError, "standby server required in the hot"
430 " standby configuration");
431 }
432
433 // Require one primary server in the hot standby configuration.
434 if (peers_cnt.count(PeerConfig::PRIMARY) == 0) {
435 isc_throw(HAConfigValidationError, "primary server required in the hot"
436 " standby configuration");
437 }
438
439 // In the hot-standby mode the wait-backup-ack must be false.
440 if (wait_backup_ack_) {
441 isc_throw(HAConfigValidationError, "'wait-backup-ack' must be set to false in the"
442 " hot standby configuration");
443 }
444
445 // The server must not transition to communication-recovery state in
446 // hot-standby mode.
447 if (delayed_updates_limit_ > 0) {
448 isc_throw(HAConfigValidationError, "'delayed-updates-limit' must be set to 0 in"
449 " the hot standby configuration");
450 }
451
452 } else if (ha_mode_ == PASSIVE_BACKUP) {
453 if (peers_cnt.count(PeerConfig::SECONDARY) > 0) {
454 isc_throw(HAConfigValidationError, "secondary servers not allowed in the"
455 " passive backup configuration");
456 }
457
458 if (peers_cnt.count(PeerConfig::STANDBY) > 0) {
459 isc_throw(HAConfigValidationError, "standby servers not allowed in the"
460 " passive backup configuration");
461 }
462
463 if (peers_cnt.count(PeerConfig::PRIMARY) == 0) {
464 isc_throw(HAConfigValidationError, "primary server required in the"
465 " passive backup configuration");
466 }
467
468 // The server must not transition to communication-recovery state in
469 // passive-backup mode.
470 if (delayed_updates_limit_ > 0) {
471 isc_throw(HAConfigValidationError, "'delayed-updates-limit' must be set to 0 in"
472 " the passive backup configuration");
473 }
474 }
475
476 // We get it from staging because applying the DHCP multi-threading configuration
477 // occurs after library loading during the (re)configuration process.
478 auto mcfg = CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading();
479 bool dhcp_mt_enabled = false;
480 uint32_t dhcp_threads = 0;
481 uint32_t dummy_queue_size = 0;
482 CfgMultiThreading::extract(mcfg, dhcp_mt_enabled, dhcp_threads, dummy_queue_size);
483
485 if (!dhcp_mt_enabled) {
486 // HA+MT requires DHCP multi-threading.
488 .arg(getThisServerName());
490 return;
491 }
492
493 // When DHCP threads is configured as zero, we should auto-detect.
494 if (!dhcp_threads) {
496 // If machine says it cannot support threads.
497 if (!dhcp_threads) {
499 .arg(getThisServerName());
501 return;
502 }
503 }
504
505 // If http_listener_threads_ is 0, then we use the same number of
506 // threads as DHCP does.
507 if (http_listener_threads_ == 0) {
508 http_listener_threads_ = dhcp_threads;
509 }
510
511 // If http_client_threads_ is 0, then we use the same number of
512 // threads as DHCP does.
513 if (http_client_threads_ == 0) {
514 http_client_threads_ = dhcp_threads;
515 }
516 } else {
517 if (dhcp_mt_enabled) {
518 // DHCP multi-threading requires HA+MT for optimal performance.
520 .arg(getThisServerName());
521 return;
522 }
523 }
524}
525
526std::string
528 const std::string parameter_name = "ha-server-name";
529 auto context = subnet->getContext();
530 if (!context || (context->getType() != Element::map) || !context->contains(parameter_name)) {
531 NetworkPtr shared_network;
532 subnet->getSharedNetwork(shared_network);
533 if (shared_network) {
534 context = shared_network->getContext();
535 }
536 }
537 if (context && (context->getType() == Element::map) && context->contains(parameter_name)) {
538 auto server_name_element = context->get(parameter_name);
539 if ((server_name_element->getType() != Element::string) || server_name_element->stringValue().empty()) {
540 isc_throw(BadValue, "'" << parameter_name << "' must be a non-empty string");
541 }
542 return (server_name_element->stringValue());
543 }
544 return ("");
545}
546
547} // end of namespace isc::ha
548} // end of namespace isc
@ map
Definition data.h:160
@ string
Definition data.h:157
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
static void extract(data::ConstElementPtr value, bool &enabled, uint32_t &thread_count, uint32_t &queue_size)
Extract multi-threading parameters from a given configuration.
Exception thrown when configuration validation fails.
Definition ha_config.h:30
HA peer configuration.
Definition ha_config.h:68
std::string getLogLabel() const
Returns a string identifying a server used in logging.
Definition ha_config.cc:58
void addBasicAuthHttpHeader(http::PostHttpRequestJsonPtr request) const
Adds a basic HTTP authentication header to a request when credentials are specified.
Definition ha_config.cc:102
asiolink::TlsContextPtr tls_context_
Server TLS context.
Definition ha_config.h:239
void setRole(const std::string &role)
Sets servers role.
Definition ha_config.cc:53
std::string getName() const
Returns server name.
Definition ha_config.h:96
static std::string roleToString(const HAConfig::PeerConfig::Role &role)
Returns role name.
Definition ha_config.cc:85
Role
Server's role in the High Availability setup.
Definition ha_config.h:85
static Role stringToRole(const std::string &role)
Decodes role provided as a string.
Definition ha_config.cc:65
void setName(const std::string &name)
Sets server name.
Definition ha_config.cc:42
http::BasicHttpAuthPtr & getBasicAuth()
Returns non-const basic HTTP authentication.
Definition ha_config.h:212
http::Url getUrl() const
Returns URL of the server's control channel.
Definition ha_config.h:107
Configuration specific to a single HA state.
Definition ha_config.h:261
static util::StatePausing stringToPausing(const std::string &pausing)
Converts pausing mode from the textual form.
Definition ha_config.cc:120
void setPausing(const std::string &pausing)
Sets pausing mode for the given state.
Definition ha_config.cc:115
StateConfig(const int state)
Constructor.
Definition ha_config.cc:110
static std::string pausingToString(const util::StatePausing &pausing)
Returns pausing mode in the textual form.
Definition ha_config.cc:135
State machine configuration information.
Definition ha_config.h:313
StateConfigPtr getStateConfig(const int state)
Returns pointer to the state specific configuration.
Definition ha_config.cc:154
uint32_t max_response_delay_
Max delay in response to heartbeats.
Definition ha_config.h:842
uint32_t http_listener_threads_
Number of HTTP listener threads.
Definition ha_config.h:849
static HAConfigPtr create()
Instantiates a HAConfig.
Definition ha_config.cc:181
uint32_t sync_page_limit_
Page size limit while synchronizing leases.
Definition ha_config.h:837
std::string getThisServerName() const
Returns name of this server.
Definition ha_config.h:359
bool require_client_certs_
Require client certs flag.
Definition ha_config.h:854
bool http_dedicated_listener_
Enable use of own HTTP listener.
Definition ha_config.h:848
void validate()
Validates configuration.
Definition ha_config.cc:286
uint32_t delayed_updates_limit_
Maximum number of lease updates held for later send in communication-recovery.
Definition ha_config.h:839
PeerConfigPtr getThisServerConfig() const
Returns configuration of this server.
Definition ha_config.cc:274
bool getRequireClientCerts() const
Returns require-client-certs.
Definition ha_config.h:734
uint32_t max_rejected_lease_updates_
Limit of rejected lease updates before termination.
Definition ha_config.h:845
std::map< std::string, PeerConfigPtr > PeerConfigMap
Map of the servers' configurations.
Definition ha_config.h:258
void setHAMode(const std::string &ha_mode)
Sets new mode of operation.
Definition ha_config.cc:216
HAMode ha_mode_
Mode of operation.
Definition ha_config.h:833
bool send_lease_updates_
Send lease updates to partner?
Definition ha_config.h:834
HAMode
Mode of operation.
Definition ha_config.h:57
uint32_t max_unacked_clients_
Maximum number of unacked clients.
Definition ha_config.h:844
PeerConfigMap peers_
Map of peers' configurations.
Definition ha_config.h:856
uint32_t max_ack_delay_
Maximum DHCP message ack delay.
Definition ha_config.h:843
util::Optional< std::string > cert_file_
Certificate file.
Definition ha_config.h:852
bool restrict_commands_
Restrict commands to HA flag.
Definition ha_config.h:855
void setThisServerName(const std::string &this_server_name)
Sets name of this server.
Definition ha_config.cc:204
PeerConfigMap getOtherServersConfig() const
Returns configuration of other servers.
Definition ha_config.cc:279
PeerConfigPtr getFailoverPeerConfig() const
Returns configuration of the partner which takes part in failover.
Definition ha_config.cc:261
PeerConfigPtr getPeerConfig(const std::string &name) const
Returns configuration of the specified server.
Definition ha_config.cc:251
util::Optional< std::string > key_file_
Private key file.
Definition ha_config.h:853
PeerConfigPtr selectNextPeerConfig(const std::string &name)
Creates and returns pointer to the new peer's configuration.
Definition ha_config.cc:186
bool sync_leases_
Synchronize databases on startup?
Definition ha_config.h:835
bool wait_backup_ack_
Wait for lease update ack from backup?
Definition ha_config.h:846
StateMachineConfigPtr state_machine_
State machine configuration.
Definition ha_config.h:857
HAConfig()
Constructor.
Definition ha_config.cc:168
util::Optional< std::string > trust_anchor_
Trust anchor.
Definition ha_config.h:851
static HAMode stringToHAMode(const std::string &ha_mode)
Decodes HA mode provided as string.
Definition ha_config.cc:221
uint32_t http_client_threads_
Number of HTTP client threads.
Definition ha_config.h:850
uint32_t sync_timeout_
Timeout for syncing lease database (ms).
Definition ha_config.h:836
boost::shared_ptr< StateConfig > StateConfigPtr
Pointer to the state configuration.
Definition ha_config.h:306
bool enable_multi_threading_
Enable multi-threading.
Definition ha_config.h:847
uint32_t heartbeat_delay_
Heartbeat delay in milliseconds.
Definition ha_config.h:841
static std::string getSubnetServerName(const dhcp::ConstSubnetPtr &subnet)
Convenience function extracting a value of the ha-server-name parameter from a subnet context.
Definition ha_config.cc:527
static std::string HAModeToString(const HAMode &ha_mode)
Returns HA mode name.
Definition ha_config.cc:236
std::string this_server_name_
This server name.
Definition ha_config.h:832
boost::shared_ptr< PeerConfig > PeerConfigPtr
Pointer to the server's configuration.
Definition ha_config.h:255
static uint32_t detectThreadCount()
The system current detected hardware concurrency thread count.
A template representing an optional value.
Definition optional.h:37
T get() const
Retrieves the encapsulated value.
Definition optional.h:123
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition optional.h:145
TLS API.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
ElementPtr copy(ConstElementPtr from, unsigned level)
Copy the data up to a nesting level.
Definition data.cc:1543
boost::shared_ptr< const Subnet > ConstSubnetPtr
A generic pointer to either const Subnet4 or const Subnet6 object.
Definition subnet.h:449
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition network.h:73
const isc::log::MessageID HA_CONFIG_DHCP_MT_DISABLED
Definition ha_messages.h:28
isc::log::Logger ha_logger("ha-hooks")
Definition ha_log.h:17
const isc::log::MessageID HA_CONFIG_DHCP_MT_DISABLED_AND_KEA_MT_ENABLED
Definition ha_messages.h:29
boost::shared_ptr< HAConfig > HAConfigPtr
Pointer to the High Availability configuration structure.
Definition ha_config.h:39
const isc::log::MessageID HA_CONFIG_SYSTEM_MT_UNSUPPORTED
Definition ha_messages.h:35
boost::shared_ptr< BasicHttpAuth > BasicHttpAuthPtr
Type of pointers to basic HTTP authentication objects.
Definition basic_auth.h:70
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
string trim(const string &input)
Trim leading and trailing spaces.
Definition str.cc:32
StatePausing
State machine pausing modes.
Definition state_model.h:48
@ STATE_PAUSE_ALWAYS
Definition state_model.h:49
@ STATE_PAUSE_ONCE
Definition state_model.h:51
@ STATE_PAUSE_NEVER
Definition state_model.h:50
Defines the logger used by the top-level component of kea-lfc.
Represents basic HTTP authentication header.
Definition basic_auth.h:73