#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>
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,
// 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);
// 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);
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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,
// 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,
// 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,
// 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,
// 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);
// 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);
// 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);
// 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);
// 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);
}
// 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);
}
// 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);
}
// 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);
}
.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 {
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));
}
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));
}
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
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));
}
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));
}
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));
}
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));
}
CfgHosts::getAll6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostCollection hosts;
+ MultiThreadingLock lock(*mutex_);
getAllInternal6(subnet_id, address, hosts);
return (hosts);
}
" 0 when adding new host reservation");
}
+ MultiThreadingLock lock(*mutex_);
+
add4(host);
add6(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()
// 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()
// 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)")
// 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()));
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)")
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;
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)
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);
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.
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;
bool
CfgHosts::setIPReservationsUnique(const bool unique) {
+ MultiThreadingLock lock(*mutex_);
ip_reservations_unique_ = unique;
return (true);
}
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
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
-// 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
#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 {
public isc::data::CfgToElement {
public:
+ /// @brief Constructor.
+ CfgHosts();
+
/// @brief Destructor.
virtual ~CfgHosts() { }
/// 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.
/// @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.
/// @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.
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
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.
///
/// 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
#include <dhcpsrv/host.h>
#include <dhcpsrv/cfgmgr.h>
#include <testutils/gtest_utils.h>
+#include <testutils/multi_threading_utils.h>
#include <gtest/gtest.h>
#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 {
/// @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.
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
// 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.
}
}
+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) {
}
}
+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) {
}
}
+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) {
}
}
+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) {
}
}
+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) {
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) {
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) {
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) {
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) {
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");
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");
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) {
// 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
// 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.
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.
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
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) {
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) {
}
}
+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;
}
}
+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) {
}
}
+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) {
}
}
+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;
}
}
+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) {
}
}
+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.
}
}
+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
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));
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
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));
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));
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) {
// 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),
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(),
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),
"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(),
"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,
"key=(empty) ipv6_reservations=(none)", hosts[0]->toText());
}
+TEST_F(CfgHostsTest, update) {
+ testUpdate();
+}
+
+TEST_F(CfgHostsTest, updateMultiThreading) {
+ MultiThreadingTest mt(true);
+ testUpdate();
+}
+
} // namespace