]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2815] Implement del6 function
authorSlawek Figiel <slawek@isc.org>
Thu, 6 Apr 2023 15:00:08 +0000 (17:00 +0200)
committerSlawek Figiel <slawek@isc.org>
Thu, 25 May 2023 11:29:29 +0000 (13:29 +0200)
src/lib/dhcpsrv/cfg_hosts.cc
src/lib/dhcpsrv/host_container.h
src/lib/dhcpsrv/hosts_messages.cc
src/lib/dhcpsrv/hosts_messages.h
src/lib/dhcpsrv/hosts_messages.mes
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc

index e1da797ff9a0af68c23bc7ad2c324a5e1de4e6b6..2ea5ad0fd79918bb74c2b69a3f458c1dba95faac 100644 (file)
@@ -1179,13 +1179,40 @@ CfgHosts::delAll6(const SubnetID& subnet_id) {
 }
 
 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
index 7cf9c647be5914482950e577793df8c4bdea7262..cb106adc24bf38abd6c7bcaa1e42728b25f4ba52 100644 (file)
@@ -179,10 +179,15 @@ struct HostResrv6Tuple {
     /// @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.
@@ -204,7 +209,7 @@ typedef boost::multi_index_container<
             // 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.
@@ -227,7 +232,7 @@ typedef boost::multi_index_container<
                 // IPv6Resrv::getPrefix() and it will return an IOAddress object.
                 boost::multi_index::const_mem_fun<
                     HostResrv6Tuple, const asiolink::IOAddress&,
-                    &HostResrv6Tuple::getKey
+                    &HostResrv6Tuple::getPrefix
                 >
            >
         >,
@@ -237,6 +242,13 @@ typedef boost::multi_index_container<
             // 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;
@@ -271,6 +283,15 @@ typedef HostContainer6::nth_index<2>::type HostContainer6Index2;
 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
 
index c9d0b3f28c768a51db96eaec4455a27b339cc9f7..4b5b75f46d36b29c453bd07c558bac15995c4613 100644 (file)
@@ -15,6 +15,7 @@ extern const isc::log::MessageID HOSTS_CFG_CACHE_HOST_DATA_SOURCE = "HOSTS_CFG_C
 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";
@@ -89,6 +90,7 @@ const char* values[] = {
     "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",
index d6ed062d92abd52bd48bb601e16a9992d8bc2b18..f40666e6c58a10f1e5b3548ac1ae63e96fac5ed2 100644 (file)
@@ -16,6 +16,7 @@ extern const isc::log::MessageID HOSTS_CFG_CACHE_HOST_DATA_SOURCE;
 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;
index 1bf3ddba7a0d6299e6cadcff44e51b4c4b587498..3c671c8688ee6257ecdde1291f8748f527a157c6 100644 (file)
@@ -39,11 +39,18 @@ The third argument is the subnet identifier. The fourth argument is the IP
 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
index 65a2b5a65e5463d4ab043a009c141195c0e39972..62e1a22e3eaee8caaf1812a762ecda6b2c9db943 100644 (file)
@@ -503,7 +503,7 @@ TEST_F(CfgHostsTest, deleteForIPv6) {
     {
         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);
@@ -600,6 +600,65 @@ TEST_F(CfgHostsTest, del4) {
     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) {