2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

[#3375] Made cfg_host MT safe

This commit is contained in:
Francis Dupont
2024-05-31 01:14:18 +02:00
parent 8dcd1a9453
commit 40827e15c3
3 changed files with 553 additions and 86 deletions

View File

@@ -13,6 +13,7 @@
#include <dhcpsrv/cfgmgr.h>
#include <exceptions/exceptions.h>
#include <util/encode/encode.h>
#include <util/multi_threading_mgr.h>
#include <boost/foreach.hpp>
#include <ostream>
#include <string>
@@ -20,11 +21,15 @@
using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::util;
using namespace std;
namespace isc {
namespace dhcp {
CfgHosts::CfgHosts() : mutex_(new mutex()) {
}
ConstHostCollection
CfgHosts::getAll(const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
@@ -32,6 +37,7 @@ CfgHosts::getAll(const Host::IdentifierType& identifier_type,
// Do not issue logging message here because it will be logged by
// the getAllInternal method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal<ConstHostCollection>(identifier_type, identifier_begin,
identifier_len, collection);
return (collection);
@@ -43,6 +49,7 @@ CfgHosts::getAll(const Host::IdentifierType& identifier_type,
// Do not issue logging message here because it will be logged by
// the getAllInternal method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal<HostCollection>(identifier_type, identifier_begin,
identifier_len, collection);
return (collection);
@@ -53,6 +60,7 @@ CfgHosts::getAll4(const SubnetID& subnet_id) const {
// Do not issue logging message here because it will be logged by
// the getAllInternal4 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal4<ConstHostCollection>(subnet_id, collection);
return (collection);
}
@@ -62,6 +70,7 @@ CfgHosts::getAll4(const SubnetID& subnet_id) {
// Do not issue logging message here because it will be logged by
// the getAllInternal4 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal4<HostCollection>(subnet_id, collection);
return (collection);
}
@@ -71,6 +80,7 @@ CfgHosts::getAll6(const SubnetID& subnet_id) const {
// Do not issue logging message here because it will be logged by
// the getAllInternal6 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal6<ConstHostCollection>(subnet_id, collection);
return (collection);
}
@@ -80,6 +90,7 @@ CfgHosts::getAll6(const SubnetID& subnet_id) {
// Do not issue logging message here because it will be logged by
// the getAllInternal6 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal6<HostCollection>(subnet_id, collection);
return (collection);
}
@@ -89,6 +100,7 @@ CfgHosts::getAllbyHostname(const std::string& hostname) const {
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal<ConstHostCollection>(hostname, collection);
return (collection);
}
@@ -98,6 +110,7 @@ CfgHosts::getAllbyHostname(const std::string& hostname) {
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal<HostCollection>(hostname, collection);
return (collection);
}
@@ -108,6 +121,7 @@ CfgHosts::getAllbyHostname4(const std::string& hostname,
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal4 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal4<ConstHostCollection>(hostname, subnet_id, collection);
return (collection);
}
@@ -118,6 +132,7 @@ CfgHosts::getAllbyHostname4(const std::string& hostname,
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal4 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal4<HostCollection>(hostname, subnet_id, collection);
return (collection);
}
@@ -128,6 +143,7 @@ CfgHosts::getAllbyHostname6(const std::string& hostname,
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal6 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal6<ConstHostCollection>(hostname, subnet_id, collection);
return (collection);
}
@@ -138,6 +154,7 @@ CfgHosts::getAllbyHostname6(const std::string& hostname,
// Do not issue logging message here because it will be logged by
// the getAllbyHostnameInternal6 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllbyHostnameInternal6<HostCollection>(hostname, subnet_id, collection);
return (collection);
}
@@ -150,6 +167,7 @@ CfgHosts::getPage4(const SubnetID& subnet_id,
// Do not issue logging message here because it will be logged by
// the getPageInternal4 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal4<ConstHostCollection>(subnet_id,
lower_host_id,
page_size,
@@ -165,6 +183,7 @@ CfgHosts::getPage4(const SubnetID& subnet_id,
// Do not issue logging message here because it will be logged by
// the getPageInternal4 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal4<HostCollection>(subnet_id,
lower_host_id,
page_size,
@@ -180,6 +199,7 @@ CfgHosts::getPage6(const SubnetID& subnet_id,
// Do not issue logging message here because it will be logged by
// the getPageInternal6 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal6<ConstHostCollection>(subnet_id,
lower_host_id,
page_size,
@@ -195,6 +215,7 @@ CfgHosts::getPage6(const SubnetID& subnet_id,
// Do not issue logging message here because it will be logged by
// the getPageInternal6 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal6<HostCollection>(subnet_id,
lower_host_id,
page_size,
@@ -209,6 +230,7 @@ CfgHosts::getPage4(size_t& /*source_index*/,
// Do not issue logging message here because it will be logged by
// the getPageInternal method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal<ConstHostCollection>(lower_host_id,
page_size,
collection);
@@ -222,6 +244,7 @@ CfgHosts::getPage4(size_t& /*source_index*/,
// Do not issue logging message here because it will be logged by
// the getPageInternal method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal<HostCollection>(lower_host_id,
page_size,
collection);
@@ -235,6 +258,7 @@ CfgHosts::getPage6(size_t& /*source_index*/,
// Do not issue logging message here because it will be logged by
// the getPageInternal method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal<ConstHostCollection>(lower_host_id,
page_size,
collection);
@@ -248,6 +272,7 @@ CfgHosts::getPage6(size_t& /*source_index*/,
// Do not issue logging message here because it will be logged by
// the getPageInternal method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getPageInternal<HostCollection>(lower_host_id,
page_size,
collection);
@@ -259,6 +284,7 @@ CfgHosts::getAll4(const IOAddress& address) const {
// Do not issue logging message here because it will be logged by
// the getAllInternal4 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal4<ConstHostCollection>(address, collection);
return (collection);
}
@@ -268,6 +294,7 @@ CfgHosts::getAll4(const IOAddress& address) {
// Do not issue logging message here because it will be logged by
// the getAllInternal4 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal4<HostCollection>(address, collection);
return (collection);
}
@@ -277,6 +304,7 @@ CfgHosts::getAll6(const IOAddress& address) const {
// Do not issue logging message here because it will be logged by
// the getAllInternal6 method.
ConstHostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal6<ConstHostCollection>(address, collection);
return (collection);
}
@@ -286,6 +314,7 @@ CfgHosts::getAll6(const IOAddress& address) {
// Do not issue logging message here because it will be logged by
// the getAllInternal6 method.
HostCollection collection;
MultiThreadingLock lock(*mutex_);
getAllInternal6<HostCollection>(address, collection);
return (collection);
}
@@ -632,6 +661,42 @@ CfgHosts::getAllInternal4(const IOAddress& address, Storage& storage) const {
.arg(storage.size());
}
ConstHostCollection
CfgHosts::getAllInternal4(const SubnetID& subnet_id,
const IOAddress& address) const {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4)
.arg(subnet_id)
.arg(address.toText());
// Must not specify address other than IPv4.
if (!address.isV4()) {
isc_throw(BadHostAddress, "must specify an IPv4 address when searching"
" for a host, specified address was " << address);
}
// Search for the Host using the reserved IPv4 address as a key.
ConstHostCollection hosts;
const HostContainerIndex1& idx = hosts_.get<1>();
HostContainerIndex1Range r = idx.equal_range(address);
// Append each Host object to the storage.
BOOST_FOREACH(auto const& host, r) {
if (host->getIPv4SubnetID() == subnet_id) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA,
HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_HOST)
.arg(subnet_id)
.arg(address.toText())
.arg(host->toText());
hosts.push_back(host);
}
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_COUNT)
.arg(subnet_id)
.arg(address.toText())
.arg(hosts.size());
return (hosts);
}
template<typename Storage>
void
CfgHosts::getAllInternal6(const IOAddress& address, Storage& storage) const {
@@ -665,6 +730,7 @@ CfgHosts::get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
MultiThreadingLock lock(*mutex_);
return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
identifier_len));
}
@@ -674,6 +740,7 @@ CfgHosts::get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) {
MultiThreadingLock lock(*mutex_);
return (getHostInternal(subnet_id, false, identifier_type, identifier_begin,
identifier_len));
}
@@ -683,46 +750,29 @@ CfgHosts::get4(const SubnetID& subnet_id, const IOAddress& address) const {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4)
.arg(subnet_id).arg(address.toText());
ConstHostCollection hosts = getAll4(address);
for (auto const& host : hosts) {
if (host->getIPv4SubnetID() == subnet_id) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_HOST)
.arg(subnet_id)
.arg(address.toText())
.arg(host->toText());
return (host);
}
ConstHostCollection hosts = getAllInternal4(subnet_id, address);
if (hosts.empty()) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_NULL)
.arg(subnet_id)
.arg(address.toText());
return (ConstHostPtr());
} else {
ConstHostPtr host = *hosts.begin();
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_HOST)
.arg(subnet_id)
.arg(address.toText())
.arg(host->toText());
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_NULL)
.arg(subnet_id).arg(address.toText());
return (ConstHostPtr());
}
ConstHostCollection
CfgHosts::getAll4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4)
.arg(subnet_id).arg(address.toText());
ConstHostCollection hosts;
for (auto const& host : getAll4(address)) {
if (host->getIPv4SubnetID() == subnet_id) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA,
HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_HOST)
.arg(subnet_id)
.arg(address.toText())
.arg(host->toText());
hosts.push_back(host);
}
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS4_COUNT)
.arg(subnet_id)
.arg(address.toText())
.arg(hosts.size());
return (hosts);
MultiThreadingLock lock(*mutex_);
return (getAllInternal4(subnet_id, address));
}
ConstHostPtr
@@ -730,6 +780,7 @@ CfgHosts::get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
MultiThreadingLock lock(*mutex_);
return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
identifier_len));
}
@@ -739,17 +790,20 @@ CfgHosts::get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) {
MultiThreadingLock lock(*mutex_);
return (getHostInternal(subnet_id, true, identifier_type, identifier_begin,
identifier_len));
}
ConstHostPtr
CfgHosts::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
MultiThreadingLock lock(*mutex_);
return (getHostInternal6<ConstHostPtr>(prefix, prefix_len));
}
HostPtr
CfgHosts::get6(const IOAddress& prefix, const uint8_t prefix_len) {
MultiThreadingLock lock(*mutex_);
return (getHostInternal6<HostPtr>(prefix, prefix_len));
}
@@ -757,6 +811,7 @@ ConstHostPtr
CfgHosts::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
// Do not log here because getHostInternal6 logs.
MultiThreadingLock lock(*mutex_);
return (getHostInternal6<ConstHostPtr, ConstHostCollection>(subnet_id, address));
}
@@ -764,6 +819,7 @@ HostPtr
CfgHosts::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) {
// Do not log here because getHostInternal6 logs.
MultiThreadingLock lock(*mutex_);
return (getHostInternal6<HostPtr, HostCollection>(subnet_id, address));
}
@@ -771,6 +827,7 @@ ConstHostCollection
CfgHosts::getAll6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostCollection hosts;
MultiThreadingLock lock(*mutex_);
getAllInternal6(subnet_id, address, hosts);
return (hosts);
}
@@ -963,6 +1020,8 @@ CfgHosts::add(const HostPtr& host) {
" 0 when adding new host reservation");
}
MultiThreadingLock lock(*mutex_);
add4(host);
add6(host);
@@ -977,16 +1036,16 @@ CfgHosts::add4(const HostPtr& host) {
// Check for duplicates for the specified IPv4 subnet.
if (host->getIPv4SubnetID() != SUBNET_ID_UNUSED) {
if (hwaddr && !hwaddr->hwaddr_.empty() &&
get4(host->getIPv4SubnetID(), Host::IDENT_HWADDR,
&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
getHostInternal(host->getIPv4SubnetID(), false, Host::IDENT_HWADDR,
&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
isc_throw(DuplicateHost, "failed to add new host using the HW"
<< " address '" << hwaddr->toText(false)
<< "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
<< "' as this host has already been added");
}
if (duid && !duid->getDuid().empty() &&
get4(host->getIPv4SubnetID(), Host::IDENT_DUID,
&duid->getDuid()[0], duid->getDuid().size())) {
getHostInternal(host->getIPv4SubnetID(), false, Host::IDENT_DUID,
&duid->getDuid()[0], duid->getDuid().size())) {
isc_throw(DuplicateHost, "failed to add new host using the "
<< "DUID '" << duid->toText()
<< "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
@@ -995,16 +1054,16 @@ CfgHosts::add4(const HostPtr& host) {
// Check for duplicates for the specified IPv6 subnet.
} else if (host->getIPv6SubnetID() != SUBNET_ID_UNUSED) {
if (duid && !duid->getDuid().empty() &&
get6(host->getIPv6SubnetID(), Host::IDENT_DUID,
&duid->getDuid()[0], duid->getDuid().size())) {
getHostInternal(host->getIPv6SubnetID(), true, Host::IDENT_DUID,
&duid->getDuid()[0], duid->getDuid().size())) {
isc_throw(DuplicateHost, "failed to add new host using the "
<< "DUID '" << duid->toText()
<< "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
<< "' as this host has already been added");
}
if (hwaddr && !hwaddr->hwaddr_.empty() &&
get6(host->getIPv6SubnetID(), Host::IDENT_HWADDR,
&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
getHostInternal(host->getIPv6SubnetID(), true, Host::IDENT_HWADDR,
&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size())) {
isc_throw(DuplicateHost, "failed to add new host using the HW"
<< " address '" << hwaddr->toText(false)
<< "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
@@ -1015,7 +1074,8 @@ CfgHosts::add4(const HostPtr& host) {
// Check if the address is already reserved for the specified IPv4 subnet.
if (ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero() &&
(host->getIPv4SubnetID() != SUBNET_ID_UNUSED) &&
get4(host->getIPv4SubnetID(), host->getIPv4Reservation())) {
!getAllInternal4(host->getIPv4SubnetID(),
host->getIPv4Reservation()).empty()) {
isc_throw(ReservedAddress, "failed to add new host using the HW"
" address '" << (hwaddr ? hwaddr->toText(false) : "(null)")
<< " and DUID '" << (duid ? duid->toText() : "(null)")
@@ -1027,8 +1087,8 @@ CfgHosts::add4(const HostPtr& host) {
// Check if the (identifier type, identifier) tuple is already used.
const std::vector<uint8_t>& id = host->getIdentifier();
if ((host->getIPv4SubnetID() != SUBNET_ID_UNUSED) && !id.empty()) {
if (get4(host->getIPv4SubnetID(), host->getIdentifierType(), &id[0],
id.size())) {
if (getHostInternal(host->getIPv4SubnetID(), false,
host->getIdentifierType(), &id[0], id.size())) {
isc_throw(DuplicateHost, "failed to add duplicate IPv4 host using identifier: "
<< Host::getIdentifierAsText(host->getIdentifierType(),
&id[0], id.size()));
@@ -1066,7 +1126,8 @@ CfgHosts::add6(const HostPtr& host) {
if (ip_reservations_unique_) {
// If there's an entry for this (subnet-id, address), reject it.
if (get6(host->getIPv6SubnetID(), it.second.getPrefix())) {
if (getHostInternal6<ConstHostPtr, ConstHostCollection>
(host->getIPv6SubnetID(), it.second.getPrefix())) {
isc_throw(DuplicateHost, "failed to add address reservation for "
<< "host using the HW address '"
<< (hwaddr ? hwaddr->toText(false) : "(null)")
@@ -1084,10 +1145,16 @@ bool
CfgHosts::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
size_t erased_hosts = 0;
size_t erased_addresses = 0;
MultiThreadingLock lock(*mutex_);
if (addr.isV4()) {
HostContainerIndex4& idx = hosts_.get<4>();
ConstHostCollection hosts;
getAllInternal4<ConstHostCollection>(addr, hosts);
// Delete IPv4 reservation and host.
for (auto const& host : getAll4(subnet_id, addr)) {
for (auto const& host : hosts) {
if (host->getIPv4SubnetID() != subnet_id) {
continue;
}
erased_hosts += idx.erase(host->getHostId());
}
erased_addresses = erased_hosts;
@@ -1116,6 +1183,7 @@ CfgHosts::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
size_t
CfgHosts::delAll4(const SubnetID& subnet_id) {
HostContainerIndex2& idx = hosts_.get<2>();
MultiThreadingLock lock(*mutex_);
size_t erased = idx.erase(subnet_id);
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_DEL_ALL_SUBNET4)
@@ -1131,6 +1199,7 @@ CfgHosts::del4(const SubnetID& subnet_id,
const uint8_t* identifier_begin,
const size_t identifier_len) {
HostContainerIndex0& idx = hosts_.get<0>();
MultiThreadingLock lock(*mutex_);
auto const t = boost::make_tuple(std::vector<uint8_t>(identifier_begin,
identifier_begin + identifier_len),
identifier_type);
@@ -1159,6 +1228,7 @@ size_t
CfgHosts::delAll6(const SubnetID& subnet_id) {
// Delete IPv6 reservations.
HostContainer6Index2& idx6 = hosts6_.get<2>();
MultiThreadingLock lock(*mutex_);
size_t erased_addresses = idx6.erase(subnet_id);
// Delete hosts.
@@ -1184,6 +1254,7 @@ CfgHosts::del6(const SubnetID& subnet_id,
auto const t = boost::make_tuple(std::vector<uint8_t>(identifier_begin,
identifier_begin + identifier_len),
identifier_type);
MultiThreadingLock lock(*mutex_);
auto const& range = idx.equal_range(t);
size_t erased_hosts = 0;
size_t erased_reservations = 0;
@@ -1213,6 +1284,7 @@ CfgHosts::del6(const SubnetID& subnet_id,
bool
CfgHosts::setIPReservationsUnique(const bool unique) {
MultiThreadingLock lock(*mutex_);
ip_reservations_unique_ = unique;
return (true);
}
@@ -1236,6 +1308,7 @@ CfgHosts::toElement4() const {
CfgHostsList result;
// Iterate using arbitrary the index 0
const HostContainerIndex0& idx = hosts_.get<0>();
MultiThreadingLock lock(*mutex_);
for (auto const& host : idx) {
// Convert host to element representation
@@ -1253,6 +1326,7 @@ CfgHosts::toElement6() const {
CfgHostsList result;
// Iterate using arbitrary the index 0
const HostContainerIndex0& idx = hosts_.get<0>();
MultiThreadingLock lock(*mutex_);
for (auto const& host : idx) {
// Convert host to Element representation

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014-2023 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -14,7 +14,10 @@
#include <dhcpsrv/host_container.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/writable_host_data_source.h>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <set>
#include <mutex>
#include <vector>
namespace isc {
@@ -38,6 +41,9 @@ class CfgHosts : public BaseHostDataSource, public WritableHostDataSource,
public isc::data::CfgToElement {
public:
/// @brief Constructor.
CfgHosts();
/// @brief Destructor.
virtual ~CfgHosts() { }
@@ -536,13 +542,13 @@ public:
/// has already been added to the IPv4 or IPv6 subnet.
virtual void add(const HostPtr& host);
/// @brief Attempts to delete a hosts by address.
/// @brief Attempts to delete hosts by address.
///
/// This method supports both v4 and v6.
/// @todo: Not implemented.
///
/// @param subnet_id subnet identifier.
/// @param addr specified address.
/// @return true if deletion was successful, false otherwise.
virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr);
/// @brief Attempts to delete all hosts for a given IPv4 subnet.
@@ -555,7 +561,6 @@ public:
/// @brief Attempts to delete a host by (subnet4-id, identifier, identifier-type)
///
/// This method supports v4 only.
/// @todo: Not implemented.
///
/// @param subnet_id IPv4 Subnet identifier.
/// @param identifier_type Identifier type.
@@ -577,7 +582,6 @@ public:
/// @brief Attempts to delete a host by (subnet6-id, identifier, identifier-type)
///
/// This method supports v6 only.
/// @todo: Not implemented.
///
/// @param subnet_id IPv6 Subnet identifier.
/// @param identifier_type Identifier type.
@@ -635,6 +639,9 @@ public:
private:
/// @note: all private/internal methods suppose the caller takes
/// the mutex at the exception of toElement[46].
/// @brief Returns @c Host objects for the specific identifier and type.
///
/// This private method is called by the @c CfgHosts::getAll
@@ -812,6 +819,19 @@ private:
void getAllInternal6(const asiolink::IOAddress& address,
Storage& storage) const;
/// @brief Returns @c Host objects for the specified (Subnet-id,IPv6 address) tuple.
///
/// This private method is called by the @c CfgHosts::getAll4 methods
/// to retrieve the @c Host for which the specified IPv4 address is
/// reserved and is in specified subnet-id. The retrieved objects are
/// appended to the returned container.
///
/// @param subnet_id Subnet identifier.
/// @param address IPv4 address.
/// @return Collection of const @c Host objects.
ConstHostCollection
getAllInternal4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Returns @c Host objects for the specified (Subnet-id,IPv6 address) tuple.
///
@@ -924,6 +944,9 @@ private:
/// may be non-unique.
bool ip_reservations_unique_ = true;
/// @brief The mutex used to protect host containers.
const boost::scoped_ptr<std::mutex> mutex_;
/// @brief Unparse a configuration object (DHCPv4 reservations)
///
/// @return a pointer to unparsed configuration

View File

@@ -14,6 +14,7 @@
#include <dhcpsrv/host.h>
#include <dhcpsrv/cfgmgr.h>
#include <testutils/gtest_utils.h>
#include <testutils/multi_threading_utils.h>
#include <gtest/gtest.h>
@@ -21,8 +22,10 @@
#include <set>
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::test;
using namespace isc::util;
namespace {
@@ -55,6 +58,40 @@ public:
/// @param address Address to be increased.
IOAddress increase(const IOAddress& address, const uint8_t num) const;
/// @brief test methods.
void testGetAllNonRepeatingHosts();
void testGetAllRepeatingHosts();
void testGetAll4BySubnet();
void testGetAll6BySubnet();
void testGetAll6ByAddress();
void testGetPage4();
void testGetPage6();
void testGetPage4All();
void testGetPage6All();
void testGetAll4ByAddress();
void testDeleteForIPv4();
void testDeleteForIPv6();
void testDel4();
void testDel6();
void testDeleteAll4();
void testGet4();
void testUnparsed4();
void testGet6();
void testDeleteAll6();
void testUnparse6();
void testGet6ByAddr();
void testGet6MultipleAddrs();
void testAdd4AlreadyReserved();
void testAllow4AlreadyReserved();
void testAdd6Invalid2Hosts();
void testAllowAddress6AlreadyReserved();
void testAllowPrefix6AlreadyReserved();
void testDuplicatesSubnet4HWAddr();
void testDuplicatesSubnet4DUID();
void testDuplicatesSubnet6HWAddr();
void testDuplicatesSubnet6DUID();
void testUpdate();
/// @brief Collection of HW address objects allocated for unit tests.
std::vector<HWAddrPtr> hwaddrs_;
/// @brief Collection of DUIDs allocated for unit tests.
@@ -95,10 +132,12 @@ CfgHostsTest::CfgHostsTest() {
IOAddress addrb(addrb_template + i);
addressesb_.push_back(addrb);
}
MultiThreadingMgr::instance().setMode(false);
}
CfgHostsTest::~CfgHostsTest() {
CfgMgr::instance().setFamily(AF_INET);
MultiThreadingMgr::instance().setMode(false);
}
IOAddress
@@ -113,7 +152,8 @@ CfgHostsTest::increase(const IOAddress& address, const uint8_t num) const {
// This test checks that hosts with unique HW addresses and DUIDs can be
// retrieved from the host configuration.
TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
void
CfgHostsTest::testGetAllNonRepeatingHosts() {
CfgHosts cfg;
// Add 25 hosts identified by HW address and 25 hosts identified by
// DUID. They are added to different subnets.
@@ -161,9 +201,19 @@ TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
}
}
TEST_F(CfgHostsTest, getAllNonRepeatingHosts) {
testGetAllNonRepeatingHosts();
}
TEST_F(CfgHostsTest, getAllNonRepeatingHostsMultiThreading) {
MultiThreadingTest mt(true);
testGetAllNonRepeatingHosts();
}
// This test verifies that the host can be added to multiple subnets and
// that the getAll message retrieves all instances of the host.
TEST_F(CfgHostsTest, getAllRepeatingHosts) {
void
CfgHostsTest::testGetAllRepeatingHosts() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -219,9 +269,19 @@ TEST_F(CfgHostsTest, getAllRepeatingHosts) {
}
}
TEST_F(CfgHostsTest, getAllRepeatingHosts) {
testGetAllRepeatingHosts();
}
TEST_F(CfgHostsTest, getAllRepeatingHostsMultiThreading) {
MultiThreadingTest mt(true);
testGetAllRepeatingHosts();
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration.
TEST_F(CfgHostsTest, getAll4BySubnet) {
void
CfgHostsTest::testGetAll4BySubnet() {
CfgHosts cfg;
// Add 25 hosts identified by HW address in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
@@ -245,9 +305,19 @@ TEST_F(CfgHostsTest, getAll4BySubnet) {
}
}
TEST_F(CfgHostsTest, getAll4BySubnet) {
testGetAll4BySubnet();
}
TEST_F(CfgHostsTest, getAll4BySubnetMultiThreading) {
MultiThreadingTest mt(true);
testGetAll4BySubnet();
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration.
TEST_F(CfgHostsTest, getAll6BySubnet) {
void
CfgHostsTest::testGetAll6BySubnet() {
CfgHosts cfg;
// Add 25 hosts identified by DUID in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
@@ -277,9 +347,19 @@ TEST_F(CfgHostsTest, getAll6BySubnet) {
}
}
TEST_F(CfgHostsTest, getAll6BySubnet) {
testGetAll6BySubnet();
}
TEST_F(CfgHostsTest, getAll6BySubnetMultiThreading) {
MultiThreadingTest mt(true);
testGetAll6BySubnet();
}
// This test checks that hosts with the same reserved address can be retrieved
// from the host configuration.
TEST_F(CfgHostsTest, getAll6ByAddress) {
void
CfgHostsTest::testGetAll6ByAddress() {
CfgHosts cfg;
// Add 25 hosts identified by DUID in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
@@ -305,9 +385,19 @@ TEST_F(CfgHostsTest, getAll6ByAddress) {
}
}
TEST_F(CfgHostsTest, getAll6ByAddress) {
testGetAll6ByAddress();
}
TEST_F(CfgHostsTest, getAll6ByAddressMultiThreading) {
MultiThreadingTest mt(true);
testGetAll6ByAddress();
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration by pages.
TEST_F(CfgHostsTest, getPage4) {
void
CfgHostsTest::testGetPage4() {
CfgHosts cfg;
// Add 25 hosts identified by DUID in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
@@ -342,9 +432,19 @@ TEST_F(CfgHostsTest, getPage4) {
EXPECT_EQ(0, page.size());
}
TEST_F(CfgHostsTest, getPage4) {
testGetPage4();
}
TEST_F(CfgHostsTest, getPage4MultiThreading) {
MultiThreadingTest mt(true);
testGetPage4();
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration by pages.
TEST_F(CfgHostsTest, getPage6) {
void
CfgHostsTest::testGetPage6() {
CfgHosts cfg;
// Add 25 hosts identified by HW address in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
@@ -384,9 +484,19 @@ TEST_F(CfgHostsTest, getPage6) {
EXPECT_EQ(0, page.size());
}
TEST_F(CfgHostsTest, getPage6) {
testGetPage6();
}
TEST_F(CfgHostsTest, getPage6MultiThreading) {
MultiThreadingTest mt(true);
testGetPage6();
}
// This test checks that all hosts can be retrieved from the host
// configuration by pages.
TEST_F(CfgHostsTest, getPage4All) {
void
CfgHostsTest::testGetPage4All() {
CfgHosts cfg;
// Add 25 hosts identified by DUID.
for (unsigned i = 0; i < 25; ++i) {
@@ -417,9 +527,19 @@ TEST_F(CfgHostsTest, getPage4All) {
EXPECT_EQ(0, page.size());
}
TEST_F(CfgHostsTest, getPage4All) {
testGetPage4All();
}
TEST_F(CfgHostsTest, getPage4AllMultiThreading) {
MultiThreadingTest mt(true);
testGetPage4All();
}
// This test checks that all hosts can be retrieved from the host
// configuration by pages.
TEST_F(CfgHostsTest, getPage6All) {
void
CfgHostsTest::testGetPage6All() {
CfgHosts cfg;
// Add 25 hosts identified by HW address.
for (unsigned i = 0; i < 25; ++i) {
@@ -455,9 +575,19 @@ TEST_F(CfgHostsTest, getPage6All) {
EXPECT_EQ(0, page.size());
}
TEST_F(CfgHostsTest, getPage6All) {
testGetPage6All();
}
TEST_F(CfgHostsTest, getPage6AllMultiThreading) {
MultiThreadingTest mt(true);
testGetPage6All();
}
// This test checks that all reservations for the specified IPv4 address can
// be retrieved.
TEST_F(CfgHostsTest, getAll4ByAddress) {
void
CfgHostsTest::testGetAll4ByAddress() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -483,9 +613,19 @@ TEST_F(CfgHostsTest, getAll4ByAddress) {
EXPECT_EQ(25, *subnet_ids.rbegin());
}
TEST_F(CfgHostsTest, getAll4ByAddress) {
testGetAll4ByAddress();
}
TEST_F(CfgHostsTest, getAll4ByAddressMultiThreading) {
MultiThreadingTest mt(true);
testGetAll4ByAddress();
}
// This test checks that the IPv4 reservation for the specified IPv4 address can
// be deleted.
TEST_F(CfgHostsTest, deleteForIPv4) {
void
CfgHostsTest::testDeleteForIPv4() {
CfgHosts cfg;
// Add hosts.
IOAddress address("10.0.0.42");
@@ -517,9 +657,19 @@ TEST_F(CfgHostsTest, deleteForIPv4) {
EXPECT_EQ(0, hosts_by_address.size());
}
TEST_F(CfgHostsTest, deleteForIPv4) {
testDeleteForIPv4();
}
TEST_F(CfgHostsTest, deleteForIPv4MultiThreading) {
MultiThreadingTest mt(true);
testDeleteForIPv4();
}
// This test checks that the IPv6 reservation for the specified subnet ID and
// IPv6 address can be deleted.
TEST_F(CfgHostsTest, deleteForIPv6) {
void
CfgHostsTest::testDeleteForIPv6() {
CfgHosts cfg;
// Add hosts.
IOAddress address("2001:db8:1::1");
@@ -554,6 +704,15 @@ TEST_F(CfgHostsTest, deleteForIPv6) {
EXPECT_EQ(host_count-1, hosts_by_subnet.size());
}
TEST_F(CfgHostsTest, deleteForIPv6) {
testDeleteForIPv6();
}
TEST_F(CfgHostsTest, deleteForIPv6MultiThreading) {
MultiThreadingTest mt(true);
testDeleteForIPv6();
}
// This test checks that false is returned for deleting the IPv4 reservation
// that doesn't exist.
TEST_F(CfgHostsTest, deleteForMissingIPv4) {
@@ -561,6 +720,9 @@ TEST_F(CfgHostsTest, deleteForMissingIPv4) {
// Delete non-existent host.
EXPECT_FALSE(cfg.del(SubnetID(42), IOAddress(("10.0.0.42"))));
MultiThreadingTest mt(true);
EXPECT_FALSE(cfg.del(SubnetID(42), IOAddress(("10.0.0.42"))));
}
// This test checks that false is returned for deleting the IPv6 reservation
@@ -570,11 +732,15 @@ TEST_F(CfgHostsTest, deleteForMissingIPv6) {
// Delete non-existent host.
EXPECT_FALSE(cfg.del(SubnetID(42), IOAddress(("2001:db8:1::1"))));
MultiThreadingTest mt(true);
EXPECT_FALSE(cfg.del(SubnetID(42), IOAddress(("2001:db8:1::1"))));
}
// This test checks that the reservation for the specified IPv4 subnet and
// identifier can be deleted.
TEST_F(CfgHostsTest, del4) {
void
CfgHostsTest::testDel4() {
CfgHosts cfg;
// Add hosts.
@@ -627,9 +793,19 @@ TEST_F(CfgHostsTest, del4) {
EXPECT_FALSE(host);
}
TEST_F(CfgHostsTest, del4) {
testDel4();
}
TEST_F(CfgHostsTest, del4MultiThreading) {
MultiThreadingTest mt(true);
testDel4();
}
// This test checks that the host and its reservations for the specified IPv6
// subnet and identifier can be deleted.
TEST_F(CfgHostsTest, del6) {
void
CfgHostsTest::testDel6() {
CfgHosts cfg;
// Add hosts.
@@ -686,12 +862,24 @@ TEST_F(CfgHostsTest, del6) {
EXPECT_FALSE(host);
}
TEST_F(CfgHostsTest, del6) {
testDel6();
}
TEST_F(CfgHostsTest, del6MultiThreading) {
MultiThreadingTest mt(true);
testDel6();
}
// This test checks that false is returned for deleting the IPv4 host that
// doesn't exist.
TEST_F(CfgHostsTest, del4MissingHost) {
CfgHosts cfg;
EXPECT_FALSE(cfg.del4(SubnetID(42), Host::IdentifierType::IDENT_DUID,
&duids_[0]->getDuid()[0], duids_[0]->getDuid().size()));
MultiThreadingTest mt(true);
EXPECT_FALSE(cfg.del4(SubnetID(42), Host::IdentifierType::IDENT_DUID,
&duids_[0]->getDuid()[0], duids_[0]->getDuid().size()));
}
// This test checks that false is returned for deleting the IPv6 host that
@@ -700,11 +888,15 @@ TEST_F(CfgHostsTest, del6MissingHost) {
CfgHosts cfg;
EXPECT_FALSE(cfg.del6(SubnetID(42), Host::IdentifierType::IDENT_DUID,
&duids_[0]->getDuid()[0], duids_[0]->getDuid().size()));
MultiThreadingTest mt(true);
EXPECT_FALSE(cfg.del6(SubnetID(42), Host::IdentifierType::IDENT_DUID,
&duids_[0]->getDuid()[0], duids_[0]->getDuid().size()));
}
// This test checks that all reservations for the specified IPv4 subnet can
// be deleted.
TEST_F(CfgHostsTest, deleteAll4) {
void
CfgHostsTest::testDeleteAll4() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -748,9 +940,19 @@ TEST_F(CfgHostsTest, deleteAll4) {
EXPECT_EQ(1, *subnet_ids.begin());
}
TEST_F(CfgHostsTest, deleteAll4) {
testDeleteAll4();
}
TEST_F(CfgHostsTest, deleteAll4MultiThreading) {
MultiThreadingTest mt(true);
testDeleteAll4();
}
// This test checks that the reservations can be retrieved for the particular
// host connected to the specific IPv4 subnet (by subnet id).
TEST_F(CfgHostsTest, get4) {
void
CfgHostsTest::testGet4() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -787,8 +989,18 @@ TEST_F(CfgHostsTest, get4) {
}
}
TEST_F(CfgHostsTest, get4) {
testGet4();
}
TEST_F(CfgHostsTest, get4MultiThreading) {
MultiThreadingTest mt(true);
testGet4();
}
// This test checks that the DHCPv4 reservations can be unparsed
TEST_F(CfgHostsTest, unparsed4) {
void
CfgHostsTest::testUnparsed4() {
CfgMgr::instance().setFamily(AF_INET);
CfgHosts cfg;
CfgHostsList list;
@@ -871,9 +1083,19 @@ TEST_F(CfgHostsTest, unparsed4) {
}
}
TEST_F(CfgHostsTest, unparsed4) {
testUnparsed4();
}
TEST_F(CfgHostsTest, unparsed4MultiThreading) {
MultiThreadingTest mt(true);
testUnparsed4();
}
// This test checks that the reservations can be retrieved for the particular
// host connected to the specific IPv6 subnet (by subnet id).
TEST_F(CfgHostsTest, get6) {
void
CfgHostsTest::testGet6() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -922,9 +1144,19 @@ TEST_F(CfgHostsTest, get6) {
}
}
TEST_F(CfgHostsTest, get6) {
testGet6();
}
TEST_F(CfgHostsTest, get6MultiThreading) {
MultiThreadingTest mt(true);
testGet6();
}
// This test checks that all reservations for the specified IPv6 subnet can
// be deleted.
TEST_F(CfgHostsTest, deleteAll6) {
void
CfgHostsTest::testDeleteAll6() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -969,8 +1201,18 @@ TEST_F(CfgHostsTest, deleteAll6) {
}
}
TEST_F(CfgHostsTest, deleteAll6) {
testDeleteAll6();
}
TEST_F(CfgHostsTest, deleteAll6MultiThreading) {
MultiThreadingTest mt(true);
testDeleteAll6();
}
// This test checks that the DHCPv6 reservations can be unparsed
TEST_F(CfgHostsTest, unparse6) {
void
CfgHostsTest::testUnparse6() {
CfgMgr::instance().setFamily(AF_INET6);
CfgHosts cfg;
CfgHostsList list;
@@ -1071,9 +1313,19 @@ TEST_F(CfgHostsTest, unparse6) {
}
}
TEST_F(CfgHostsTest, unparse6) {
testUnparse6();
}
TEST_F(CfgHostsTest, unparse6MultiThreading) {
MultiThreadingTest mt(true);
testUnparse6();
}
// This test checks that the IPv6 reservations can be retrieved for a particular
// (subnet-id, address) tuple.
TEST_F(CfgHostsTest, get6ByAddr) {
void
CfgHostsTest::testGet6ByAddr() {
CfgHosts cfg;
// Add hosts.
for (unsigned i = 0; i < 25; ++i) {
@@ -1103,9 +1355,19 @@ TEST_F(CfgHostsTest, get6ByAddr) {
}
}
TEST_F(CfgHostsTest, get6ByAddr) {
testGet6ByAddr();
}
TEST_F(CfgHostsTest, get6ByAddrMultiThreading) {
MultiThreadingTest mt(true);
testGet6ByAddr();
}
// This test checks that the IPv6 reservations can be retrieved for a particular
// (subnet-id, address) tuple.
TEST_F(CfgHostsTest, get6MultipleAddrs) {
void
CfgHostsTest::testGet6MultipleAddrs() {
CfgHosts cfg;
// Add 25 hosts. Each host has reservations for 5 addresses.
@@ -1154,10 +1416,19 @@ TEST_F(CfgHostsTest, get6MultipleAddrs) {
}
}
TEST_F(CfgHostsTest, get6MultipleAddrs) {
testGet6MultipleAddrs();
}
TEST_F(CfgHostsTest, get6MultipleAddrsMultiThreading) {
MultiThreadingTest mt(true);
testGet6MultipleAddrs();
}
// Checks that it's not possible for a second host to reserve an address
// which is already reserved.
TEST_F(CfgHostsTest, add4AlreadyReserved) {
void
CfgHostsTest::testAdd4AlreadyReserved() {
CfgHosts cfg;
// First host has a reservation for address 192.0.2.1
@@ -1179,9 +1450,19 @@ TEST_F(CfgHostsTest, add4AlreadyReserved) {
EXPECT_THROW(cfg.add(host2), isc::dhcp::ReservedAddress);
}
TEST_F(CfgHostsTest, add4AlreadyReserved) {
testAdd4AlreadyReserved();
}
TEST_F(CfgHostsTest, add4AlreadyReservedMultiThreading) {
MultiThreadingTest mt(true);
testAdd4AlreadyReserved();
}
// Test that it is possible to allow inserting multiple reservations for
// the same IP address.
TEST_F(CfgHostsTest, allow4AlreadyReserved) {
void
CfgHostsTest::testAllow4AlreadyReserved() {
CfgHosts cfg;
// Allow creating multiple reservations for the same IP address.
ASSERT_TRUE(cfg.setIPReservationsUnique(false));
@@ -1212,9 +1493,19 @@ TEST_F(CfgHostsTest, allow4AlreadyReserved) {
returned[1]->getIPv4Reservation().toText());
}
TEST_F(CfgHostsTest, allow4AlreadyReserved) {
testAllow4AlreadyReserved();
}
TEST_F(CfgHostsTest, allow4AlreadyReservedMultiThreading) {
MultiThreadingTest mt(true);
testAllow4AlreadyReserved();
}
// Checks that it's not possible for two hosts to have the same address
// reserved at the same time.
TEST_F(CfgHostsTest, add6Invalid2Hosts) {
void
CfgHostsTest::testAdd6Invalid2Hosts() {
CfgHosts cfg;
// First host has a reservation for address 2001:db8::1
@@ -1238,9 +1529,19 @@ TEST_F(CfgHostsTest, add6Invalid2Hosts) {
EXPECT_THROW(cfg.add(host2), isc::dhcp::DuplicateHost);
}
TEST_F(CfgHostsTest, add6Invalid2Hosts) {
testAdd6Invalid2Hosts();
}
TEST_F(CfgHostsTest, add6Invalid2HostsMultiThreading) {
MultiThreadingTest mt(true);
testAdd6Invalid2Hosts();
}
// Test that it is possible to allow inserting multiple reservations for
// the same IPv6 address.
TEST_F(CfgHostsTest, allowAddress6AlreadyReserved) {
void
CfgHostsTest::testAllowAddress6AlreadyReserved() {
CfgHosts cfg;
// Allow creating multiple reservations for the same IP address.
ASSERT_TRUE(cfg.setIPReservationsUnique(false));
@@ -1279,9 +1580,19 @@ TEST_F(CfgHostsTest, allowAddress6AlreadyReserved) {
range1.first->second.getPrefix().toText());
}
TEST_F(CfgHostsTest, allowAddress6AlreadyReserved) {
testAllowAddress6AlreadyReserved();
}
TEST_F(CfgHostsTest, allowAddress6AlreadyReservedMultiThreading) {
MultiThreadingTest mt(true);
testAllowAddress6AlreadyReserved();
}
// Test that it is possible to allow inserting multiple reservations for
// the same IPv6 delegated prefix.
TEST_F(CfgHostsTest, allowPrefix6AlreadyReserved) {
void
CfgHostsTest::testAllowPrefix6AlreadyReserved() {
CfgHosts cfg;
// Allow creating multiple reservations for the same delegated prefix.
ASSERT_TRUE(cfg.setIPReservationsUnique(false));
@@ -1320,6 +1631,15 @@ TEST_F(CfgHostsTest, allowPrefix6AlreadyReserved) {
range1.first->second.getPrefix().toText());
}
TEST_F(CfgHostsTest, allowPrefix6AlreadyReserved) {
testAllowPrefix6AlreadyReserved();
}
TEST_F(CfgHostsTest, allowPrefix6AlreadyReservedMultiThreading) {
MultiThreadingTest mt(true);
testAllowPrefix6AlreadyReserved();
}
// Check that no error is reported when adding a host with subnet
// ids equal to global.
TEST_F(CfgHostsTest, globalSubnetIDs) {
@@ -1344,7 +1664,8 @@ TEST_F(CfgHostsTest, unusedSubnetIDs) {
// This test verifies that it is not possible to add the same Host to the
// same IPv4 subnet twice.
TEST_F(CfgHostsTest, duplicatesSubnet4HWAddr) {
void
CfgHostsTest::testDuplicatesSubnet4HWAddr() {
CfgHosts cfg;
// Add a host.
ASSERT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
@@ -1367,9 +1688,19 @@ TEST_F(CfgHostsTest, duplicatesSubnet4HWAddr) {
IOAddress("10.0.0.10")))));
}
TEST_F(CfgHostsTest, duplicatesSubnet4HWAddr) {
testDuplicatesSubnet4HWAddr();
}
TEST_F(CfgHostsTest, duplicatesSubnet4HWAddrMultiThreading) {
MultiThreadingTest mt(true);
testDuplicatesSubnet4HWAddr();
}
// This test verifies that it is not possible to add the same Host to the
// same IPv4 subnet twice.
TEST_F(CfgHostsTest, duplicatesSubnet4DUID) {
void
CfgHostsTest::testDuplicatesSubnet4DUID() {
CfgHosts cfg;
// Add a host.
ASSERT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
@@ -1392,9 +1723,19 @@ TEST_F(CfgHostsTest, duplicatesSubnet4DUID) {
IOAddress("10.0.0.10")))));
}
TEST_F(CfgHostsTest, duplicatesSubnet4DUID) {
testDuplicatesSubnet4DUID();
}
TEST_F(CfgHostsTest, duplicatesSubnet4DUIDMultiThreading) {
MultiThreadingTest mt(true);
testDuplicatesSubnet4DUID();
}
// This test verifies that it is not possible to add the same Host to the
// same IPv6 subnet twice.
TEST_F(CfgHostsTest, duplicatesSubnet6HWAddr) {
void
CfgHostsTest::testDuplicatesSubnet6HWAddr() {
CfgHosts cfg;
// Add a host.
ASSERT_NO_THROW(cfg.add(HostPtr(new Host(hwaddrs_[0]->toText(false),
@@ -1420,9 +1761,19 @@ TEST_F(CfgHostsTest, duplicatesSubnet6HWAddr) {
"foo.example.com"))));
}
TEST_F(CfgHostsTest, duplicatesSubnet6HWAddr) {
testDuplicatesSubnet6HWAddr();
}
TEST_F(CfgHostsTest, duplicatesSubnet6HWAddrMultiThreading) {
MultiThreadingTest mt(true);
testDuplicatesSubnet6HWAddr();
}
// This test verifies that it is not possible to add the same Host to the
// same IPv6 subnet twice.
TEST_F(CfgHostsTest, duplicatesSubnet6DUID) {
void
CfgHostsTest::testDuplicatesSubnet6DUID() {
CfgHosts cfg;
// Add a host.
ASSERT_NO_THROW(cfg.add(HostPtr(new Host(duids_[0]->toText(),
@@ -1448,8 +1799,18 @@ TEST_F(CfgHostsTest, duplicatesSubnet6DUID) {
"foo.example.com"))));
}
// Checks that updates work correctly.
TEST_F(CfgHostsTest, update) {
TEST_F(CfgHostsTest, duplicatesSubnet6DUID) {
testDuplicatesSubnet6DUID();
}
TEST_F(CfgHostsTest, duplicatesSubnet6DUIDMultiThreading) {
MultiThreadingTest mt(true);
testDuplicatesSubnet6DUID();
}
// Checks that updates work correctly. Note it is not really MT safe.
void
CfgHostsTest::testUpdate() {
CfgHosts cfg;
HostPtr const host(boost::make_shared<Host>(duids_[0]->toText(), "duid", SUBNET_ID_UNUSED,
@@ -1506,4 +1867,13 @@ TEST_F(CfgHostsTest, update) {
"key=(empty) ipv6_reservations=(none)", hosts[0]->toText());
}
TEST_F(CfgHostsTest, update) {
testUpdate();
}
TEST_F(CfgHostsTest, updateMultiThreading) {
MultiThreadingTest mt(true);
testUpdate();
}
} // namespace