]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#158,!136] Added ability to remove all hosts for subnet id.
authorMarcin Siodelski <marcin@isc.org>
Fri, 23 Nov 2018 08:43:14 +0000 (09:43 +0100)
committerMarcin Siodelski <marcin@isc.org>
Mon, 26 Nov 2018 20:26:33 +0000 (15:26 -0500)
src/lib/dhcpsrv/cfg_hosts.cc
src/lib/dhcpsrv/cfg_hosts.h
src/lib/dhcpsrv/host_container.h
src/lib/dhcpsrv/hosts_messages.mes
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc

index 9725920d9d2af518ea7c268af4e7d5cee6d73fe8..b07fe152ed7d0b3caac46cccf56a6ea63de1c1d8 100644 (file)
@@ -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*/,
index e41ba6a2503161cb93c2d4c1713ed4248c69961a..52b0f4f82c59f278295ab18ec1f890ab4542ccd2 100644 (file)
@@ -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.
index e352051f3606bf32ffe14eaf1c19f2f66d7ac091..4d420b47fcded8c9d83b13303bc349e6a375fe32 100644 (file)
@@ -67,6 +67,20 @@ typedef boost::multi_index_container<
             // Index using values returned by the @c Host::getIPv4Reservation.
             boost::multi_index::const_mem_fun<Host, const asiolink::IOAddress&,
                                                &Host::getIPv4Reservation>
+        >,
+
+        // 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<Host, SubnetID,
+                                              &Host::getIPv4SubnetID>
+        >,
+
+        // 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<Host, SubnetID,
+                                              &Host::getIPv6SubnetID>
         >
     >
 > HostContainer;
@@ -91,6 +105,26 @@ typedef HostContainer::nth_index<1>::type HostContainerIndex1;
 typedef std::pair<HostContainerIndex1::iterator,
                   HostContainerIndex1::iterator> 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<HostContainerIndex2::iterator,
+                  HostContainerIndex2::iterator> 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<HostContainerIndex3::iterator,
+                  HostContainerIndex3::iterator> 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<HostResrv6Tuple, const SubnetID,
+                                       &HostResrv6Tuple::subnet_id_>
         >
     >
 > HostContainer6;
@@ -191,6 +232,16 @@ typedef HostContainer6::nth_index<1>::type HostContainer6Index1;
 typedef std::pair<HostContainer6Index1::iterator,
                   HostContainer6Index1::iterator> 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<HostContainer6Index2::iterator,
+                  HostContainer6Index2::iterator> HostContainer6Index2Range;
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 
index f3ccfde0babde635c001e4581e557f39eeba4780..bdae8d9b1ee7de5756b237d7d291202d2e7b9ccf 100644 (file)
@@ -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
index 9503c7a147ade507a744fa393771771624277530..b105750b4f488b38dafbfa30afc41e87295d5048 100644 (file)
@@ -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<uint32_t> 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);