Kea 3.3.3
query_filter.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
9#include <dhcp/dhcp4.h>
10#include <dhcp/dhcp6.h>
11#include <dhcp/option.h>
15
16#include <array>
17#include <iostream>
18#include <sstream>
19
20#include <ha_log.h>
21
22using namespace isc::dhcp;
23using namespace isc::log;
24using namespace isc::util;
25
26namespace {
27
31std::array<uint8_t, 256> loadb_mx_tbl = { {
32 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, 181, 143, 186, 157, 0,
33 232, 31, 32, 55, 60, 152, 58, 17, 237, 174, 70, 160, 144, 220, 90, 57,
34 223, 59, 3, 18, 140, 111, 166, 203, 196, 134, 243, 124, 95, 222, 179,
35 197, 65, 180, 48, 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, 209, 23,
36 97, 16, 40, 91, 219, 61, 100, 10, 210, 109, 250, 127, 22, 138, 29, 108,
37 244, 67, 207, 9, 178, 204, 74, 98, 126, 249, 167, 116, 34, 77, 193,
38 200, 121, 5, 20, 113, 71, 35, 128, 13, 182, 94, 25, 226, 227, 199, 75,
39 27, 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, 212, 142, 218, 115,
40 241, 73, 88, 105, 39, 114, 62, 255, 192, 201, 145, 214, 168, 158, 221,
41 148, 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, 205, 242, 217, 11,
42 187, 146, 159, 64, 86, 239, 195, 42, 106, 198, 118, 112, 184, 172, 87,
43 2, 173, 117, 176, 229, 247, 253, 137, 185, 99, 164, 102, 147, 45, 66,
44 231, 52, 141, 211, 194, 206, 246, 238, 56, 110, 78, 248, 63, 240, 189,
45 93, 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, 101, 69, 8, 252, 83, 120,
46 76, 135, 85, 54, 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, 190,
47 132, 156, 38, 47, 1, 7, 254, 24, 4, 216, 131, 89, 21, 28, 133, 37, 153,
48 149, 80, 170, 68, 6, 169, 234, 151 }
49};
50
52std::array<bool, DHCP_TYPES_EOF> v4_ha_types = {
53 false, // DHCP_NOTYPE = 0
54 true, // DHCPDISCOVER = 1
55 false, // DHCPOFFER = 2
56 true, // DHCPREQUEST = 3
57 true, // DHCPDECLINE = 4
58 false, // DHCPACK = 5
59 false, // DHCPNAK = 6
60 true, // DHCPRELEASE = 7
61 true, // DHCPINFORM = 8
62 false, // DHCPFORCERENEW = 9
63 false, // DHCPLEASEQUERY = 10
64 false, // DHCPLEASEUNASSIGNED = 11
65 false, // DHCPLEASEUNKNOWN = 12
66 false, // DHCPLEASEACTIVE = 13
67 false, // DHCPBULKLEASEQUERY = 14
68 false, // DHCPLEASEQUERYDONE = 15
69 false, // DHCPACTIVELEASEQUERY = 16
70 false, // DHCPLEASEQUERYSTATUS = 17
71 false // DHCPTLS = 18
72};
73
75std::array<bool, DHCPV6_TYPES_EOF> v6_ha_types = {
76 false, // DHCPV6_NOTYPE = 0
77 true, // DHCPV6_SOLICIT = 1
78 false, // DHCPV6_ADVERTISE = 2
79 true, // DHCPV6_REQUEST = 3
80 true, // DHCPV6_CONFIRM = 4
81 true, // DHCPV6_RENEW = 5
82 true, // DHCPV6_REBIND = 6
83 false, // DHCPV6_REPLY = 7
84 true, // DHCPV6_RELEASE = 8
85 true, // DHCPV6_DECLINE = 9
86 false, // DHCPV6_RECONFIGURE = 10
87 false, // DHCPV6_INFORMATION_REQUEST = 11
88 false, // DHCPV6_RELAY_FORW = 12
89 false, // DHCPV6_RELAY_REPL = 13
90 false, // DHCPV6_LEASEQUERY = 14
91 false, // DHCPV6_LEASEQUERY_REPLY = 15
92 false, // DHCPV6_LEASEQUERY_DONE = 16
93 false, // DHCPV6_LEASEQUERY_DATA = 17
94 false, // DHCPV6_RECONFIGURE_REQUEST = 18
95 false, // DHCPV6_RECONFIGURE_REPLY = 19
99 false, // DHCPV6_DHCPV4_QUERY = 20
100 false, // DHCPV6_DHCPV4_RESPONSE = 21
101 false, // DHCPV6_ACTIVELEASEQUERY = 22
102 false, // DHCPV6_STARTTLS = 23
103 false, // DHCPV6_BNDUPD = 24
104 false, // DHCPV6_BNDREPLY = 25
105 false, // DHCPV6_POOLREQ = 26
106 false, // DHCPV6_POOLRESP = 27
107 false, // DHCPV6_UPDREQ = 28
108 false, // DHCPV6_UPDREQALL = 29
109 false, // DHCPV6_UPDDONE = 30
110 false, // DHCPV6_CONNECT = 31
111 false, // DHCPV6_CONNECTREPLY = 32
112 false, // DHCPV6_DISCONNECT = 33
113 false, // DHCPV6_STATE = 34
114 false // DHCPV6_CONTACT = 35
115};
116
117} // end of anonymous namespace
118
119namespace isc {
120namespace ha {
121
124 mutex_(new std::mutex) {
125
126 // Make sure that the configuration is valid. We make certain
127 // assumptions about the availability of the servers' configurations
128 // in the config_ structure.
129 config_->validate();
130
131 HAConfig::PeerConfigMap peers_map = config->getAllServersConfig();
132 std::vector<HAConfig::PeerConfigPtr> backup_peers;
133
134 // The returned configurations are not ordered. Let's iterate over them
135 // and put them in the desired order.
136 for (auto const& peer_pair : peers_map) {
137 auto peer = peer_pair.second;
138 // The primary server is always first on the list.
139 if (peer->getRole() == HAConfig::PeerConfig::PRIMARY) {
140 peers_.insert(peers_.begin(), peer);
142
143 // The secondary server is always behind the primary server.
144 } else if ((peer->getRole() == HAConfig::PeerConfig::SECONDARY) ||
145 (peer->getRole() == HAConfig::PeerConfig::STANDBY)) {
146 peers_.push_back(peer);
147
148 // If this is a secondary server, we're in the load balancing
149 // mode, in which case we have two active servers.
150 if (peer->getRole() == HAConfig::PeerConfig::SECONDARY) {
152 }
153
154 // If this is neither primary nor secondary/standby, it is a backup.
155 } else {
156 backup_peers.push_back(peer);
157 }
158 }
159
160 // Append backup servers to the list.
161 if (!backup_peers.empty()) {
162 peers_.insert(peers_.end(), backup_peers.begin(), backup_peers.end());
163 }
164
165 // The query filter is initially setup to serve default scopes, i.e. for the
166 // load balancing case the primary and secondary are responsible for their
167 // own scopes. The backup servers are not responding to any queries. In the
168 // hot standby mode, the primary server is responsible for the entire traffic.
169 // The standby server is not responding.
171}
172
173void
174QueryFilter::serveScope(const std::string& scope_name) {
175 if (MultiThreadingMgr::instance().getMode()) {
176 std::lock_guard<std::mutex> lock(*mutex_);
177 serveScopeInternal(scope_name);
178 } else {
179 serveScopeInternal(scope_name);
180 }
181}
182
183void
184QueryFilter::serveScopeInternal(const std::string& scope_name) {
185 validateScopeName(scope_name);
186 scopes_[scope_name] = true;
187}
188
189void
190QueryFilter::serveScopeOnly(const std::string& scope_name) {
191 if (MultiThreadingMgr::instance().getMode()) {
192 std::lock_guard<std::mutex> lock(*mutex_);
193 serveScopeOnlyInternal(scope_name);
194 } else {
195 serveScopeOnlyInternal(scope_name);
196 }
197}
198
199void
200QueryFilter::serveScopeOnlyInternal(const std::string& scope_name) {
201 validateScopeName(scope_name);
202 serveNoScopesInternal();
203 serveScopeInternal(scope_name);
204}
205
206void
207QueryFilter::serveScopes(const std::vector<std::string>& scopes) {
208 if (MultiThreadingMgr::instance().getMode()) {
209 std::lock_guard<std::mutex> lock(*mutex_);
210 serveScopesInternal(scopes);
211 } else {
212 serveScopesInternal(scopes);
213 }
214}
215
216void
217QueryFilter::serveScopesInternal(const std::vector<std::string>& scopes) {
218 // Remember currently enabled scopes in case we fail to process
219 // the provided list of scopes.
220 auto current_scopes = scopes_;
221 try {
222 serveNoScopesInternal();
223 for (size_t i = 0; i < scopes.size(); ++i) {
224 serveScopeInternal(scopes[i]);
225 }
226
227 } catch (...) {
228 // There was an error processing scopes list. Need to revert
229 // to the previous configuration.
230 scopes_ = current_scopes;
231 throw;
232 }
233}
234
235void
237 if (MultiThreadingMgr::instance().getMode()) {
238 std::lock_guard<std::mutex> lock(*mutex_);
239 serveDefaultScopesInternal();
240 } else {
241 serveDefaultScopesInternal();
242 }
243}
244
245void
246QueryFilter::serveDefaultScopesInternal() {
247 // Get this server instance configuration.
248 HAConfig::PeerConfigPtr my_config = config_->getThisServerConfig();
249 HAConfig::PeerConfig::Role my_role = my_config->getRole();
250
251 // Clear scopes.
252 serveNoScopesInternal();
253
254 // If I am primary or secondary, then I am only responsible for my own
255 // scope. If I am standby, I am not responsible for any scope.
256 if ((my_role == HAConfig::PeerConfig::PRIMARY) ||
257 (my_role == HAConfig::PeerConfig::SECONDARY)) {
258 serveScopeInternal(my_config->getName());
259 }
260}
261
262void
264 if (MultiThreadingMgr::instance().getMode()) {
265 std::lock_guard<std::mutex> lock(*mutex_);
266 serveFailoverScopesInternal();
267 } else {
268 serveFailoverScopesInternal();
269 }
270}
271
272void
273QueryFilter::serveFailoverScopesInternal() {
274 // Clear scopes.
275 serveNoScopesInternal();
276
277 // Iterate over the roles of all servers to see which scope should
278 // be enabled.
279 for (auto const& peer : peers_) {
280 // The scope of the primary server must always be served. If we're
281 // doing load balancing, the scope of the secondary server also
282 // has to be served. Regardless if I am primary or secondary,
283 // I will start serving queries from both scopes. If I am a
284 // standby server, I will start serving the scope of the primary
285 // server.
286 if ((peer->getRole() == HAConfig::PeerConfig::PRIMARY) ||
287 (peer->getRole() == HAConfig::PeerConfig::SECONDARY)) {
288 serveScopeInternal(peer->getName());
289 }
290 }
291}
292
293void
295 if (MultiThreadingMgr::instance().getMode()) {
296 std::lock_guard<std::mutex> lock(*mutex_);
297 serveNoScopesInternal();
298 } else {
299 serveNoScopesInternal();
300 }
301}
302
303void
304QueryFilter::serveNoScopesInternal() {
305 scopes_.clear();
306
307 // Disable scope for each peer in the configuration.
308 for (auto const& peer : peers_) {
309 scopes_[peer->getName()] = false;
310 }
311}
312
313bool
314QueryFilter::amServingScope(const std::string& scope_name) const {
315 if (MultiThreadingMgr::instance().getMode()) {
316 std::lock_guard<std::mutex> lock(*mutex_);
317 return (amServingScopeInternal(scope_name));
318 } else {
319 return (amServingScopeInternal(scope_name));
320 }
321}
322
323bool
324QueryFilter::amServingScopeInternal(const std::string& scope_name) const {
325 auto scope = scopes_.find(scope_name);
326 return ((scope == scopes_.end()) || (scope->second));
327}
328
329std::set<std::string>
331 if (MultiThreadingMgr::instance().getMode()) {
332 std::lock_guard<std::mutex> lock(*mutex_);
333 return (getServedScopesInternal());
334 } else {
335 return (getServedScopesInternal());
336 }
337}
338
339std::set<std::string>
340QueryFilter::getServedScopesInternal() const {
341 std::set<std::string> scope_set;
342 for (auto const& scope : scopes_) {
343 if (scope.second) {
344 scope_set.insert(scope.first);
345 }
346 }
347 return (scope_set);
348}
349
350bool
352 auto msg_type = query4->getType();
353 return (msg_type < v4_ha_types.size() && v4_ha_types[msg_type]);
354}
355
356bool
358 auto msg_type = query->getType();
359 return (msg_type < v6_ha_types.size() && v6_ha_types[msg_type]);
360}
361
362
363bool
364QueryFilter::inScope(const dhcp::Pkt4Ptr& query4, std::string& scope_class) const {
365 if (MultiThreadingMgr::instance().getMode()) {
366 std::lock_guard<std::mutex> lock(*mutex_);
367 return (queryInScopeInternal(query4, scope_class));
368 } else {
369 return (queryInScopeInternal(query4, scope_class));
370 }
371}
372
373bool
374QueryFilter::inScope(const dhcp::Pkt6Ptr& query6, std::string& scope_class) const {
375 if (MultiThreadingMgr::instance().getMode()) {
376 std::lock_guard<std::mutex> lock(*mutex_);
377 return (queryInScopeInternal(query6, scope_class));
378 } else {
379 return (queryInScopeInternal(query6, scope_class));
380 }
381}
382
383template<typename QueryPtrType>
384bool
385QueryFilter::queryInScopeInternal(const QueryPtrType& query,
386 std::string& scope_class) const {
387 if (!query) {
388 isc_throw(BadValue, "query must not be null");
389 }
390
391 // If it's not a type HA cares about, it's in scope for this peer.
392 if (!isHaType(query)) {
393 auto scope = peers_[0]->getName();
394 scope_class = makeScopeClass(scope);
395 return (true);
396 }
397
398 int candidate_server = 0;
399
400 // If we're doing load balancing we have to check if this query
401 // belongs to us or the partner. If it belongs to a partner but
402 // we're configured to serve this scope, we should accept it.
403 if (config_->getHAMode() == HAConfig::LOAD_BALANCING) {
404 candidate_server = loadBalance(query);
405 // Malformed query received.
406 if (candidate_server < 0) {
407 return (false);
408 }
409 }
410
411 auto scope = peers_[candidate_server]->getName();
412 scope_class = makeScopeClass(scope);
413 return ((candidate_server >= 0) && amServingScopeInternal(scope));
414}
415
416bool
417QueryFilter::inScope(const Lease4Ptr& lease4) const {
418 if (MultiThreadingMgr::instance().getMode()) {
419 std::lock_guard<std::mutex> lock(*mutex_);
420 return (leaseInScopeInternal(lease4));
421 } else {
422 return (leaseInScopeInternal(lease4));
423 }
424}
425
426bool
427QueryFilter::inScope(const Lease6Ptr& lease6) const {
428 if (MultiThreadingMgr::instance().getMode()) {
429 std::lock_guard<std::mutex> lock(*mutex_);
430 return (leaseInScopeInternal(lease6));
431 } else {
432 return (leaseInScopeInternal(lease6));
433 }
434}
435
436template<typename LeasePtrType>
437bool
438QueryFilter::leaseInScopeInternal(const LeasePtrType& lease) const {
439 if (!lease) {
440 isc_throw(BadValue, "lease must not be null");
441 }
442
443 int candidate_server = 0;
444
445 // If we're doing load balancing we have to check if this query
446 // belongs to us or the partner. If it belongs to a partner but
447 // we're configured to serve this scope, we should accept it.
448 if (config_->getHAMode() == HAConfig::LOAD_BALANCING) {
449 candidate_server = loadBalance(lease);
450 // Malformed query received.
451 if (candidate_server < 0) {
452 return (false);
453 }
454 }
455
456 auto scope = peers_[candidate_server]->getName();
457 return ((candidate_server >= 0) && amServingScopeInternal(scope));
458}
459
460int
462 uint8_t lb_hash = 0;
463 // Try to compute the hash by client identifier if the client
464 // identifier has been specified.
465 OptionPtr opt_client_id = query4->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
466 if (opt_client_id && !opt_client_id->getData().empty()) {
467 auto const& client_id_key = opt_client_id->getData();
468 lb_hash = loadBalanceHash(&client_id_key[0], client_id_key.size());
469
470 } else {
471 // No client identifier available. Use the HW address instead.
472 HWAddrPtr hwaddr = query4->getHWAddr();
473 if (hwaddr && !hwaddr->hwaddr_.empty()) {
474 lb_hash = loadBalanceHash(&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size());
475
476 } else {
477 // No client identifier and no HW address. Indicate an
478 // error.
479 std::stringstream xid;
480 xid << "0x" << std::hex << query4->getTransid() << std::dec;
482 .arg(config_->getThisServerName())
483 .arg(xid.str());
484 return (-1);
485 }
486 }
487
488 // The hash value modulo number of active servers gives an index
489 // of the server to process the packet.
490 return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
491}
492
493int
495 uint8_t lb_hash = 0;
496 // Compute the hash by DUID if the DUID.
497 OptionPtr opt_duid = query6->getOption(D6O_CLIENTID);
498 if (opt_duid && !opt_duid->getData().empty()) {
499 auto const& duid_key = opt_duid->getData();
500 lb_hash = loadBalanceHash(&duid_key[0], duid_key.size());
501
502 } else {
503 // No DUID. Indicate an error.
504 std::stringstream xid;
505 xid << "0x" << std::hex << query6->getTransid() << std::dec;
507 .arg(config_->getThisServerName())
508 .arg(xid.str());
509 return (-1);
510 }
511
512 // The hash value modulo number of active servers gives an index
513 // of the server to process the packet.
514 return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
515}
516
517int
519 uint8_t lb_hash = 0;
520 // Try to compute the hash by client identifier if the client
521 // identifier has been specified.
522 if (lease4->client_id_ && !lease4->client_id_->getClientId().empty()) {
523 auto const& client_id_key = lease4->client_id_->getClientId();
524 lb_hash = loadBalanceHash(&client_id_key[0], client_id_key.size());
525
526 } else {
527 // No client identifier available. Use the HW address instead.
528 HWAddrPtr hwaddr = lease4->hwaddr_;
529 if (hwaddr && !hwaddr->hwaddr_.empty()) {
530 lb_hash = loadBalanceHash(&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size());
531
532 } else {
533 // No client identifier and no HW address. Indicate an
534 // error.
536 .arg(config_->getThisServerName())
537 .arg(lease4->addr_);
538 return (-1);
539 }
540 }
541
542 // The hash value modulo number of active servers gives an index
543 // of the server to process the packet.
544 return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
545}
546
547int
549 uint8_t lb_hash = 0;
550 // Compute the hash by DUID if the DUID.
551 auto duid = lease6->duid_;
552 if (duid && !duid->getDuid().empty()) {
553 auto const& duid_key = duid->getDuid();
554 lb_hash = loadBalanceHash(&duid_key[0], duid_key.size());
555
556 } else {
557 // No DUID. Indicate an error.
559 .arg(config_->getThisServerName())
560 .arg(lease6->addr_);
561 return (-1);
562 }
563
564 // The hash value modulo number of active servers gives an index
565 // of the server to process the packet.
566 return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
567}
568
569uint8_t
570QueryFilter::loadBalanceHash(const uint8_t* key, const size_t key_len) const {
571 uint8_t hash = static_cast<uint8_t>(key_len);
572
573 for (size_t i = key_len; i > 0;) {
574 hash = loadb_mx_tbl[hash ^ key[--i]];
575 }
576
577 return (hash);
578}
579
580void
581QueryFilter::validateScopeName(const std::string& scope_name) const {
582 try {
583 // If there is no such server, the scope name is invalid.
584 static_cast<void>(config_->getPeerConfig(scope_name));
585
586 } catch (...) {
587 isc_throw(BadValue, "invalid server name specified '" << scope_name
588 << "' while enabling/disabling HA scopes");
589 }
590}
591
592std::string
593QueryFilter::makeScopeClass(const std::string& scope_name) const {
594 return (std::string("HA_") + scope_name);
595}
596
597} // end of namespace isc::ha
598} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Role
Server's role in the High Availability setup.
Definition ha_config.h:85
std::map< std::string, PeerConfigPtr > PeerConfigMap
Map of the servers' configurations.
Definition ha_config.h:258
boost::shared_ptr< PeerConfig > PeerConfigPtr
Pointer to the server's configuration.
Definition ha_config.h:255
void serveScopes(const std::vector< std::string > &scopes)
Enables selected scopes.
bool inScope(const dhcp::Pkt4Ptr &query4, std::string &scope_class) const
Checks if this server should process the DHCPv4 query.
bool amServingScope(const std::string &scope_name) const
Checks if this server instance is configured to process traffic belonging to a particular scope.
std::string makeScopeClass(const std::string &scope_name) const
Returns scope class name for the specified scope name.
boost::scoped_ptr< std::mutex > mutex_
Mutex to protect the internal state.
void serveFailoverScopes()
Enable scopes required in failover case.
uint8_t loadBalanceHash(const uint8_t *key, const size_t key_len) const
Compute load balancing hash.
void validateScopeName(const std::string &scope_name) const
Checks if the scope name matches a name of any of the configured servers.
int active_servers_
Number of the active servers in the given HA mode.
HAConfigPtr config_
Pointer to the HA configuration.
void serveScopeOnly(const std::string &scope_name)
Enable scope and disable all other scopes.
int loadBalance(const dhcp::Pkt4Ptr &query4) const
Performs load balancing of the DHCPv4 queries.
static bool isHaType(const dhcp::Pkt4Ptr &query4)
Determines if a DHCPv4 query is a message type HA should process.
void serveDefaultScopes()
Serve default scopes for the given HA mode.
void serveNoScopes()
Disables all scopes.
std::set< std::string > getServedScopes() const
Returns served scopes.
void serveScope(const std::string &scope_name)
Enable scope.
std::vector< HAConfig::PeerConfigPtr > peers_
Vector of HA peers configurations.
std::map< std::string, bool > scopes_
Holds mapping of the scope names to the flag which indicates if the scopes are enabled or disabled.
QueryFilter(const HAConfigPtr &config)
Constructor.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
@ D6O_CLIENTID
Definition dhcp6.h:21
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition dhcp4.h:130
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:556
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:166
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:343
boost::shared_ptr< Option > OptionPtr
Definition option.h:38
const isc::log::MessageID HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING
Definition ha_messages.h:89
isc::log::Logger ha_logger("ha-hooks")
Definition ha_log.h:17
const isc::log::MessageID HA_LOAD_BALANCING_LEASE_DUID_MISSING
Definition ha_messages.h:88
boost::shared_ptr< HAConfig > HAConfigPtr
Pointer to the High Availability configuration structure.
Definition ha_config.h:39
const isc::log::MessageID HA_LOAD_BALANCING_DUID_MISSING
Definition ha_messages.h:86
const isc::log::MessageID HA_LOAD_BALANCING_IDENTIFIER_MISSING
Definition ha_messages.h:87
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.