}
bool
-CfgHosts::del6(const SubnetID& /*subnet_id*/,
- const Host::IdentifierType& /*identifier_type*/,
- const uint8_t* /*identifier_begin*/,
- const size_t /*identifier_len*/) {
- /// @todo: Implement host removal
- isc_throw(NotImplemented, "sorry, not implemented");
- return (false);
+CfgHosts::del6(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) {
+ HostContainerIndex0& idx = hosts_.get<0>();
+ HostContainer6Index3& idx6 = hosts6_.get<3>();
+
+ const auto t = boost::make_tuple(std::vector<uint8_t>(identifier_begin,
+ identifier_begin + identifier_len),
+ identifier_type);
+ const auto& range = idx.equal_range(t);
+ size_t erased_hosts = 0;
+ size_t erased_reservations = 0;
+ for (auto key = range.first; key != range.second;) {
+ if ((*key)->getIPv6SubnetID() != subnet_id) {
+ ++key;
+ // Skip hosts from other subnets.
+ continue;
+ }
+
+ // Delete host.
+ key = idx.erase(key);
+ erased_hosts++;
+ // Delete reservations.
+ erased_reservations += idx6.erase((*key)->getHostId());
+ }
+
+ LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_DEL6)
+ .arg(erased_hosts)
+ .arg(erased_reservations)
+ .arg(subnet_id)
+ .arg(Host::getIdentifierAsText(identifier_type, identifier_begin, identifier_len));
+
+ return (erased_hosts != 0);
}
bool
/// @brief Value of the IPv6 Subnet-id
const SubnetID subnet_id_;
- /// @brief Key extractor (used in the second composite key)
- const asiolink::IOAddress& getKey() const {
+ /// @brief Key extractor used in the second composite key
+ const asiolink::IOAddress& getPrefix() const {
return (resrv_.getPrefix());
}
+
+ /// @brief Key extractor used in the fourth composite key
+ HostID getHostId() const {
+ return (host_->getHostId());
+ }
};
/// @brief Multi-index container holding IPv6 reservations.
// Address is extracted by calling IPv6Resrv::getPrefix()
// and it will return an IOAddress object.
boost::multi_index::const_mem_fun<
- HostResrv6Tuple, const asiolink::IOAddress&, &HostResrv6Tuple::getKey>
+ HostResrv6Tuple, const asiolink::IOAddress&, &HostResrv6Tuple::getPrefix>
>,
// Second index is used to search by (subnet_id, address) pair.
// IPv6Resrv::getPrefix() and it will return an IOAddress object.
boost::multi_index::const_mem_fun<
HostResrv6Tuple, const asiolink::IOAddress&,
- &HostResrv6Tuple::getKey
+ &HostResrv6Tuple::getPrefix
>
>
>,
// Index using values returned by the @c Host::getIPv6SubnetID
boost::multi_index::member<HostResrv6Tuple, const SubnetID,
&HostResrv6Tuple::subnet_id_>
+ >,
+
+ // Fourth index is used to search by increasing host id
+ boost::multi_index::ordered_non_unique<
+ // Index using values returned by the @c Host::getHostId
+ boost::multi_index::const_mem_fun<HostResrv6Tuple, uint64_t,
+ &HostResrv6Tuple::getHostId>
>
>
> HostContainer6;
typedef std::pair<HostContainer6Index2::iterator,
HostContainer6Index2::iterator> HostContainer6Index2Range;
+/// @brief Fourth index type in the @c HostContainer6.
+///
+/// This index allows for searching for @c Host objects using a host id.
+typedef HostContainer6::nth_index<3>::type HostContainer6Index3;
+
+/// @brief Results range returned using the @c HostContainer6Index3.
+typedef std::pair<HostContainer6Index3::iterator,
+ HostContainer6Index3::iterator> HostContainer6Index3Range;
+
}; // end of isc::dhcp namespace
}; // end of isc namespace
extern const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE = "HOSTS_CFG_CLOSE_HOST_DATA_SOURCE";
extern const isc::log::MessageID HOSTS_CFG_DEL = "HOSTS_CFG_DEL";
extern const isc::log::MessageID HOSTS_CFG_DEL4 = "HOSTS_CFG_DEL4";
+extern const isc::log::MessageID HOSTS_CFG_DEL6 = "HOSTS_CFG_DEL6";
extern const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET4 = "HOSTS_CFG_DEL_ALL_SUBNET4";
extern const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET6 = "HOSTS_CFG_DEL_ALL_SUBNET6";
extern const isc::log::MessageID HOSTS_CFG_GET_ALL = "HOSTS_CFG_GET_ALL";
"HOSTS_CFG_CLOSE_HOST_DATA_SOURCE", "Closing host data source: %1",
"HOSTS_CFG_DEL", "deleted %1 host(s) having %2 IPv6 reservation(s) for subnet id %3 and address %4",
"HOSTS_CFG_DEL4", "deleted %1 host(s) for subnet id %2 and identifier %3",
+ "HOSTS_CFG_DEL6", "deleted %1 host(s) having %2 IPv6 reservation(s) for subnet id %3 and identifier %4",
"HOSTS_CFG_DEL_ALL_SUBNET4", "deleted all %1 host(s) for subnet id %2",
"HOSTS_CFG_DEL_ALL_SUBNET6", "deleted all %1 host(s) having %2 IPv6 reservation(s) for subnet id %3",
"HOSTS_CFG_GET_ALL", "get all hosts with reservations",
extern const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE;
extern const isc::log::MessageID HOSTS_CFG_DEL;
extern const isc::log::MessageID HOSTS_CFG_DEL4;
+extern const isc::log::MessageID HOSTS_CFG_DEL6;
extern const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET4;
extern const isc::log::MessageID HOSTS_CFG_DEL_ALL_SUBNET6;
extern const isc::log::MessageID HOSTS_CFG_GET_ALL;
address.
% HOSTS_CFG_DEL4 deleted %1 host(s) for subnet id %2 and identifier %3
-This debug message is issued when reservations are deleted for the specified
+This debug message is issued when IPv4 reservations are deleted for the specified
subnet and identifier. The first argument specifies how many hosts have been
deleted. The second argument is the subnet identifier. The third argument is
the identifier.
+% HOSTS_CFG_DEL6 deleted %1 host(s) having %2 IPv6 reservation(s) for subnet id %3 and identifier %4
+This debug message is issued when IPv6 reservations are deleted for the
+specified subnet and identifier. The first argument specifies how many hosts
+have been deleted. The second argument specifies how many reservations have
+been deleted. The third argument is the subnet identifier. The fourth argument
+is the identifier.
+
% HOSTS_CFG_DEL_ALL_SUBNET4 deleted all %1 host(s) for subnet id %2
This debug message is issued when all IPv4 reservations are deleted for
the specified subnet. The first argument specifies how many reservations
{
HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
SUBNET_ID_UNUSED, subnet_id,
- IOAddress("0.0.0.0")));
+ IOAddress::IPV4_ZERO_ADDRESS()));
host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
increase(IOAddress(address), i)));
cfg.add(host);
EXPECT_FALSE(host);
}
+// This test checks that the host and its reservations for the specified IPv6
+// subnet and identifier can be deleted.
+TEST_F(CfgHostsTest, del6) {
+ CfgHosts cfg;
+
+ // Add hosts.
+ size_t host_count = 20;
+ size_t host_id = 5;
+ SubnetID subnet_id(42);
+ IOAddress address("2001:db8:1::1");
+
+ // Add half of the hosts with the same subnet ID but differ with DUID and
+ // address.
+ for (size_t i = 0; i < host_count / 2; i++) {
+ HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
+ SUBNET_ID_UNUSED, subnet_id,
+ IOAddress::IPV4_ZERO_ADDRESS()));
+ host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ increase(IOAddress(address), i)));
+ cfg.add(host);
+ }
+ // Add half of the hosts with the same subnet DUID and address but
+ // differ with address.
+ for (size_t i = 0; i < host_count / 2; i++) {
+ HostPtr host = HostPtr(new Host(duids_[host_id]->toText(), "duid",
+ SUBNET_ID_UNUSED, SubnetID(subnet_id + i + 1),
+ IOAddress::IPV4_ZERO_ADDRESS()));
+ host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ increase(address, host_id)));
+ cfg.add(host);
+ }
+
+
+ // Get all inserted hosts.
+ HostCollection hosts_by_subnet = cfg.getAll6(subnet_id);
+ HostCollection hosts_by_address = cfg.getAll6(increase(address, host_id));
+ HostPtr host = cfg.get6(subnet_id, Host::IdentifierType::IDENT_DUID,
+ &duids_[host_id]->getDuid()[0],
+ duids_[host_id]->getDuid().size());
+ // Make sure the hosts and IP reservations were added.
+ ASSERT_EQ(host_count / 2, hosts_by_subnet.size());
+ ASSERT_EQ(host_count / 2 + 1, hosts_by_address.size());
+ ASSERT_TRUE(host);
+
+ // Delete one host.
+ EXPECT_TRUE(cfg.del6(subnet_id, Host::IdentifierType::IDENT_DUID,
+ &duids_[host_id]->getDuid()[0], duids_[host_id]->getDuid().size()));
+
+ // Check if the host is actually deleted.
+ hosts_by_subnet = cfg.getAll6(subnet_id);
+ hosts_by_address = cfg.getAll6(increase(address, host_id));
+ host = cfg.get6(subnet_id, Host::IdentifierType::IDENT_DUID,
+ &duids_[host_id]->getDuid()[0],
+ duids_[host_id]->getDuid().size());
+ EXPECT_EQ((host_count / 2)-1, hosts_by_subnet.size());
+ EXPECT_EQ(host_count / 2, hosts_by_address.size());
+ EXPECT_FALSE(host);
+}
+
// This test checks that all reservations for the specified IPv4 subnet can
// be deleted.
TEST_F(CfgHostsTest, deleteAll4) {