Kea  2.1.7-git
cfg_hosts.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2020 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 <dhcp/duid.h>
9 #include <dhcp/hwaddr.h>
10 #include <dhcpsrv/cfg_hosts.h>
11 #include <dhcpsrv/cfg_hosts_util.h>
12 #include <dhcpsrv/hosts_log.h>
13 #include <dhcpsrv/cfgmgr.h>
14 #include <exceptions/exceptions.h>
15 #include <util/encode/hex.h>
16 #include <ostream>
17 #include <string>
18 #include <vector>
19 
20 using namespace isc::asiolink;
21 using namespace isc::data;
22 
23 namespace isc {
24 namespace dhcp {
25 
27 CfgHosts::getAll(const Host::IdentifierType& identifier_type,
28  const uint8_t* identifier_begin,
29  const size_t identifier_len) const {
30  // Do not issue logging message here because it will be logged by
31  // the getAllInternal method.
32  ConstHostCollection collection;
33  getAllInternal<ConstHostCollection>(identifier_type, identifier_begin,
34  identifier_len, collection);
35  return (collection);
36 }
37 
39 CfgHosts::getAll(const Host::IdentifierType& identifier_type,
40  const uint8_t* identifier_begin, const size_t identifier_len) {
41  // Do not issue logging message here because it will be logged by
42  // the getAllInternal method.
43  HostCollection collection;
44  getAllInternal<HostCollection>(identifier_type, identifier_begin,
45  identifier_len, collection);
46  return (collection);
47 }
48 
50 CfgHosts::getAll4(const SubnetID& subnet_id) const {
51  // Do not issue logging message here because it will be logged by
52  // the getAllInternal4 method.
53  ConstHostCollection collection;
54  getAllInternal4<ConstHostCollection>(subnet_id, collection);
55  return (collection);
56 }
57 
59 CfgHosts::getAll4(const SubnetID& subnet_id) {
60  // Do not issue logging message here because it will be logged by
61  // the getAllInternal4 method.
62  HostCollection collection;
63  getAllInternal4<HostCollection>(subnet_id, collection);
64  return (collection);
65 }
66 
68 CfgHosts::getAll6(const SubnetID& subnet_id) const {
69  // Do not issue logging message here because it will be logged by
70  // the getAllInternal6 method.
71  ConstHostCollection collection;
72  getAllInternal6<ConstHostCollection>(subnet_id, collection);
73  return (collection);
74 }
75 
77 CfgHosts::getAll6(const SubnetID& subnet_id) {
78  // Do not issue logging message here because it will be logged by
79  // the getAllInternal6 method.
80  HostCollection collection;
81  getAllInternal6<HostCollection>(subnet_id, collection);
82  return (collection);
83 }
84 
86 CfgHosts::getAllbyHostname(const std::string& hostname) const {
87  // Do not issue logging message here because it will be logged by
88  // the getAllbyHostnameInternal method.
89  ConstHostCollection collection;
90  getAllbyHostnameInternal<ConstHostCollection>(hostname, collection);
91  return (collection);
92 }
93 
95 CfgHosts::getAllbyHostname(const std::string& hostname) {
96  // Do not issue logging message here because it will be logged by
97  // the getAllbyHostnameInternal method.
98  HostCollection collection;
99  getAllbyHostnameInternal<HostCollection>(hostname, collection);
100  return (collection);
101 }
102 
104 CfgHosts::getAllbyHostname4(const std::string& hostname,
105  const SubnetID& subnet_id) const {
106  // Do not issue logging message here because it will be logged by
107  // the getAllbyHostnameInternal4 method.
108  ConstHostCollection collection;
109  getAllbyHostnameInternal4<ConstHostCollection>(hostname, subnet_id, collection);
110  return (collection);
111 }
112 
114 CfgHosts::getAllbyHostname4(const std::string& hostname,
115  const SubnetID& subnet_id) {
116  // Do not issue logging message here because it will be logged by
117  // the getAllbyHostnameInternal4 method.
118  HostCollection collection;
119  getAllbyHostnameInternal4<HostCollection>(hostname, subnet_id, collection);
120  return (collection);
121 }
122 
124 CfgHosts::getAllbyHostname6(const std::string& hostname,
125  const SubnetID& subnet_id) const {
126  // Do not issue logging message here because it will be logged by
127  // the getAllbyHostnameInternal6 method.
128  ConstHostCollection collection;
129  getAllbyHostnameInternal6<ConstHostCollection>(hostname, subnet_id, collection);
130  return (collection);
131 }
132 
134 CfgHosts::getAllbyHostname6(const std::string& hostname,
135  const SubnetID& subnet_id) {
136  // Do not issue logging message here because it will be logged by
137  // the getAllbyHostnameInternal6 method.
138  HostCollection collection;
139  getAllbyHostnameInternal6<HostCollection>(hostname, subnet_id, collection);
140  return (collection);
141 }
142 
144 CfgHosts::getPage4(const SubnetID& subnet_id,
145  size_t& /*source_index*/,
146  uint64_t lower_host_id,
147  const HostPageSize& page_size) const {
148  // Do not issue logging message here because it will be logged by
149  // the getPageInternal4 method.
150  ConstHostCollection collection;
151  getPageInternal4<ConstHostCollection>(subnet_id,
152  lower_host_id,
153  page_size,
154  collection);
155  return (collection);
156 }
157 
159 CfgHosts::getPage4(const SubnetID& subnet_id,
160  size_t& /*source_index*/,
161  uint64_t lower_host_id,
162  const HostPageSize& page_size) {
163  // Do not issue logging message here because it will be logged by
164  // the getPageInternal4 method.
165  HostCollection collection;
166  getPageInternal4<HostCollection>(subnet_id,
167  lower_host_id,
168  page_size,
169  collection);
170  return (collection);
171 }
172 
174 CfgHosts::getPage6(const SubnetID& subnet_id,
175  size_t& /*source_index*/,
176  uint64_t lower_host_id,
177  const HostPageSize& page_size) const {
178  // Do not issue logging message here because it will be logged by
179  // the getPageInternal6 method.
180  ConstHostCollection collection;
181  getPageInternal6<ConstHostCollection>(subnet_id,
182  lower_host_id,
183  page_size,
184  collection);
185  return (collection);
186 }
187 
189 CfgHosts::getPage6(const SubnetID& subnet_id,
190  size_t& /*source_index*/,
191  uint64_t lower_host_id,
192  const HostPageSize& page_size) {
193  // Do not issue logging message here because it will be logged by
194  // the getPageInternal6 method.
195  HostCollection collection;
196  getPageInternal6<HostCollection>(subnet_id,
197  lower_host_id,
198  page_size,
199  collection);
200  return (collection);
201 }
202 
204 CfgHosts::getPage4(size_t& /*source_index*/,
205  uint64_t lower_host_id,
206  const HostPageSize& page_size) const {
207  // Do not issue logging message here because it will be logged by
208  // the getPageInternal method.
209  ConstHostCollection collection;
210  getPageInternal<ConstHostCollection>(lower_host_id,
211  page_size,
212  collection);
213  return (collection);
214 }
215 
217 CfgHosts::getPage4(size_t& /*source_index*/,
218  uint64_t lower_host_id,
219  const HostPageSize& page_size) {
220  // Do not issue logging message here because it will be logged by
221  // the getPageInternal method.
222  HostCollection collection;
223  getPageInternal<HostCollection>(lower_host_id,
224  page_size,
225  collection);
226  return (collection);
227 }
228 
230 CfgHosts::getPage6(size_t& /*source_index*/,
231  uint64_t lower_host_id,
232  const HostPageSize& page_size) const {
233  // Do not issue logging message here because it will be logged by
234  // the getPageInternal method.
235  ConstHostCollection collection;
236  getPageInternal<ConstHostCollection>(lower_host_id,
237  page_size,
238  collection);
239  return (collection);
240 }
241 
243 CfgHosts::getPage6(size_t& /*source_index*/,
244  uint64_t lower_host_id,
245  const HostPageSize& page_size) {
246  // Do not issue logging message here because it will be logged by
247  // the getPageInternal method.
248  HostCollection collection;
249  getPageInternal<HostCollection>(lower_host_id,
250  page_size,
251  collection);
252  return (collection);
253 }
254 
256 CfgHosts::getAll4(const IOAddress& address) const {
257  // Do not issue logging message here because it will be logged by
258  // the getAllInternal4 method.
259  ConstHostCollection collection;
260  getAllInternal4<ConstHostCollection>(address, collection);
261  return (collection);
262 }
263 
265 CfgHosts::getAll4(const IOAddress& address) {
266  // Do not issue logging message here because it will be logged by
267  // the getAllInternal4 method.
268  HostCollection collection;
269  getAllInternal4<HostCollection>(address, collection);
270  return (collection);
271 }
272 
274 CfgHosts::getAll6(const IOAddress& address) const {
275  // Do not issue logging message here because it will be logged by
276  // the getAllInternal6 method.
277  ConstHostCollection collection;
278  getAllInternal6<ConstHostCollection>(address, collection);
279  return (collection);
280 }
281 
283 CfgHosts::getAll6(const IOAddress& address) {
284  // Do not issue logging message here because it will be logged by
285  // the getAllInternal6 method.
286  HostCollection collection;
287  getAllInternal6<HostCollection>(address, collection);
288  return (collection);
289 }
290 
291 template<typename Storage>
292 void
293 CfgHosts::getAllInternal(const Host::IdentifierType& identifier_type,
294  const uint8_t* identifier,
295  const size_t identifier_len,
296  Storage& storage) const {
297 
298  // Convert host identifier into textual format for logging purposes.
299  // This conversion is exception free.
300  std::string identifier_text = Host::getIdentifierAsText(identifier_type,
301  identifier,
302  identifier_len);
304  .arg(identifier_text);
305 
306  // Use the identifier and identifier type as a composite key.
307  const HostContainerIndex0& idx = hosts_.get<0>();
308  boost::tuple<const std::vector<uint8_t>, const Host::IdentifierType> t =
309  boost::make_tuple(std::vector<uint8_t>(identifier,
310  identifier + identifier_len),
311  identifier_type);
312 
313  // Append each Host object to the storage.
314  for (HostContainerIndex0::iterator host = idx.lower_bound(t);
315  host != idx.upper_bound(t);
316  ++host) {
319  .arg(identifier_text)
320  .arg((*host)->toText());
321  storage.push_back(*host);
322  }
323 
324  // Log how many hosts have been found.
326  .arg(identifier_text)
327  .arg(storage.size());
328 }
329 
330 template<typename Storage>
331 void
332 CfgHosts::getAllInternal4(const SubnetID& subnet_id,
333  Storage& storage) const {
334 
336  .arg(subnet_id);
337 
338  // Use try DHCPv4 subnet id.
339  const HostContainerIndex2& idx = hosts_.get<2>();
340 
341  // Append each Host object to the storage.
342  for (HostContainerIndex2::iterator host = idx.lower_bound(subnet_id);
343  host != idx.upper_bound(subnet_id);
344  ++host) {
347  .arg(subnet_id)
348  .arg((*host)->toText());
349  storage.push_back(*host);
350  }
351 
352  // Log how many hosts have been found.
354  .arg(subnet_id)
355  .arg(storage.size());
356 }
357 
358 template<typename Storage>
359 void
360 CfgHosts::getAllInternal6(const SubnetID& subnet_id,
361  Storage& storage) const {
362 
364  .arg(subnet_id);
365 
366  // Use try DHCPv6 subnet id.
367  const HostContainerIndex3& idx = hosts_.get<3>();
368 
369  // Append each Host object to the storage.
370  for (HostContainerIndex3::iterator host = idx.lower_bound(subnet_id);
371  host != idx.upper_bound(subnet_id);
372  ++host) {
375  .arg(subnet_id)
376  .arg((*host)->toText());
377  storage.push_back(*host);
378  }
379 
380  // Log how many hosts have been found.
382  .arg(subnet_id)
383  .arg(storage.size());
384 }
385 
386 template<typename Storage>
387 void
388 CfgHosts::getAllbyHostnameInternal(const std::string& hostname,
389  Storage& storage) const {
390 
392  .arg(hostname);
393 
394  // Use try hostname.
395  const HostContainerIndex5& idx = hosts_.get<5>();
396 
397  // Append each Host object to the storage.
398  for (HostContainerIndex5::iterator host = idx.lower_bound(hostname);
399  host != idx.upper_bound(hostname);
400  ++host) {
403  .arg(hostname)
404  .arg((*host)->toText());
405  storage.push_back(*host);
406  }
407 
408  // Log how many hosts have been found.
410  .arg(hostname)
411  .arg(storage.size());
412 }
413 
414 template<typename Storage>
415 void
416 CfgHosts::getAllbyHostnameInternal4(const std::string& hostname,
417  const SubnetID& subnet_id,
418  Storage& storage) const {
419 
422  .arg(hostname)
423  .arg(subnet_id);
424 
425  // Use try hostname.
426  const HostContainerIndex5& idx = hosts_.get<5>();
427 
428  // Append each Host object to the storage.
429  for (HostContainerIndex5::iterator host = idx.lower_bound(hostname);
430  host != idx.upper_bound(hostname);
431  ++host) {
432  if ((*host)->getIPv4SubnetID() != subnet_id) {
433  continue;
434  }
437  .arg(hostname)
438  .arg(subnet_id)
439  .arg((*host)->toText());
440  storage.push_back(*host);
441  }
442 
443  // Log how many hosts have been found.
446  .arg(hostname)
447  .arg(subnet_id)
448  .arg(storage.size());
449 }
450 
451 template<typename Storage>
452 void
453 CfgHosts::getAllbyHostnameInternal6(const std::string& hostname,
454  const SubnetID& subnet_id,
455  Storage& storage) const {
456 
459  .arg(hostname)
460  .arg(subnet_id);
461 
462  // Use try hostname.
463  const HostContainerIndex5& idx = hosts_.get<5>();
464 
465  // Append each Host object to the storage.
466  for (HostContainerIndex5::iterator host = idx.lower_bound(hostname);
467  host != idx.upper_bound(hostname);
468  ++host) {
469  if ((*host)->getIPv6SubnetID() != subnet_id) {
470  continue;
471  }
474  .arg(hostname)
475  .arg(subnet_id)
476  .arg((*host)->toText());
477  storage.push_back(*host);
478  }
479 
480  // Log how many hosts have been found.
483  .arg(hostname)
484  .arg(subnet_id)
485  .arg(storage.size());
486 }
487 
488 template<typename Storage>
489 void
490 CfgHosts::getPageInternal(uint64_t lower_host_id,
491  const HostPageSize& page_size,
492  Storage& storage) const {
493 
495 
496  // Use the host id last index.
497  const HostContainerIndex4& idx = hosts_.get<4>();
498  HostContainerIndex4::const_iterator host = idx.lower_bound(lower_host_id);
499 
500  // Exclude the lower bound id when it is not zero.
501  if (lower_host_id &&
502  (host != idx.end()) && ((*host)->getHostId() == lower_host_id)) {
503  ++host;
504  }
505 
506  // Return hosts within the page size.
507  for (; host != idx.end(); ++host) {
510  .arg((*host)->toText());
511  storage.push_back(*host);
512  if (storage.size() >= page_size.page_size_) {
513  break;
514  }
515  }
516 
517  // Log how many hosts have been found.
519  .arg(storage.size());
520 }
521 
522 template<typename Storage>
523 void
524 CfgHosts::getPageInternal4(const SubnetID& subnet_id,
525  uint64_t lower_host_id,
526  const HostPageSize& page_size,
527  Storage& storage) const {
528 
530  .arg(subnet_id);
531 
532  // Use the host id last index.
533  const HostContainerIndex4& idx = hosts_.get<4>();
534  HostContainerIndex4::const_iterator host = idx.lower_bound(lower_host_id);
535 
536  // Exclude the lower bound id when it is not zero.
537  if (lower_host_id &&
538  (host != idx.end()) && ((*host)->getHostId() == lower_host_id)) {
539  ++host;
540  }
541 
542  // Return hosts in the subnet within the page size.
543  for (; host != idx.end(); ++host) {
544  if ((*host)->getIPv4SubnetID() != subnet_id) {
545  continue;
546  }
549  .arg(subnet_id)
550  .arg((*host)->toText());
551  storage.push_back(*host);
552  if (storage.size() >= page_size.page_size_) {
553  break;
554  }
555  }
556 
557  // Log how many hosts have been found.
559  .arg(subnet_id)
560  .arg(storage.size());
561 }
562 
563 template<typename Storage>
564 void
565 CfgHosts::getPageInternal6(const SubnetID& subnet_id,
566  uint64_t lower_host_id,
567  const HostPageSize& page_size,
568  Storage& storage) const {
569 
571  .arg(subnet_id);
572 
573  // Use the host id last index.
574  const HostContainerIndex4& idx = hosts_.get<4>();
575  HostContainerIndex4::const_iterator host = idx.lower_bound(lower_host_id);
576 
577  // Exclude the lower bound id when it is not zero.
578  if (lower_host_id &&
579  (host != idx.end()) && ((*host)->getHostId() == lower_host_id)) {
580  ++host;
581  }
582 
583  // Return hosts in the subnet within the page size.
584  for (; host != idx.end(); ++host) {
585  if ((*host)->getIPv6SubnetID() != subnet_id) {
586  continue;
587  }
590  .arg(subnet_id)
591  .arg((*host)->toText());
592  storage.push_back(*host);
593  if (storage.size() >= page_size.page_size_) {
594  break;
595  }
596  }
597 
598  // Log how many hosts have been found.
600  .arg(subnet_id)
601  .arg(storage.size());
602 }
603 
604 
605 template<typename Storage>
606 void
607 CfgHosts::getAllInternal4(const IOAddress& address, Storage& storage) const {
609  .arg(address.toText());
610 
611  // Must not specify address other than IPv4.
612  if (!address.isV4()) {
613  isc_throw(BadHostAddress, "must specify an IPv4 address when searching"
614  " for a host, specified address was " << address);
615  }
616  // Search for the Host using the reserved IPv4 address as a key.
617  const HostContainerIndex1& idx = hosts_.get<1>();
618  HostContainerIndex1Range r = idx.equal_range(address);
619  // Append each Host object to the storage.
620  for (HostContainerIndex1::iterator host = r.first; host != r.second;
621  ++host) {
624  .arg(address.toText())
625  .arg((*host)->toText());
626  storage.push_back(*host);
627  }
628 
630  .arg(address.toText())
631  .arg(storage.size());
632 }
633 
634 template<typename Storage>
635 void
636 CfgHosts::getAllInternal6(const IOAddress& address, Storage& storage) const {
638  .arg(address.toText());
639 
640  // Must not specify address other than IPv6.
641  if (!address.isV6()) {
642  isc_throw(BadHostAddress, "must specify an IPv6 address when searching"
643  " for a host, specified address was " << address);
644  }
645  // Search for the Host using the reserved IPv6 address as a key.
646  const HostContainerIndex1& idx = hosts_.get<1>();
647  HostContainerIndex1Range r = idx.equal_range(address);
648  // Append each Host object to the storage.
649  for (HostContainerIndex1::iterator host = r.first; host != r.second;
650  ++host) {
653  .arg(address.toText())
654  .arg((*host)->toText());
655  storage.push_back(*host);
656  }
657 
659  .arg(address.toText())
660  .arg(storage.size());
661 }
662 
664 CfgHosts::get4(const SubnetID& subnet_id,
665  const Host::IdentifierType& identifier_type,
666  const uint8_t* identifier_begin,
667  const size_t identifier_len) const {
668  return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
669  identifier_len));
670 }
671 
672 HostPtr
673 CfgHosts::get4(const SubnetID& subnet_id,
674  const Host::IdentifierType& identifier_type,
675  const uint8_t* identifier_begin,
676  const size_t identifier_len) {
677  return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
678  identifier_len));
679 }
680 
682 CfgHosts::get4(const SubnetID& subnet_id, const IOAddress& address) const {
684  .arg(subnet_id).arg(address.toText());
685 
686  ConstHostCollection hosts = getAll4(address);
687  for (ConstHostCollection::const_iterator host = hosts.begin();
688  host != hosts.end(); ++host) {
689  if ((*host)->getIPv4SubnetID() == subnet_id) {
692  .arg(subnet_id)
693  .arg(address.toText())
694  .arg((*host)->toText());
695  return (*host);
696  }
697  }
698 
700  .arg(subnet_id).arg(address.toText());
701  return (ConstHostPtr());
702 }
703 
705 CfgHosts::getAll4(const SubnetID& subnet_id,
706  const asiolink::IOAddress& address) const {
708  .arg(subnet_id).arg(address.toText());
709 
710  ConstHostCollection hosts;
711  for (auto host : getAll4(address)) {
712  if (host->getIPv4SubnetID() == subnet_id) {
715  .arg(subnet_id)
716  .arg(address.toText())
717  .arg(host->toText());
718  hosts.push_back(host);
719  }
720  }
722  .arg(subnet_id)
723  .arg(address.toText())
724  .arg(hosts.size());
725 
726  return (hosts);
727 }
728 
730 CfgHosts::get6(const SubnetID& subnet_id,
731  const Host::IdentifierType& identifier_type,
732  const uint8_t* identifier_begin,
733  const size_t identifier_len) const {
734  return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
735  identifier_len));
736 }
737 
738 HostPtr
739 CfgHosts::get6(const SubnetID& subnet_id,
740  const Host::IdentifierType& identifier_type,
741  const uint8_t* identifier_begin,
742  const size_t identifier_len) {
743  return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
744  identifier_len));
745 }
746 
748 CfgHosts::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
749  return (getHostInternal6<ConstHostPtr>(prefix, prefix_len));
750 }
751 
752 HostPtr
753 CfgHosts::get6(const IOAddress& prefix, const uint8_t prefix_len) {
754  return (getHostInternal6<HostPtr>(prefix, prefix_len));
755 }
756 
758 CfgHosts::get6(const SubnetID& subnet_id,
759  const asiolink::IOAddress& address) const {
760  // Do not log here because getHostInternal6 logs.
761  return (getHostInternal6<ConstHostPtr, ConstHostCollection>(subnet_id, address));
762 }
763 
764 HostPtr
765 CfgHosts::get6(const SubnetID& subnet_id,
766  const asiolink::IOAddress& address) {
767  // Do not log here because getHostInternal6 logs.
768  return (getHostInternal6<HostPtr, HostCollection>(subnet_id, address));
769 }
770 
772 CfgHosts::getAll6(const SubnetID& subnet_id,
773  const asiolink::IOAddress& address) const {
774  ConstHostCollection hosts;
775  getAllInternal6(subnet_id, address, hosts);
776  return (hosts);
777 }
778 
779 template<typename ReturnType, typename Storage>
780 ReturnType
781 CfgHosts::getHostInternal6(const SubnetID& subnet_id,
782  const asiolink::IOAddress& address) const {
784  .arg(subnet_id).arg(address.toText());
785 
786  Storage storage;
787  getAllInternal6<Storage>(subnet_id, address, storage);
788  switch (storage.size()) {
789  case 0:
792  .arg(subnet_id)
793  .arg(address.toText());
794  return (HostPtr());
795 
796  case 1:
799  .arg(subnet_id)
800  .arg(address.toText())
801  .arg((*storage.begin())->toText());
802  return (*storage.begin());
803 
804  default:
805  isc_throw(DuplicateHost, "more than one reservation found"
806  " for the host belonging to the subnet with id '"
807  << subnet_id << "' and using the address '"
808  << address.toText() << "'");
809  }
810 
811 }
812 
813 template<typename ReturnType>
814 ReturnType
815 CfgHosts::getHostInternal6(const asiolink::IOAddress& prefix,
816  const uint8_t prefix_len) const {
818  .arg(prefix.toText()).arg(static_cast<int>(prefix_len));
819 
820  // Let's get all reservations that match subnet_id, address.
821  const HostContainer6Index0& idx = hosts6_.get<0>();
822  HostContainer6Index0Range r = make_pair(idx.lower_bound(prefix),
823  idx.upper_bound(prefix));
824  for (HostContainer6Index0::iterator resrv = r.first; resrv != r.second;
825  ++resrv) {
826  if (resrv->resrv_.getPrefixLen() == prefix_len) {
829  .arg(prefix.toText())
830  .arg(static_cast<int>(prefix_len))
831  .arg(resrv->host_->toText());
832  return (resrv->host_);
833  }
834  }
835 
838  .arg(prefix.toText())
839  .arg(static_cast<int>(prefix_len));
840  return (ReturnType());
841 }
842 
843 template<typename Storage>
844 void
845 CfgHosts::getAllInternal6(const SubnetID& subnet_id,
846  const asiolink::IOAddress& address,
847  Storage& storage) const {
849  .arg(subnet_id).arg(address.toText());
850 
851  // Must not specify address other than IPv6.
852  if (!address.isV6()) {
853  isc_throw(BadHostAddress, "must specify an IPv6 address when searching"
854  " for a host, specified address was " << address);
855  }
856 
857  // Let's get all reservations that match subnet_id, address.
858  const HostContainer6Index1& idx = hosts6_.get<1>();
859  HostContainer6Index1Range r = make_pair(idx.lower_bound(boost::make_tuple(subnet_id, address)),
860  idx.upper_bound(boost::make_tuple(subnet_id, address)));
861 
862  // For each IPv6 reservation, add the host to the results list. Fortunately,
863  // in all sane cases, there will be only one such host. (Each host can have
864  // multiple addresses reserved, but for each (address, subnet_id) there should
865  // be at most one host reserving it).
866  for(HostContainer6Index1::iterator resrv = r.first; resrv != r.second; ++resrv) {
869  .arg(subnet_id)
870  .arg(address.toText())
871  .arg(resrv->host_->toText());
872  storage.push_back(resrv->host_);
873  }
874 
877  .arg(subnet_id)
878  .arg(address.toText())
879  .arg(storage.size());
880 }
881 
882 HostPtr
883 CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
884  const Host::IdentifierType& identifier_type,
885  const uint8_t* identifier,
886  const size_t identifier_len) const {
887 
889  .arg(subnet6 ? "IPv6" : "IPv4")
890  .arg(subnet_id)
891  .arg(Host::getIdentifierAsText(identifier_type, identifier, identifier_len));
892 
893  // Get all hosts for a specified identifier. This may return multiple hosts
894  // for different subnets, but the number of hosts returned should be low
895  // because one host presumably doesn't show up in many subnets.
896  HostCollection hosts;
897  getAllInternal<HostCollection>(identifier_type, identifier, identifier_len,
898  hosts);
899 
900  HostPtr host;
901  // Iterate over the returned hosts and select those for which the
902  // subnet id matches.
903  for (HostCollection::const_iterator host_it = hosts.begin();
904  host_it != hosts.end(); ++host_it) {
905  // Check if this is IPv4 subnet or IPv6 subnet.
906  SubnetID host_subnet_id = subnet6 ? (*host_it)->getIPv6SubnetID() :
907  (*host_it)->getIPv4SubnetID();
908 
909  if (subnet_id == host_subnet_id) {
910  // If this is the first occurrence of the host for this subnet,
911  // remember it. But, if we find that this is second @c Host object
912  // for the same client, it is a misconfiguration. Most likely,
913  // the administrator has specified one reservation for a HW
914  // address and another one for the DUID, which gives an ambiguous
915  // result, and we don't know which reservation we should choose.
916  // Therefore, throw an exception.
917  if (!host) {
918  host = *host_it;
919 
920  } else {
921  isc_throw(DuplicateHost, "more than one reservation found"
922  " for the host belonging to the subnet with id '"
923  << subnet_id << "' and using the identifier '"
924  << Host::getIdentifierAsText(identifier_type,
925  identifier,
926  identifier_len)
927  << "'");
928  }
929  }
930  }
931 
932  if (host) {
935  .arg(subnet_id)
936  .arg(Host::getIdentifierAsText(identifier_type, identifier,
937  identifier_len))
938  .arg(host->toText());
939 
940  } else {
943  .arg(subnet_id)
944  .arg(Host::getIdentifierAsText(identifier_type, identifier,
945  identifier_len));
946  }
947 
948  return (host);
949 }
950 
951 void
952 CfgHosts::add(const HostPtr& host) {
954  .arg(host ? host->toText() : "(no-host)");
955 
956  // Sanity check that the host is non-null.
957  if (!host) {
958  isc_throw(BadValue, "specified host object must not be NULL when it"
959  " is added to the configuration");
960  }
961 
962  // At least one subnet ID must be used
963  if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED &&
964  host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
965  isc_throw(BadValue, "must not use both IPv4 and IPv6 subnet ids of"
966  " 0 when adding new host reservation");
967  }
968 
969  add4(host);
970 
971  add6(host);
972 }
973 
974 void
975 CfgHosts::add4(const HostPtr& host) {
976 
977  HWAddrPtr hwaddr = host->getHWAddress();
978  DuidPtr duid = host->getDuid();
979 
980  // There should be at least one resource reserved: hostname, IPv4
981  // address, siaddr, sname, file or IPv6 address or prefix.
983  if (host->getHostname().empty() &&
984  (host->getIPv4Reservation().isV4Zero()) &&
985  !host->hasIPv6Reservation() &&
986  host->getNextServer().isV4Zero() &&
987  host->getServerHostname().empty() &&
988  host->getBootFileName().empty() &&
989  host->getCfgOption4()->empty() &&
990  host->getCfgOption6()->empty() &&
991  host->getClientClasses4().empty() &&
992  host->getClientClasses6().empty()) {
993  std::ostringstream s;
994  if (hwaddr) {
995  s << "for DUID: " << hwaddr->toText();
996  } else if (duid) {
997  s << "for HW address: " << duid->toText();
998  }
999  isc_throw(BadValue, "specified reservation " << s.str()
1000  << " must include at least one resource, i.e. "
1001  "hostname, IPv4 address, IPv6 address/prefix, "
1002  "options");
1003  }
1004 
1005  // Check for duplicates for the specified IPv4 subnet.
1006  if (host->getIPv4SubnetID() != SUBNET_ID_UNUSED) {
1007  if (hwaddr && !hwaddr->hwaddr_.empty() &&
1008  get4(host->getIPv4SubnetID(), Host::IDENT_HWADDR,
1009  &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
1010  isc_throw(DuplicateHost, "failed to add new host using the HW"
1011  << " address '" << hwaddr->toText(false)
1012  << "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
1013  << "' as this host has already been added");
1014  }
1015  if (duid && !duid->getDuid().empty() &&
1016  get4(host->getIPv4SubnetID(), Host::IDENT_DUID,
1017  &duid->getDuid()[0], duid->getDuid().size())) {
1018  isc_throw(DuplicateHost, "failed to add new host using the "
1019  << "DUID '" << duid->toText()
1020  << "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
1021  << "' as this host has already been added");
1022  }
1023  // Check for duplicates for the specified IPv6 subnet.
1024  } else if (host->getIPv6SubnetID() != SUBNET_ID_UNUSED) {
1025  if (duid && !duid->getDuid().empty() &&
1026  get6(host->getIPv6SubnetID(), Host::IDENT_DUID,
1027  &duid->getDuid()[0], duid->getDuid().size())) {
1028  isc_throw(DuplicateHost, "failed to add new host using the "
1029  << "DUID '" << duid->toText()
1030  << "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
1031  << "' as this host has already been added");
1032  }
1033  if (hwaddr && !hwaddr->hwaddr_.empty() &&
1034  get6(host->getIPv6SubnetID(), Host::IDENT_HWADDR,
1035  &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
1036  isc_throw(DuplicateHost, "failed to add new host using the HW"
1037  << " address '" << hwaddr->toText(false)
1038  << "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
1039  << "' as this host has already been added");
1040  }
1041  }
1042 
1043  // Check if the address is already reserved for the specified IPv4 subnet.
1044  if (ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero() &&
1045  (host->getIPv4SubnetID() != SUBNET_ID_UNUSED) &&
1046  get4(host->getIPv4SubnetID(), host->getIPv4Reservation())) {
1047  isc_throw(ReservedAddress, "failed to add new host using the HW"
1048  " address '" << (hwaddr ? hwaddr->toText(false) : "(null)")
1049  << " and DUID '" << (duid ? duid->toText() : "(null)")
1050  << "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
1051  << "' for the address " << host->getIPv4Reservation()
1052  << ": There's already a reservation for this address");
1053  }
1054 
1055  // Check if the (identifier type, identifier) tuple is already used.
1056  const std::vector<uint8_t>& id = host->getIdentifier();
1057  if ((host->getIPv4SubnetID() != SUBNET_ID_UNUSED) && !id.empty()) {
1058  if (get4(host->getIPv4SubnetID(), host->getIdentifierType(), &id[0],
1059  id.size())) {
1060  isc_throw(DuplicateHost, "failed to add duplicate IPv4 host using identifier: "
1061  << Host::getIdentifierAsText(host->getIdentifierType(),
1062  &id[0], id.size()));
1063  }
1064  }
1065 
1066  // This is a new instance - add it.
1067  host->setHostId(++next_host_id_);
1068  hosts_.insert(host);
1069 }
1070 
1071 void
1072 CfgHosts::add6(const HostPtr& host) {
1073 
1074  if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
1075  // This is IPv4-only host. No need to add it to v6 tables.
1076  return;
1077  }
1078 
1079  HWAddrPtr hwaddr = host->getHWAddress();
1080  DuidPtr duid = host->getDuid();
1081 
1082  // Get all reservations for this host.
1083  IPv6ResrvRange reservations = host->getIPv6Reservations();
1084 
1085  // Check if there are any IPv6 reservations.
1086  if (std::distance(reservations.first, reservations.second) == 0) {
1087  // If there aren't, we don't need to add this to hosts6_, which is used
1088  // for getting hosts by their IPv6 address reservations.
1089  return;
1090  }
1091 
1092  // Now for each reservation, insert corresponding (address, host) tuple.
1093  for (IPv6ResrvIterator it = reservations.first; it != reservations.second;
1094  ++it) {
1095 
1096  if (ip_reservations_unique_) {
1097  // If there's an entry for this (subnet-id, address), reject it.
1098  if (get6(host->getIPv6SubnetID(), it->second.getPrefix())) {
1099  isc_throw(DuplicateHost, "failed to add address reservation for "
1100  << "host using the HW address '"
1101  << (hwaddr ? hwaddr->toText(false) : "(null)")
1102  << " and DUID '" << (duid ? duid->toText() : "(null)")
1103  << "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
1104  << "' for address/prefix " << it->second.getPrefix()
1105  << ": There's already reservation for this address/prefix");
1106  }
1107  }
1108  hosts6_.insert(HostResrv6Tuple(it->second, host));
1109  }
1110 }
1111 
1112 bool
1113 CfgHosts::del(const SubnetID& /*subnet_id*/, const asiolink::IOAddress& /*addr*/) {
1115  isc_throw(NotImplemented, "sorry, not implemented");
1116  return (false);
1117 }
1118 
1119 size_t
1120 CfgHosts::delAll4(const SubnetID& subnet_id) {
1121  HostContainerIndex2& idx = hosts_.get<2>();
1122  size_t erased = idx.erase(subnet_id);
1123 
1125  .arg(erased)
1126  .arg(subnet_id);
1127 
1128  return (erased);
1129 }
1130 
1131 bool
1132 CfgHosts::del4(const SubnetID& /*subnet_id*/,
1133  const Host::IdentifierType& /*identifier_type*/,
1134  const uint8_t* /*identifier_begin*/,
1135  const size_t /*identifier_len*/) {
1137  isc_throw(NotImplemented, "sorry, not implemented");
1138  return (false);
1139 }
1140 
1141 size_t
1142 CfgHosts::delAll6(const SubnetID& subnet_id) {
1143  // Delete IPv6 reservations.
1144  HostContainer6Index2& idx6 = hosts6_.get<2>();
1145  size_t erased_addresses = idx6.erase(subnet_id);
1146 
1147  // Delete hosts.
1148  HostContainerIndex3& idx = hosts_.get<3>();
1149  size_t erased_hosts = idx.erase(subnet_id);
1150 
1152  .arg(erased_hosts)
1153  .arg(erased_addresses)
1154  .arg(subnet_id);
1155 
1156  return (erased_hosts);
1157 }
1158 
1159 bool
1160 CfgHosts::del6(const SubnetID& /*subnet_id*/,
1161  const Host::IdentifierType& /*identifier_type*/,
1162  const uint8_t* /*identifier_begin*/,
1163  const size_t /*identifier_len*/) {
1165  isc_throw(NotImplemented, "sorry, not implemented");
1166  return (false);
1167 }
1168 
1169 bool
1170 CfgHosts::setIPReservationsUnique(const bool unique) {
1171  ip_reservations_unique_ = unique;
1172  return (true);
1173 }
1174 
1175 
1176 ElementPtr
1177 CfgHosts::toElement() const {
1178  uint16_t family = CfgMgr::instance().getFamily();
1179  if (family == AF_INET) {
1180  return (toElement4());
1181  } else if (family == AF_INET6) {
1182  return (toElement6());
1183  } else {
1184  isc_throw(ToElementError, "CfgHosts::toElement: unknown "
1185  "address family: " << family);
1186  }
1187 }
1188 
1189 ElementPtr
1190 CfgHosts::toElement4() const {
1191  CfgHostsList result;
1192  // Iterate using arbitrary the index 0
1193  const HostContainerIndex0& idx = hosts_.get<0>();
1194  for (HostContainerIndex0::const_iterator host = idx.begin();
1195  host != idx.end(); ++host) {
1196 
1197  // Convert host to element representation
1198  ElementPtr map = (*host)->toElement4();
1199 
1200  // Push it on the list
1201  SubnetID subnet_id = (*host)->getIPv4SubnetID();
1202  result.add(subnet_id, map);
1203  }
1204  return (result.externalize());
1205 }
1206 
1207 ElementPtr
1208 CfgHosts::toElement6() const {
1209  CfgHostsList result;
1210  // Iterate using arbitrary the index 0
1211  const HostContainerIndex0& idx = hosts_.get<0>();
1212  for (HostContainerIndex0::const_iterator host = idx.begin();
1213  host != idx.end(); ++host) {
1214 
1215  // Convert host to Element representation
1216  ElementPtr map = (*host)->toElement6();
1217 
1218  // Push it on the list
1219  SubnetID subnet_id = (*host)->getIPv6SubnetID();
1220  result.add(subnet_id, map);
1221  }
1222  return (result.externalize());
1223 }
1224 
1225 } // end of namespace isc::dhcp
1226 } // end of namespace isc
const isc::log::MessageID HOSTS_CFG_ADD_HOST
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
std::pair< HostContainer6Index0::iterator, HostContainer6Index0::iterator > HostContainer6Index0Range
Results range returned using the HostContainer6Index0.
const int HOSTS_DBG_TRACE_DETAIL_DATA
Records detailed results of lookups.
Definition: hosts_log.h:43
HostContainer6::nth_index< 1 >::type HostContainer6Index1
Second index type in the HostContainer6.
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4
Defines one entry for the Host Container for v6 hosts.
Wraps value holding size of the page with host reservations.
A generic exception that is thrown when a function is not implemented.
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS4
std::pair< HostContainer6Index1::iterator, HostContainer6Index1::iterator > HostContainer6Index1Range
Results range returned using the HostContainer6Index1.
Utility class to represent host reservation configurations internally as a map keyed by subnet IDs...
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOST
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:785
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID4_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6
const isc::log::MessageID HOSTS_CFG_GET_ONE_PREFIX_HOST
const int HOSTS_DBG_RESULTS
Records the results of the lookups.
Definition: hosts_log.h:33
Cannot unparse error.
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_HOST
std::pair< HostContainerIndex1::iterator, HostContainerIndex1::iterator > HostContainerIndex1Range
Results range returned using the HostContainerIndex1.
HostContainer6::nth_index< 2 >::type HostContainer6Index2
Third index type in the HostContainer6.
const size_t page_size_
Holds page size.
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_NULL
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_HOST
HostContainer::nth_index< 0 >::type HostContainerIndex0
First index type in the HostContainer.
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:794
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_COUNT
HostContainer::nth_index< 3 >::type HostContainerIndex3
Forth index type in the HostContainer.
const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_HOST
const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void add(SubnetID id, isc::data::ElementPtr resv)
Add a host reservation to the map.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:243
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:791
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
Definition: hosts_log.h:51
const int HOSTS_DBG_TRACE
Logging levels for the host reservations management.
Definition: hosts_log.h:27
const isc::log::MessageID HOSTS_CFG_GET_ONE_PREFIX
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID6
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS4_HOST
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:788
HostContainer::nth_index< 1 >::type HostContainerIndex1
Second index type in the HostContainer.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
Definition: host.h:241
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID4
HostContainer6::nth_index< 0 >::type HostContainer6Index0
First index type in the HostContainer6.
Defines the logger used by the top-level component of kea-lfc.
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_HOST
const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET4
Exception thrown when the duplicate Host object is detected.
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_HOST
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID4_HOST
HostContainer::nth_index< 4 >::type HostContainerIndex4
Fifth index type in the HostContainer.
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_NULL
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID6_HOST
isc::data::ElementPtr externalize() const
Externalize the map to a list Element.
const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST
const isc::log::MessageID HOSTS_CFG_GET_ALL
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS4_COUNT
isc::data::ConstElementPtr get(SubnetID id) const
Return the host reservations for a subnet ID.
const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET6
Exception thrown when invalid IP address has been specified for Host.
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_NULL
HostContainer::nth_index< 2 >::type HostContainerIndex2
Third index type in the HostContainer.
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_HOST
const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER
HostContainer::nth_index< 5 >::type HostContainerIndex5
Sixth index type in the HostContainer.
IdentifierType
Type of the host identifier.
Definition: host.h:307
const isc::log::MessageID HOSTS_CFG_GET_ALL_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_HOST
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6
Exception thrown when an address is already reserved by a Host object (DuplicateHost is same identity...
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_HOST
const isc::log::MessageID HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4
const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_COUNT
const isc::log::MessageID HOSTS_CFG_GET_ONE_PREFIX_NULL
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24
const isc::log::MessageID HOSTS_CFG_GET_ALL_SUBNET_ID6_COUNT