Kea  1.5.0
host_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2018 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 #include <dhcpsrv/cfg_hosts.h>
9 #include <dhcpsrv/cfgmgr.h>
10 #include <dhcpsrv/host_mgr.h>
11 #include <dhcpsrv/hosts_log.h>
13 
14 namespace {
15 
22 isc::dhcp::ConstCfgHostsPtr getCfgHosts() {
23  return (isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgHosts());
24 }
25 
26 } // end of anonymous namespace
27 
28 namespace isc {
29 namespace dhcp {
30 
31 using namespace isc::asiolink;
32 
33 boost::scoped_ptr<HostMgr>&
34 HostMgr::getHostMgrPtr() {
35  static boost::scoped_ptr<HostMgr> host_mgr_ptr;
36  return (host_mgr_ptr);
37 }
38 
39 void
41  getHostMgrPtr().reset(new HostMgr());
42 }
43 
44 void
45 HostMgr::addBackend(const std::string& access) {
46  HostDataSourceFactory::add(getHostMgrPtr()->alternate_sources_, access);
47 }
48 
49 bool
50 HostMgr::delBackend(const std::string& db_type) {
51  return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type));
52 }
53 
54 void
56  getHostMgrPtr()->alternate_sources_.clear();
57 }
58 
61  if (alternate_sources_.empty()) {
62  return (HostDataSourcePtr());
63  }
64  return (alternate_sources_[0]);
65 }
66 
67 bool
69  if (getHostMgrPtr()->cache_ptr_) {
70  return (true);
71  }
72  HostDataSourceList& sources = getHostMgrPtr()->alternate_sources_;
73  if (sources.empty()) {
74  return (false);
75  }
76  CacheHostDataSourcePtr cache_ptr =
77  boost::dynamic_pointer_cast<CacheHostDataSource>(sources[0]);
78  if (cache_ptr) {
79  getHostMgrPtr()->cache_ptr_ = cache_ptr;
80  if (logging) {
81  LOG_INFO(hosts_logger, HOSTS_CFG_CACHE_HOST_DATA_SOURCE)
82  .arg(cache_ptr->getType());
83  }
84  return (true);
85  }
86  return (false);
87 }
88 
89 HostMgr&
91  boost::scoped_ptr<HostMgr>& host_mgr_ptr = getHostMgrPtr();
92  if (!host_mgr_ptr) {
93  create();
94  }
95  return (*host_mgr_ptr);
96 }
97 
99 HostMgr::getAll(const Host::IdentifierType& identifier_type,
100  const uint8_t* identifier_begin,
101  const size_t identifier_len) const {
102  ConstHostCollection hosts = getCfgHosts()->getAll(identifier_type,
103  identifier_begin,
104  identifier_len);
105  for (auto source : alternate_sources_) {
106  ConstHostCollection hosts_plus =
107  source->getAll(identifier_type, identifier_begin, identifier_len);
108  hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
109  }
110  return (hosts);
111 }
112 
113 
115 HostMgr::getAll4(const IOAddress& address) const {
116  ConstHostCollection hosts = getCfgHosts()->getAll4(address);
117  for (auto source : alternate_sources_) {
118  ConstHostCollection hosts_plus = source->getAll4(address);
119  hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
120  }
121  return (hosts);
122 }
123 
125 HostMgr::get4Any(const SubnetID& subnet_id,
126  const Host::IdentifierType& identifier_type,
127  const uint8_t* identifier_begin,
128  const size_t identifier_len) const {
129  ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
130  identifier_begin, identifier_len);
131 
132  // Found it in the config file or there are no backends configured?
133  // Then we're done here.
134  if (host || alternate_sources_.empty()) {
135  return (host);
136  }
137 
139  HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER)
140  .arg(subnet_id)
141  .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
142  identifier_len));
143 
144  // Try to find a host in each configured backend. We return as soon
145  // as we find first hit.
146  for (auto source : alternate_sources_) {
147  host = source->get4(subnet_id, identifier_type,
148  identifier_begin, identifier_len);
149 
150  if (host) {
152  HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST)
153  .arg(subnet_id)
154  .arg(Host::getIdentifierAsText(identifier_type,
155  identifier_begin,
156  identifier_len))
157  .arg(source->getType())
158  .arg(host->toText());
159 
160  if (source != cache_ptr_) {
161  cache(host);
162  }
163  return (host);
164  }
165  }
167  HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
168  .arg(subnet_id)
169  .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
170  identifier_len));
171  return (ConstHostPtr());
172 }
173 
175 HostMgr::get4(const SubnetID& subnet_id,
176  const Host::IdentifierType& identifier_type,
177  const uint8_t* identifier_begin,
178  const size_t identifier_len) const {
179  ConstHostPtr host = get4Any(subnet_id, identifier_type,
180  identifier_begin, identifier_len);
181  if (host && host->getNegative()) {
182  return (ConstHostPtr());
183  } else if (!host && negative_caching_) {
184  cacheNegative(subnet_id, SubnetID(SUBNET_ID_UNUSED),
185  identifier_type, identifier_begin, identifier_len);
186  }
187  return (host);
188 }
189 
191 HostMgr::get4(const SubnetID& subnet_id,
192  const asiolink::IOAddress& address) const {
193  ConstHostPtr host = getCfgHosts()->get4(subnet_id, address);
194  if (host || alternate_sources_.empty()) {
195  return (host);
196  }
198  HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4)
199  .arg(subnet_id)
200  .arg(address.toText());
201  for (auto source : alternate_sources_) {
202  host = source->get4(subnet_id, address);
203  if (host && host->getNegative()) {
204  return (ConstHostPtr());
205  }
206  if (host && source != cache_ptr_) {
207  cache(host);
208  }
209  if (host) {
210  return (host);
211  }
212  }
213  return (ConstHostPtr());
214 }
215 
216 
218 HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
219  ConstHostPtr host = getCfgHosts()->get6(prefix, prefix_len);
220  if (host || alternate_sources_.empty()) {
221  return (host);
222  }
223  LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_MGR_ALTERNATE_GET6_PREFIX)
224  .arg(prefix.toText())
225  .arg(static_cast<int>(prefix_len));
226  for (auto source : alternate_sources_) {
227  host = source->get6(prefix, prefix_len);
228  if (host && host->getNegative()) {
229  return (ConstHostPtr());
230  }
231  if (host && source != cache_ptr_) {
232  cache(host);
233  }
234  if (host) {
235  return (host);
236  }
237  }
238  return (ConstHostPtr());
239 }
240 
242 HostMgr::get6Any(const SubnetID& subnet_id,
243  const Host::IdentifierType& identifier_type,
244  const uint8_t* identifier_begin,
245  const size_t identifier_len) const {
246  ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
247  identifier_begin, identifier_len);
248  if (host || alternate_sources_.empty()) {
249  return (host);
250  }
251 
253  HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER)
254  .arg(subnet_id)
255  .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
256  identifier_len));
257 
258  for (auto source : alternate_sources_) {
259  host = source->get6(subnet_id, identifier_type,
260  identifier_begin, identifier_len);
261 
262  if (host) {
264  HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
265  .arg(subnet_id)
266  .arg(Host::getIdentifierAsText(identifier_type,
267  identifier_begin,
268  identifier_len))
269  .arg(source->getType())
270  .arg(host->toText());
271 
272  if (source != cache_ptr_) {
273  cache(host);
274  }
275  return (host);
276  }
277  }
278 
280  HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
281  .arg(subnet_id)
282  .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
283  identifier_len));
284 
285  return (ConstHostPtr());
286 }
287 
289 HostMgr::get6(const SubnetID& subnet_id,
290  const Host::IdentifierType& identifier_type,
291  const uint8_t* identifier_begin,
292  const size_t identifier_len) const {
293  ConstHostPtr host = get6Any(subnet_id, identifier_type,
294  identifier_begin, identifier_len);
295  if (host && host->getNegative()) {
296  return (ConstHostPtr());
297  } else if (!host && negative_caching_) {
298  cacheNegative(SubnetID(SUBNET_ID_UNUSED), subnet_id,
299  identifier_type, identifier_begin, identifier_len);
300  }
301  return (host);
302 }
303 
305 HostMgr::get6(const SubnetID& subnet_id,
306  const asiolink::IOAddress& addr) const {
307  ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
308  if (host || alternate_sources_.empty()) {
309  return (host);
310  }
312  HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6)
313  .arg(subnet_id)
314  .arg(addr.toText());
315  for (auto source : alternate_sources_) {
316  host = source->get6(subnet_id, addr);
317  if (host && host->getNegative()) {
318  return (ConstHostPtr());
319  }
320  if (host && source != cache_ptr_) {
321  cache(host);
322  }
323  if (host) {
324  return (host);
325  }
326  }
327  return (ConstHostPtr());
328 }
329 
330 void
331 HostMgr::add(const HostPtr& host) {
332  if (alternate_sources_.empty()) {
333  isc_throw(NoHostDataSourceManager, "Unable to add new host because there is "
334  "no hosts-database configured.");
335  }
336  for (auto source : alternate_sources_) {
337  source->add(host);
338  }
339  // If no backend throws the host should be cached.
340  if (cache_ptr_) {
341  cache(host);
342  }
343 }
344 
345 bool
346 HostMgr::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
347  if (alternate_sources_.empty()) {
348  isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
349  "no hosts-database configured.");
350  }
351 
352  for (auto source : alternate_sources_) {
353  if (source->del(subnet_id, addr)) {
354  return (true);
355  }
356  }
357  return (false);
358 }
359 
360 bool
361 HostMgr::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
362  const uint8_t* identifier_begin, const size_t identifier_len) {
363  if (alternate_sources_.empty()) {
364  isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
365  "no hosts-database configured.");
366  }
367 
368  for (auto source : alternate_sources_) {
369  if (source->del4(subnet_id, identifier_type,
370  identifier_begin, identifier_len)) {
371  return (true);
372  }
373  }
374  return (false);
375 }
376 
377 bool
378 HostMgr::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
379  const uint8_t* identifier_begin, const size_t identifier_len) {
380  if (alternate_sources_.empty()) {
381  isc_throw(NoHostDataSourceManager, "unable to delete a host because there is "
382  "no alternate host data source present");
383  }
384 
385  for (auto source : alternate_sources_) {
386  if (source->del6(subnet_id, identifier_type,
387  identifier_begin, identifier_len)) {
388  return (true);
389  }
390  }
391  return (false);
392 }
393 
394 void
396  if (cache_ptr_) {
397  // Need a real host.
398  if (!host || host->getNegative()) {
399  return;
400  }
401  // Replace any existing value.
402  // Don't check the result as it does not matter?
403  cache_ptr_->insert(host, true);
404  }
405 }
406 
407 void
408 HostMgr::cacheNegative(const SubnetID& ipv4_subnet_id,
409  const SubnetID& ipv6_subnet_id,
410  const Host::IdentifierType& identifier_type,
411  const uint8_t* identifier_begin,
412  const size_t identifier_len) const {
413  if (cache_ptr_ && negative_caching_) {
414  HostPtr host(new Host(identifier_begin, identifier_len,
415  identifier_type,
416  ipv4_subnet_id, ipv6_subnet_id,
418  host->setNegative(true);
419  // Don't replace any existing value.
420  // nor matter if it fails.
421  cache_ptr_->insert(host, false);
422  }
423 }
424 
425 } // end of isc::dhcp namespace
426 } // end of isc namespace
isc::dhcp::hosts_logger
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
Definition: hosts_log.h:51
cfg_hosts.h
hosts_log.h
isc::dhcp::CfgMgr::instance
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
isc::dhcp::Host::IdentifierType
IdentifierType
Type of the host identifier.
Definition: host.h:252
isc::dhcp::HostMgr::get4
virtual ConstHostPtr get4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv4 subnet.
Definition: host_mgr.cc:175
isc::dhcp::HostMgr::checkCacheBackend
static bool checkCacheBackend(bool logging=false)
Check for the cache host backend.
Definition: host_mgr.cc:68
isc::dhcp::HostMgr::addBackend
static void addBackend(const std::string &access)
Add an alternate host backend (aka host data source).
Definition: host_mgr.cc:45
isc::dhcp::HostMgr::get4Any
virtual ConstHostPtr get4Any(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns any host connected to the IPv4 subnet.
Definition: host_mgr.cc:125
isc::dhcp::HostMgr::create
static void create()
Creates new instance of the HostMgr.
Definition: host_mgr.cc:40
isc::dhcp::Host
Represents a device with IPv4 and/or IPv6 reservations.
Definition: host.h:242
isc::dhcp::HostPtr
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:725
isc::dhcp::HostMgr::get6
virtual ConstHostPtr get6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv6 subnet.
Definition: host_mgr.cc:289
isc::dhcp::HostMgr::getAll
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Return all hosts connected to any subnet for which reservations have been made using a specified iden...
Definition: host_mgr.cc:99
isc::dhcp::HostMgr::del4
virtual bool del4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet4-id, identifier, identifier-type)
Definition: host_mgr.cc:361
isc::dhcp::HostMgr::getHostDataSource
HostDataSourcePtr getHostDataSource() const
Returns the first host data source.
Definition: host_mgr.cc:60
isc::dhcp::HostMgr::add
virtual void add(const HostPtr &host)
Adds a new host to the alternate data source.
Definition: host_mgr.cc:331
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::dhcp::HostMgr::get6Any
virtual ConstHostPtr get6Any(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns any host connected to the IPv6 subnet.
Definition: host_mgr.cc:242
isc::dhcp::HostDataSourceList
std::vector< HostDataSourcePtr > HostDataSourceList
HostDataSource list.
Definition: base_host_data_source.h:254
isc::dhcp::HostMgr::del
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete a host by address.
Definition: host_mgr.cc:346
isc::dhcp::NoHostDataSourceManager
No host data source instance exception.
Definition: host_data_source_factory.h:27
isc::dhcp::HOSTS_DBG_RESULTS
const int HOSTS_DBG_RESULTS
Records the results of the lookups.
Definition: hosts_log.h:33
isc::dhcp::HostDataSourceFactory::del
static bool del(HostDataSourceList &sources, const std::string &db_type)
Delete a host data source.
Definition: host_data_source_factory.cc:80
isc::dhcp::HostMgr::del6
virtual bool del6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet6-id, identifier, identifier-type)
Definition: host_mgr.cc:378
isc::dhcp::HostMgr::delBackend
static bool delBackend(const std::string &db_type)
Delete an alternate host backend (aka host data source).
Definition: host_mgr.cc:50
isc::dhcp::Host::getIdentifierAsText
std::string getIdentifierAsText() const
Returns host identifier in a textual form.
Definition: host.cc:239
isc::dhcp::CacheHostDataSourcePtr
boost::shared_ptr< CacheHostDataSource > CacheHostDataSourcePtr
CacheHostDataSource pointer.
Definition: cache_host_data_source.h:62
cfgmgr.h
isc::dhcp::HostMgr::instance
static HostMgr & instance()
Returns a sole instance of the HostMgr.
Definition: host_mgr.cc:90
isc::dhcp::HOSTS_DBG_TRACE
const int HOSTS_DBG_TRACE
Logging levels for the host reservations management.
Definition: hosts_log.h:27
isc::dhcp::HostDataSourceFactory::add
static void add(HostDataSourceList &sources, const std::string &dbaccess)
Create and add an instance of a host data source.
Definition: host_data_source_factory.cc:46
isc::dhcp::HostDataSourcePtr
boost::shared_ptr< BaseHostDataSource > HostDataSourcePtr
HostDataSource pointer.
Definition: base_host_data_source.h:251
isc::dhcp::ConstHostCollection
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:731
host_data_source_factory.h
isc::dhcp::HostMgr::cacheNegative
virtual void cacheNegative(const SubnetID &ipv4_subnet_id, const SubnetID &ipv6_subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Cache a negative answer.
Definition: host_mgr.cc:408
isc::dhcp::ConstHostPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:728
host_mgr.h
isc::dhcp::HostMgr::cache
virtual void cache(ConstHostPtr host) const
Cache an answer.
Definition: host_mgr.cc:395
isc::dhcp::SubnetID
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
isc::dhcp::HostMgr::getAll4
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Returns a collection of hosts using the specified IPv4 address.
Definition: host_mgr.cc:115
isc::dhcp::HostMgr
Host Manager.
Definition: host_mgr.h:54
isc::dhcp::ConstCfgHostsPtr
boost::shared_ptr< const CfgHosts > ConstCfgHostsPtr
Const pointer.
Definition: cfg_hosts.h:485
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
isc::dhcp::HostMgr::delAllBackends
static void delAllBackends()
Delete all alternate backends.
Definition: host_mgr.cc:55