From: Marcin Siodelski Date: Fri, 23 Nov 2018 08:43:14 +0000 (+0100) Subject: [#158,!136] Added ability to remove all hosts for subnet id. X-Git-Tag: 75-radius-documentation-needs-an-update_base~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=57653336b85eae9b22fcb26b34118f686cfeb0dd;p=thirdparty%2Fkea.git [#158,!136] Added ability to remove all hosts for subnet id. --- diff --git a/src/lib/dhcpsrv/cfg_hosts.cc b/src/lib/dhcpsrv/cfg_hosts.cc index 9725920d9d..b07fe152ed 100644 --- a/src/lib/dhcpsrv/cfg_hosts.cc +++ b/src/lib/dhcpsrv/cfg_hosts.cc @@ -600,6 +600,18 @@ CfgHosts::del(const SubnetID& /*subnet_id*/, const asiolink::IOAddress& /*addr*/ return (false); } +size_t +CfgHosts::delAll4(const SubnetID& subnet_id) { + HostContainerIndex2& idx = hosts_.get<2>(); + size_t erased = idx.erase(subnet_id); + + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_DEL_ALL_SUBNET4) + .arg(erased) + .arg(subnet_id); + + return (erased); +} + bool CfgHosts::del4(const SubnetID& /*subnet_id*/, const Host::IdentifierType& /*identifier_type*/, @@ -610,6 +622,24 @@ CfgHosts::del4(const SubnetID& /*subnet_id*/, return (false); } +size_t +CfgHosts::delAll6(const SubnetID& subnet_id) { + // Delete IPv6 reservations. + HostContainer6Index2& idx6 = hosts6_.get<2>(); + size_t erased_addresses = idx6.erase(subnet_id); + + // Delete hosts. + HostContainerIndex3& idx = hosts_.get<3>(); + size_t erased_hosts = idx.erase(subnet_id); + + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_DEL_ALL_SUBNET6) + .arg(erased_hosts) + .arg(erased_addresses) + .arg(subnet_id); + + return (erased_hosts); +} + bool CfgHosts::del6(const SubnetID& /*subnet_id*/, const Host::IdentifierType& /*identifier_type*/, diff --git a/src/lib/dhcpsrv/cfg_hosts.h b/src/lib/dhcpsrv/cfg_hosts.h index e41ba6a250..52b0f4f82c 100644 --- a/src/lib/dhcpsrv/cfg_hosts.h +++ b/src/lib/dhcpsrv/cfg_hosts.h @@ -241,6 +241,13 @@ public: /// @param addr specified address. virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr); + /// @brief Attempts to delete all hosts for a given IPv4 subnet. + /// + /// @param subnet_id Identifier of the subnet for which reservation should + /// be deleted. + /// @return Number of deleted hosts. + virtual size_t delAll4(const SubnetID& subnet_id); + /// @brief Attempts to delete a host by (subnet4-id, identifier, identifier-type) /// /// This method supports v4 only. @@ -256,6 +263,13 @@ public: const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len); + /// @brief Attempts to delete all hosts for a given IPv6 subnet. + /// + /// @param subnet_id Identifier of the subnet for which reservation should + /// be deleted. + /// @return Number of deleted hosts. + virtual size_t delAll6(const SubnetID& subnet_id); + /// @brief Attempts to delete a host by (subnet6-id, identifier, identifier-type) /// /// This method supports v6 only. diff --git a/src/lib/dhcpsrv/host_container.h b/src/lib/dhcpsrv/host_container.h index e352051f36..4d420b47fc 100644 --- a/src/lib/dhcpsrv/host_container.h +++ b/src/lib/dhcpsrv/host_container.h @@ -67,6 +67,20 @@ typedef boost::multi_index_container< // Index using values returned by the @c Host::getIPv4Reservation. boost::multi_index::const_mem_fun + >, + + // Third index is used to search for the host using IPv4 subnet id + boost::multi_index::ordered_non_unique< + // Index using values returned by the @c Host::getIPv4SubnetID + boost::multi_index::const_mem_fun + >, + + // Forth index is used to search for the host using IPv6 subnet id + boost::multi_index::ordered_non_unique< + // Index using values returned by the @c Host::getIPv6SubnetID + boost::multi_index::const_mem_fun > > > HostContainer; @@ -91,6 +105,26 @@ typedef HostContainer::nth_index<1>::type HostContainerIndex1; typedef std::pair HostContainerIndex1Range; +/// @brief Third index type in the @c HostContainer. +/// +/// This index allows for searching for @c Host objects using a +/// IPv4 subnet id. +typedef HostContainer::nth_index<2>::type HostContainerIndex2; + +/// @brief Results range returned using the @c HostContainerIndex2. +typedef std::pair HostContainerIndex2Range; + +/// @brief Forth index type in the @c HostContainer. +/// +/// This index allows for searching for @c Host objects using a +/// IPv6 subnet id. +typedef HostContainer::nth_index<3>::type HostContainerIndex3; + +/// @brief Results range returned using the @c HostContainerIndex3. +typedef std::pair HostContainerIndex3Range; + /// @brief Defines one entry for the Host Container for v6 hosts /// /// It's essentially a pair of (IPv6 reservation, Host pointer). @@ -167,6 +201,13 @@ typedef boost::multi_index_container< &HostResrv6Tuple::getKey > > + >, + + // Third index is used to search for the host using IPv6 subnet id + boost::multi_index::ordered_non_unique< + // Index using values returned by the @c Host::getIPv6SubnetID + boost::multi_index::member > > > HostContainer6; @@ -191,6 +232,16 @@ typedef HostContainer6::nth_index<1>::type HostContainer6Index1; typedef std::pair HostContainer6Index1Range; +/// @brief Third index type in the @c HostContainer6. +/// +/// This index allows for searching for @c Host objects using a +/// IPv6 subnet id. +typedef HostContainer6::nth_index<2>::type HostContainer6Index2; + +/// @brief Results range returned using the @c HostContainer6Index2. +typedef std::pair HostContainer6Index2Range; + }; // end of isc::dhcp namespace }; // end of isc namespace diff --git a/src/lib/dhcpsrv/hosts_messages.mes b/src/lib/dhcpsrv/hosts_messages.mes index f3ccfde0ba..bdae8d9b1e 100644 --- a/src/lib/dhcpsrv/hosts_messages.mes +++ b/src/lib/dhcpsrv/hosts_messages.mes @@ -31,6 +31,18 @@ detected by the host manager. This is a normal message being printed when the server closes host data source connection. +% 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 +have been deleted. The second argument is the subnet identifier. + +% HOSTS_CFG_DEL_ALL_SUBNET6 deleted all %1 host(s) including %2 IPv6 reservation(s) for subnet id %3 +This debug message is issued when all IPv6 reservations are deleted for +the specified subnet. The first argument specifies how many hosts +have been deleted. The second argument specifies how many IPv6 +(addresses and prefixes) have been deleted. The third argument is the +subnet identifier. + % HOSTS_CFG_GET_ALL_ADDRESS4 get all hosts with reservations for IPv4 address %1 This debug message is issued when starting to retrieve all hosts, holding the reservation for the specific IPv4 address, from the configuration. The diff --git a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc index 9503c7a147..b105750b4f 100644 --- a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc @@ -235,6 +235,54 @@ TEST_F(CfgHostsTest, getAll4ByAddress) { EXPECT_EQ(25, *subnet_ids.rbegin()); } +// This test checks that all reservations for the specified IPv4 subnet can +// be deleted. +TEST_F(CfgHostsTest, deleteAll4) { + CfgHosts cfg; + // Add hosts. + for (unsigned i = 0; i < 25; ++i) { + // Hosts will differ by hostname. It is easier than differentiating by + // IPv4 address because if they all have zero IPv4 address it is + // easier to retrieve all of them to check the host counts. + std::ostringstream s; + s << "hostname" << i; + + // Add host identified by the HW address. + cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false), + "hw-address", + SubnetID(1 + i % 2), SUBNET_ID_UNUSED, + IOAddress::IPV4_ZERO_ADDRESS(), + "hostname"))); + } + + // Get all inserted hosts. + HostCollection hosts = cfg.getAll4(IOAddress::IPV4_ZERO_ADDRESS()); + std::set subnet_ids; + for (HostCollection::const_iterator host = hosts.begin(); host != hosts.end(); + ++host) { + subnet_ids.insert((*host)->getIPv4SubnetID()); + } + // Make sure there are two unique subnets: 1 and 2. + ASSERT_EQ(2, subnet_ids.size()); + EXPECT_EQ(1, *subnet_ids.begin()); + EXPECT_EQ(2, *subnet_ids.rbegin()); + + // Delete all hosts for subnet id 2. There should be 12 of them. + EXPECT_EQ(12, cfg.delAll4(SubnetID(2))); + + // Gather the host counts again. + subnet_ids.clear(); + hosts = cfg.getAll4(IOAddress::IPV4_ZERO_ADDRESS()); + for (HostCollection::const_iterator host = hosts.begin(); host != hosts.end(); + ++host) { + subnet_ids.insert((*host)->getIPv4SubnetID()); + } + // We should only have hosts for one subnet and it should be the subnet + // with ID of 1. + ASSERT_EQ(1, subnet_ids.size()); + EXPECT_EQ(1, *subnet_ids.begin()); +} + // 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) { @@ -409,6 +457,53 @@ TEST_F(CfgHostsTest, get6) { } } +// This test checks that all reservations for the specified IPv6 subnet can +// be deleted. +TEST_F(CfgHostsTest, deleteAll6) { + CfgHosts cfg; + // Add hosts. + for (unsigned i = 0; i < 25; ++i) { + // Add host identified by HW address. The subnet for which we're + // adding the host has id of 1 for even values of i and 2 for + // odd values of i. + HostPtr host = HostPtr(new Host(hwaddrs_[i]->toText(false), + "hw-address", + SubnetID(10), SubnetID(1 + i % 2), + IOAddress("0.0.0.0"))); + host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, + increase(IOAddress("2001:db8:1::1"), + i))); + cfg.add(host); + } + + // Delete all hosts for subnet id. There should be 13 of them. + EXPECT_EQ(13, cfg.delAll6(SubnetID(1))); + + for (unsigned i = 0; i < 25; ++i) { + // Calculate subnet id for the given i. + SubnetID subnet_id = 1 + i % 2; + + // Try to retrieve host by HW address. + HostPtr host = cfg.get6(subnet_id, Host::IDENT_HWADDR, + &hwaddrs_[i]->hwaddr_[0], + hwaddrs_[i]->hwaddr_.size()); + // The host should exist for subnet id of 2. + if (subnet_id == 2) { + ASSERT_TRUE(host); + EXPECT_EQ(subnet_id, host->getIPv6SubnetID()); + IPv6ResrvRange reservations = + host->getIPv6Reservations(IPv6Resrv::TYPE_NA); + ASSERT_EQ(1, std::distance(reservations.first, reservations.second)); + EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i), + reservations.first->second.getPrefix()); + + } else { + // All hosts for subnet id 2 should be gone. + EXPECT_FALSE(host); + } + } +} + // This test checks that the DHCPv6 reservations can be unparsed TEST_F(CfgHostsTest, unparse6) { CfgMgr::instance().setFamily(AF_INET6);