From 0576737748183a1c8bb19364407704fb6bb8dbb8 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Mon, 4 Feb 2019 21:36:47 +0100 Subject: [PATCH] [#440,!218] Implemented getSharedNetworkSubnets4 for DHCPv4 CB. --- src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc | 62 ++++++++++++++++++- src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h | 10 +++ .../mysql_cb/tests/mysql_cb_dhcp4_unittest.cc | 49 +++++++++++++++ src/lib/dhcpsrv/config_backend_dhcp4.h | 10 +++ src/lib/dhcpsrv/config_backend_pool_dhcp4.cc | 11 ++++ src/lib/dhcpsrv/config_backend_pool_dhcp4.h | 12 ++++ .../testutils/test_config_backend_dhcp4.cc | 25 ++++++++ .../testutils/test_config_backend_dhcp4.h | 10 +++ 8 files changed, 186 insertions(+), 3 deletions(-) diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index 7a182eac88..d0a10910a1 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -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 { diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h index 16e5b4203d..f1ef0fb3df 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h @@ -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. diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc index 909a97338c..a8db9c3907 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc @@ -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) { diff --git a/src/lib/dhcpsrv/config_backend_dhcp4.h b/src/lib/dhcpsrv/config_backend_dhcp4.h index c0ae4eabb4..8e25920cac 100644 --- a/src/lib/dhcpsrv/config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/config_backend_dhcp4.h @@ -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. diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc b/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc index 5b24b50041..95b55309b8 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc @@ -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 + (&ConfigBackendDHCPv4::getSharedNetworkSubnets4, backend_selector, server_selector, + subnets, shared_network_name); + return (subnets); +} + SharedNetwork4Ptr ConfigBackendPoolDHCPv4::getSharedNetwork4(const BackendSelector& backend_selector, const ServerSelector& server_selector, diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp4.h b/src/lib/dhcpsrv/config_backend_pool_dhcp4.h index b2ea5dd585..70e78342fa 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp4.h +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp4.h @@ -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. diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc index 05610dff35..e06bec8f96 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc @@ -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 { diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h index 03aaa96afc..08ed47b0bf 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h @@ -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. -- 2.47.2