]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#440,!218] Implemented getSharedNetworkSubnets4 for DHCPv4 CB.
authorMarcin Siodelski <marcin@isc.org>
Mon, 4 Feb 2019 20:36:47 +0000 (21:36 +0100)
committerMarcin Siodelski <marcin@isc.org>
Mon, 4 Feb 2019 20:36:47 +0000 (21:36 +0100)
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h
src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc
src/lib/dhcpsrv/config_backend_dhcp4.h
src/lib/dhcpsrv/config_backend_pool_dhcp4.cc
src/lib/dhcpsrv/config_backend_pool_dhcp4.h
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h

index 7a182eac88b40d1e87c90ccfb351d4c8125bc3b9..d0a10910a1c5187e4ee17012d845734a0c31f6ba 100644 (file)
@@ -60,6 +60,7 @@ public:
         GET_SUBNET4_PREFIX,
         GET_ALL_SUBNETS4,
         GET_MODIFIED_SUBNETS4,
+        GET_SHARED_NETWORK_SUBNETS4,
         GET_POOL4_RANGE,
         GET_SHARED_NETWORK4_NAME,
         GET_ALL_SHARED_NETWORKS4,
@@ -587,6 +588,28 @@ public:
         }
     }
 
+    /// @brief Sends query to retrieve all subnets belonging to a shared network.
+    ///
+    /// @param server_selector Server selector.
+    /// @param shared_network_name Name of the shared network for which the
+    /// subnets should be retrieved.
+    /// @param [out] subnets Reference to the subnet collection structure where
+    /// subnets should be inserted.
+    void getSharedNetworkSubnets4(const ServerSelector& server_selector,
+                                  const std::string& shared_network_name,
+                                  Subnet4Collection& subnets) {
+        auto tags = getServerTags(server_selector);
+
+        for (auto tag : tags) {
+            MySqlBindingCollection in_bindings = {
+                MySqlBinding::createString(tag),
+                MySqlBinding::createString(shared_network_name)
+            };
+
+            getSubnets4(GET_SHARED_NETWORK_SUBNETS4, in_bindings, subnets);
+        }
+    }
+
     /// @brief Sends query to retrieve multiple pools.
     ///
     /// Query should order pools by id.
@@ -728,11 +751,31 @@ public:
 
         // Create binding with shared network name if the subnet belongs to a
         // shared network.
+        MySqlBindingPtr shared_network_binding;
+
         SharedNetwork4Ptr shared_network;
         subnet->getSharedNetwork(shared_network);
-        MySqlBindingPtr shared_network_binding =
-            (shared_network ? MySqlBinding::createString(shared_network->getName()) :
-             MySqlBinding::createNull());
+
+        // Check if the subnet is associated with a shared network instance.
+        // If it is, create the binding using the name of the shared network
+        // returned by this instance.
+        if (shared_network) {
+            shared_network_binding = MySqlBinding::createString(shared_network->getName());
+
+        // If the subnet is associated with a shared network by name (no
+        // shared network instance), use this name to create the binding.
+        // This may be the case if the subnet is added as a result of
+        // receiving a control command that merely specifies shared
+        // network name. In that case, it is expected that the shared
+        // network data is already stored in the database.
+        } else if (!subnet->getSharedNetworkName().empty()) {
+            shared_network_binding = MySqlBinding::createString(subnet->getSharedNetworkName());
+
+        // If the subnet is not associated with a shared network, create
+        // null binding.
+        } else {
+             shared_network_binding = MySqlBinding::createNull();
+        }
 
         // Create input bindings.
         MySqlBindingCollection in_bindings = {
@@ -2094,6 +2137,11 @@ TaggedStatementArray tagged_statements = { {
       MYSQL_GET_SUBNET4(AND s.modification_ts > ?)
     },
 
+    // Select subnets belonging to a shared network.
+    { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK_SUBNETS4,
+      MYSQL_GET_SUBNET4(AND s.shared_network_name = ?)
+    },
+
     // Select pool by address range.
     { MySqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE,
       "SELECT"
@@ -2475,6 +2523,14 @@ MySqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& server_selec
     return (subnets);
 }
 
+Subnet4Collection
+MySqlConfigBackendDHCPv4::getSharedNetworkSubnets4(const ServerSelector& server_selector,
+                                                   const std::string& shared_network_name) const {
+    Subnet4Collection subnets;
+    impl_->getSharedNetworkSubnets4(server_selector, shared_network_name, subnets);
+    return (subnets);
+}
+
 SharedNetwork4Ptr
 MySqlConfigBackendDHCPv4::getSharedNetwork4(const ServerSelector& server_selector,
                                             const std::string& name) const {
index 16e5b4203db97907f3f0952212df31666e26cd7a..f1ef0fb3df632d046d6b8928872d8f46c90933a7 100644 (file)
@@ -65,6 +65,16 @@ public:
     getModifiedSubnets4(const db::ServerSelector& server_selector,
                         const boost::posix_time::ptime& modification_time) const;
 
+    /// @brief Retrieves all subnets belonging to a specified shared network.
+    ///
+    /// @param server_selector Server selector.
+    /// @param shared_network_name Name of the shared network for which the
+    /// subnets should be retrieved.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+                             const std::string& shared_network_name) const;
+
     /// @brief Retrieves shared network by name.
     ///
     /// @param server_selector Server selector.
index 909a97338c5e6c146fb400e6c1c1eb201b2c8853..a8db9c39077b9b7bf86187b75eccb2d1a0a56c20 100644 (file)
@@ -801,6 +801,55 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSubnets4) {
     ASSERT_TRUE(subnets.empty());
 }
 
+// Test that subnets belonging to a shared network can be retrieved.
+TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetworkSubnets4) {
+    // Assign test subnets into shared networks level1 and level2.
+    test_subnets_[1]->setSharedNetworkName("level1");
+    test_subnets_[2]->setSharedNetworkName("level2");
+    test_subnets_[3]->setSharedNetworkName("level2");
+
+    // Store shared networks in the database.
+    for (auto network : test_networks_) {
+        cbptr_->createUpdateSharedNetwork4(ServerSelector::ALL(), network);
+    }
+
+    // Store subnets in the database.
+    for (auto subnet : test_subnets_) {
+        cbptr_->createUpdateSubnet4(ServerSelector::ALL(), subnet);
+    }
+
+    // Fetch all subnets belonging to shared network level1.
+    Subnet4Collection subnets = cbptr_->getSharedNetworkSubnets4(ServerSelector::ALL(),
+                                                                 "level1");
+    ASSERT_EQ(1, subnets.size());
+
+    // Returned subnet should match test subnet #1.
+    EXPECT_EQ(test_subnets_[1]->toElement()->str(), subnets[0]->toElement()->str());
+
+    // All subnets should also be returned for explicitly specified server tag.
+    subnets = cbptr_->getSharedNetworkSubnets4(ServerSelector::ONE("server1"), "level1");
+    ASSERT_EQ(1, subnets.size());
+
+    // Returned subnet should match test subnet #1.
+    EXPECT_EQ(test_subnets_[1]->toElement()->str(), subnets[0]->toElement()->str());
+
+    // Fetch all subnets belonging to shared network level2.
+    subnets = cbptr_->getSharedNetworkSubnets4(ServerSelector::ALL(), "level2");
+    ASSERT_EQ(2, subnets.size());
+
+    // Verify the subnets. It is safe to assume the order in which they have
+    // been returned, because the SELECT statement orders by subnet id.
+    EXPECT_EQ(test_subnets_[2]->toElement()->str(), subnets[0]->toElement()->str());
+    EXPECT_EQ(test_subnets_[3]->toElement()->str(), subnets[1]->toElement()->str());
+
+    // All subnets should also be returned for explicitly specified server tag.
+    subnets = cbptr_->getSharedNetworkSubnets4(ServerSelector::ONE("server1"), "level2");
+    ASSERT_EQ(2, subnets.size());
+
+    EXPECT_EQ(test_subnets_[2]->toElement()->str(), subnets[0]->toElement()->str());
+    EXPECT_EQ(test_subnets_[3]->toElement()->str(), subnets[1]->toElement()->str());
+}
+
 // Test that shared network can be inserted, fetched, updated and then
 // fetched again.
 TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4) {
index c0ae4eabb4f63455998b7fc6ad0db92eb91f8bf9..8e25920cac7a09521e48a26619700e7f9896f05f 100644 (file)
@@ -57,6 +57,16 @@ public:
     virtual Subnet4Collection
     getAllSubnets4(const db::ServerSelector& server_selector) const = 0;
 
+    /// @brief Retrieves all subnets belonging to a specified shared network.
+    ///
+    /// @param server_selector Server selector.
+    /// @param shared_network_name Name of the shared network for which the
+    /// subnets should be retrieved.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+                             const std::string& shared_network_name) const = 0;
+
     /// @brief Retrieves subnets modified after specified time.
     ///
     /// @param server_selector Server selector.
index 5b24b5004179ed5c530cb7b2c9b133d3f7fd1601..95b55309b86ded22500e37a1c3c15979eb1d5862 100644 (file)
@@ -57,6 +57,17 @@ ConfigBackendPoolDHCPv4::getModifiedSubnets4(const BackendSelector& backend_sele
     return (subnets);
 }
 
+Subnet4Collection
+ConfigBackendPoolDHCPv4::getSharedNetworkSubnets4(const db::BackendSelector& backend_selector,
+                                                  const db::ServerSelector& server_selector,
+                                                  const std::string& shared_network_name) const {
+    Subnet4Collection subnets;
+    getMultiplePropertiesConst<Subnet4Collection, const std::string&>
+        (&ConfigBackendDHCPv4::getSharedNetworkSubnets4, backend_selector, server_selector,
+         subnets, shared_network_name);
+    return (subnets);
+}
+
 SharedNetwork4Ptr
 ConfigBackendPoolDHCPv4::getSharedNetwork4(const BackendSelector& backend_selector,
                                            const ServerSelector& server_selector,
index b2ea5dd585ed252ad8670fe3d27be0c718273c87..70e78342fae81521c5678e94ab24adda615deb7a 100644 (file)
@@ -72,6 +72,18 @@ public:
                         const db::ServerSelector& server_selector,
                         const boost::posix_time::ptime& modification_time) const;
 
+    /// @brief Retrieves all subnets belonging to a specified shared network.
+    ///
+    /// @param backend_selector Backend selector.
+    /// @param server_selector Server selector.
+    /// @param shared_network_name Name of the shared network for which the
+    /// subnets should be retrieved.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getSharedNetworkSubnets4(const db::BackendSelector& backend_selector,
+                             const db::ServerSelector& server_selector,
+                             const std::string& shared_network_name) const;
+
     /// @brief Retrieves shared network by name.
     ///
     /// @param backend_selector Backend selector.
index 05610dff35e885501d67abc36276fdf5e818abbc..e06bec8f96e40cc9b468a7a07d64d93a5c866323 100644 (file)
@@ -66,6 +66,31 @@ TestConfigBackendDHCPv4::getModifiedSubnets4(const db::ServerSelector& /* server
     return (subnets);
 }
 
+Subnet4Collection
+TestConfigBackendDHCPv4::getSharedNetworkSubnets4(const db::ServerSelector& /* server_selector */,
+                                                  const std::string& shared_network_name) const {
+    Subnet4Collection subnets;
+
+    // Subnet collection does not include the index by shared network name.
+    // We need to iterate over the subnets and pick those that are associated
+    // with a shared network.
+    for (auto subnet = subnets_.begin(); subnet != subnets_.end();
+         ++subnet) {
+        // The subnet can be associated with a shared network instance or
+        // it may just point to the shared network name. The former is
+        // the case when the subnet belongs to the server configuration.
+        // The latter is the case when the subnet is fetched from the
+        // database.
+        SharedNetwork4Ptr network;
+        (*subnet)->getSharedNetwork(network);
+        if (((network && (network->getName() == shared_network_name)) ||
+             ((*subnet)->getSharedNetworkName() == shared_network_name))) {
+            subnets.push_back(*subnet);
+        }
+    }
+    return (subnets);
+}
+
 SharedNetwork4Ptr
 TestConfigBackendDHCPv4::getSharedNetwork4(const db::ServerSelector& /* server_selector */,
                                            const std::string& name) const {
index 03aaa96afcbc54fd9b465b4b77a71172af6f18f7..08ed47b0bf2e113bdd2e61554d5246d734d7e9ef 100644 (file)
@@ -90,6 +90,16 @@ public:
     getModifiedSubnets4(const db::ServerSelector& server_selector,
                         const boost::posix_time::ptime& modification_time) const;
 
+    /// @brief Retrieves all subnets belonging to a specified shared network.
+    ///
+    /// @param server_selector Server selector.
+    /// @param shared_network_name Name of the shared network for which the
+    /// subnets should be retrieved.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+                             const std::string& shared_network_name) const;
+
     /// @brief Retrieves shared network by name.
     ///
     /// @param server_selector Server selector.