28 const uint8_t* identifier_begin,
29 const size_t identifier_len)
const {
33 getAllInternal<ConstHostCollection>(identifier_type, identifier_begin,
34 identifier_len, collection);
40 const uint8_t* identifier_begin,
const size_t identifier_len) {
44 getAllInternal<HostCollection>(identifier_type, identifier_begin,
45 identifier_len, collection);
54 getAllInternal4<ConstHostCollection>(address, collection);
63 getAllInternal4<HostCollection>(address, collection);
72 getAllInternal6<ConstHostCollection>(address, collection);
81 getAllInternal6<HostCollection>(address, collection);
85 template<
typename Storage>
88 const uint8_t* identifier,
89 const size_t identifier_len,
90 Storage& storage)
const {
94 std::string identifier_text = Host::getIdentifierAsText(identifier_type,
98 .arg(identifier_text);
103 boost::make_tuple(std::vector<uint8_t>(identifier,
104 identifier + identifier_len),
108 for (HostContainerIndex0::iterator host = idx.lower_bound(t);
109 host != idx.upper_bound(t);
112 HOSTS_CFG_GET_ALL_IDENTIFIER_HOST)
113 .arg(identifier_text)
114 .arg((*host)->toText());
115 storage.push_back(*host);
120 .arg(identifier_text)
121 .arg(storage.size());
124 template<
typename Storage>
126 CfgHosts::getAllInternal4(
const IOAddress& address, Storage& storage)
const {
131 if (!address.
isV4()) {
132 isc_throw(BadHostAddress,
"must specify an IPv4 address when searching" 133 " for a host, specified address was " << address);
139 for (HostContainerIndex1::iterator host = r.first; host != r.second;
142 HOSTS_CFG_GET_ALL_ADDRESS4_HOST)
144 .arg((*host)->toText());
145 storage.push_back(*host);
150 .arg(storage.size());
153 template<
typename Storage>
155 CfgHosts::getAllInternal6(
const IOAddress& address, Storage& storage)
const {
160 if (!address.
isV6()) {
161 isc_throw(BadHostAddress,
"must specify an IPv6 address when searching" 162 " for a host, specified address was " << address);
168 for (HostContainerIndex1::iterator host = r.first; host != r.second;
171 HOSTS_CFG_GET_ALL_ADDRESS6_HOST)
173 .arg((*host)->toText());
174 storage.push_back(*host);
179 .arg(storage.size());
185 const uint8_t* identifier_begin,
186 const size_t identifier_len)
const {
187 return (getHostInternal(subnet_id,
false, identifier_type, identifier_begin,
194 const uint8_t* identifier_begin,
195 const size_t identifier_len) {
196 return (getHostInternal(subnet_id,
false, identifier_type, identifier_begin,
203 .arg(subnet_id).arg(address.
toText());
206 for (ConstHostCollection::const_iterator host = hosts.begin();
207 host != hosts.end(); ++host) {
208 if ((*host)->getIPv4SubnetID() == subnet_id) {
210 HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_HOST)
213 .arg((*host)->toText());
219 .arg(subnet_id).arg(address.
toText());
227 const uint8_t* identifier_begin,
228 const size_t identifier_len)
const {
229 return (getHostInternal(subnet_id,
true, identifier_type, identifier_begin,
236 const uint8_t* identifier_begin,
237 const size_t identifier_len) {
238 return (getHostInternal(subnet_id,
true, identifier_type, identifier_begin,
243 CfgHosts::get6(
const IOAddress& prefix,
const uint8_t prefix_len)
const {
244 return (getHostInternal6<ConstHostPtr>(prefix, prefix_len));
248 CfgHosts::get6(
const IOAddress& prefix,
const uint8_t prefix_len) {
249 return (getHostInternal6<HostPtr>(prefix, prefix_len));
256 return (getHostInternal6<ConstHostPtr, ConstHostCollection>(subnet_id, address));
263 return (getHostInternal6<HostPtr, HostCollection>(subnet_id, address));
266 template<
typename ReturnType,
typename Storage>
268 CfgHosts::getHostInternal6(
const SubnetID& subnet_id,
271 .arg(subnet_id).arg(address.
toText());
274 getAllInternal6<Storage>(subnet_id, address, storage);
275 switch (storage.size()) {
278 HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_NULL)
285 HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_HOST)
288 .arg((*storage.begin())->toText());
289 return (*storage.begin());
293 " for the host belonging to the subnet with id '" 294 << subnet_id <<
"' and using the address '" 295 << address.
toText() <<
"'");
300 template<
typename ReturnType>
302 CfgHosts::getHostInternal6(
const asiolink::IOAddress& prefix,
303 const uint8_t prefix_len)
const {
305 .arg(prefix.toText()).arg(static_cast<int>(prefix_len));
310 idx.upper_bound(prefix));
311 for (HostContainer6Index0::iterator resrv = r.first; resrv != r.second;
313 if (resrv->resrv_.getPrefixLen() == prefix_len) {
315 HOSTS_CFG_GET_ONE_PREFIX_HOST)
316 .arg(prefix.toText())
317 .arg(static_cast<int>(prefix_len))
318 .arg(resrv->host_->toText());
319 return (resrv->host_);
324 HOSTS_CFG_GET_ONE_PREFIX_NULL)
325 .arg(prefix.toText())
326 .arg(static_cast<int>(prefix_len));
327 return (ReturnType());
330 template<
typename Storage>
332 CfgHosts::getAllInternal6(
const SubnetID& subnet_id,
333 const asiolink::IOAddress& address,
334 Storage& storage)
const {
336 .arg(subnet_id).arg(address.toText());
339 if (!address.isV6()) {
340 isc_throw(BadHostAddress,
"must specify an IPv6 address when searching" 341 " for a host, specified address was " << address);
347 idx.upper_bound(boost::make_tuple(subnet_id, address)));
353 for(HostContainer6Index1::iterator resrv = r.first; resrv != r.second; ++resrv) {
355 HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_HOST)
357 .arg(address.toText())
358 .arg(resrv->host_->toText());
359 storage.push_back(resrv->host_);
363 HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_COUNT)
365 .arg(address.toText())
366 .arg(storage.size());
370 CfgHosts::getHostInternal(
const SubnetID& subnet_id,
const bool subnet6,
371 const Host::IdentifierType& identifier_type,
372 const uint8_t* identifier,
373 const size_t identifier_len)
const {
376 .arg(subnet6 ?
"IPv6" :
"IPv4")
378 .arg(Host::getIdentifierAsText(identifier_type, identifier, identifier_len));
384 getAllInternal<HostCollection>(identifier_type, identifier, identifier_len,
390 for (HostCollection::const_iterator host_it = hosts.begin();
391 host_it != hosts.end(); ++host_it) {
393 SubnetID host_subnet_id = subnet6 ? (*host_it)->getIPv6SubnetID() :
394 (*host_it)->getIPv4SubnetID();
396 if (subnet_id == host_subnet_id) {
408 isc_throw(DuplicateHost,
"more than one reservation found" 409 " for the host belonging to the subnet with id '" 410 << subnet_id <<
"' and using the identifier '" 411 << Host::getIdentifierAsText(identifier_type,
421 HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_HOST)
423 .arg(Host::getIdentifierAsText(identifier_type, identifier,
425 .arg(host->toText());
429 HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_NULL)
431 .arg(Host::getIdentifierAsText(identifier_type, identifier,
441 .arg(host ? host->toText() :
"(no-host)");
446 " is added to the configuration");
450 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED &&
451 host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
453 " 0 when adding new host reservation");
462 CfgHosts::add4(
const HostPtr& host) {
465 DuidPtr duid = host->getDuid();
470 if (host->getHostname().empty() &&
471 (host->getIPv4Reservation().isV4Zero()) &&
472 !host->hasIPv6Reservation() &&
473 host->getNextServer().isV4Zero() &&
474 host->getServerHostname().empty() &&
475 host->getBootFileName().empty() &&
476 host->getCfgOption4()->empty() &&
477 host->getCfgOption6()->empty() &&
478 host->getClientClasses4().empty() &&
479 host->getClientClasses6().empty()) {
480 std::ostringstream s;
482 s <<
"for DUID: " << hwaddr->toText();
484 s <<
"for HW address: " << duid->toText();
486 isc_throw(BadValue,
"specified reservation " << s.str()
487 <<
" must include at least one resource, i.e. " 488 "hostname, IPv4 address, IPv6 address/prefix, " 493 if (host->getIPv4SubnetID() != SUBNET_ID_UNUSED) {
494 if (hwaddr && !hwaddr->hwaddr_.empty() &&
495 get4(host->getIPv4SubnetID(), Host::IDENT_HWADDR,
496 &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
497 isc_throw(DuplicateHost,
"failed to add new host using the HW" 498 <<
" address '" << hwaddr->toText(
false)
499 <<
"' to the IPv4 subnet id '" << host->getIPv4SubnetID()
500 <<
"' as this host has already been added");
502 if (duid && !duid->getDuid().empty() &&
503 get4(host->getIPv4SubnetID(), Host::IDENT_DUID,
504 &duid->getDuid()[0], duid->getDuid().size())) {
505 isc_throw(DuplicateHost,
"failed to add new host using the " 506 <<
"DUID '" << duid->toText()
507 <<
"' to the IPv4 subnet id '" << host->getIPv4SubnetID()
508 <<
"' as this host has already been added");
511 }
else if (host->getIPv6SubnetID() != SUBNET_ID_UNUSED) {
512 if (duid && !duid->getDuid().empty() &&
513 get6(host->getIPv6SubnetID(), Host::IDENT_DUID,
514 &duid->getDuid()[0], duid->getDuid().size())) {
515 isc_throw(DuplicateHost,
"failed to add new host using the " 516 <<
"DUID '" << duid->toText()
517 <<
"' to the IPv6 subnet id '" << host->getIPv6SubnetID()
518 <<
"' as this host has already been added");
520 if (hwaddr && !hwaddr->hwaddr_.empty() &&
521 get6(host->getIPv6SubnetID(), Host::IDENT_HWADDR,
522 &hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
523 isc_throw(DuplicateHost,
"failed to add new host using the HW" 524 <<
" address '" << hwaddr->toText(
false)
525 <<
"' to the IPv6 subnet id '" << host->getIPv6SubnetID()
526 <<
"' as this host has already been added");
531 if (!host->getIPv4Reservation().isV4Zero() &&
532 (host->getIPv4SubnetID() != SUBNET_ID_UNUSED) &&
533 get4(host->getIPv4SubnetID(), host->getIPv4Reservation())) {
534 isc_throw(ReservedAddress,
"failed to add new host using the HW" 535 " address '" << (hwaddr ? hwaddr->toText(
false) :
"(null)")
536 <<
" and DUID '" << (duid ? duid->toText() :
"(null)")
537 <<
"' to the IPv4 subnet id '" << host->getIPv4SubnetID()
538 <<
"' for the address " << host->getIPv4Reservation()
539 <<
": There's already a reservation for this address");
543 const std::vector<uint8_t>&
id = host->getIdentifier();
544 if ((host->getIPv4SubnetID() != SUBNET_ID_UNUSED) && !
id.empty()) {
545 if (get4(host->getIPv4SubnetID(), host->getIdentifierType(), &
id[0],
547 isc_throw(DuplicateHost,
"failed to add duplicate IPv4 host using identifier: " 548 << Host::getIdentifierAsText(host->getIdentifierType(),
558 CfgHosts::add6(
const HostPtr& host) {
560 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
566 DuidPtr duid = host->getDuid();
572 if (std::distance(reservations.first, reservations.second) == 0) {
583 if (get6(host->getIPv6SubnetID(), it->second.getPrefix())) {
584 isc_throw(DuplicateHost,
"failed to add address reservation for " 585 <<
"host using the HW address '" 586 << (hwaddr ? hwaddr->toText(
false) :
"(null)")
587 <<
" and DUID '" << (duid ? duid->toText() :
"(null)")
588 <<
"' to the IPv6 subnet id '" << host->getIPv6SubnetID()
589 <<
"' for address/prefix " << it->second.getPrefix()
590 <<
": There's already reservation for this address/prefix");
592 hosts6_.insert(HostResrv6Tuple(it->second, host));
606 size_t erased = idx.erase(subnet_id);
629 size_t erased_addresses = idx6.erase(subnet_id);
633 size_t erased_hosts = idx.erase(subnet_id);
637 .arg(erased_addresses)
640 return (erased_hosts);
654 CfgHosts::toElement()
const {
655 uint16_t family = CfgMgr::instance().getFamily();
656 if (family == AF_INET) {
657 return (toElement4());
658 }
else if (family == AF_INET6) {
659 return (toElement6());
662 "address family: " << family);
667 CfgHosts::toElement4()
const {
671 for (HostContainerIndex0::const_iterator host = idx.begin();
672 host != idx.end(); ++host) {
678 SubnetID subnet_id = (*host)->getIPv4SubnetID();
679 result.
add(subnet_id, map);
685 CfgHosts::toElement6()
const {
689 for (HostContainerIndex0::const_iterator host = idx.begin();
690 host != idx.end(); ++host) {
696 SubnetID subnet_id = (*host)->getIPv6SubnetID();
697 result.add(subnet_id, map);
699 return (result.externalize());
boost::shared_ptr< DUID > DuidPtr
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.
HostContainer6::nth_index< 1 >::type HostContainer6Index1
Second index type in the HostContainer6.
A generic exception that is thrown when a function is not implemented.
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.
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
const int HOSTS_DBG_RESULTS
Records the results of the lookups.
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.
boost::shared_ptr< Element > ElementPtr
HostContainer::nth_index< 0 >::type HostContainerIndex0
First index type in the HostContainer.
std::vector< HostPtr > HostCollection
Collection of the Host objects.
HostContainer::nth_index< 3 >::type HostContainerIndex3
Forth index type in the HostContainer.
#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
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
const int HOSTS_DBG_TRACE
Logging levels for the host reservations management.
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
HostContainer::nth_index< 1 >::type HostContainerIndex1
Second index type in the HostContainer.
bool isV6() const
Convenience function to check for an IPv6 address.
bool isV4() const
Convenience function to check for an IPv4 address.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
HostContainer6::nth_index< 0 >::type HostContainer6Index0
First index type in the HostContainer6.
Defines the logger used by the top-level component of kea-dhcp-ddns.
std::string toText() const
Convert the address to a string.
Exception thrown when the duplicate Host object is detected.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
isc::data::ElementPtr externalize() const
Externalize the map to a list Element.
isc::data::ConstElementPtr get(SubnetID id) const
Return the host reservations for a subnet ID.
HostContainer::nth_index< 2 >::type HostContainerIndex2
Third index type in the HostContainer.
IdentifierType
Type of the host identifier.
The IOAddress class represents an IP addresses (version agnostic)
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)