From: Marcin Siodelski Date: Fri, 1 Sep 2017 11:05:06 +0000 (+0200) Subject: [5305] Implemented CfgSharedNetworks class. X-Git-Tag: trac5073a_base~11^2~12 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=c98545fa0f1763ab6846e9cf8d9c8996bace6b9f;p=thirdparty%2Fkea.git [5305] Implemented CfgSharedNetworks class. --- diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 84b4892543..32a6532cd9 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -102,8 +102,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_host_operations.cc cfg_host_operations.h libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h libkea_dhcpsrv_la_SOURCES += cfg_rsoo.cc cfg_rsoo.h -libkea_dhcpsrv_la_SOURCES += cfg_shared_networks4.cc cfg_shared_networks4.h -libkea_dhcpsrv_la_SOURCES += cfg_shared_networks6.h +libkea_dhcpsrv_la_SOURCES += cfg_shared_networks.h libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h diff --git a/src/lib/dhcpsrv/cfg_shared_networks.h b/src/lib/dhcpsrv/cfg_shared_networks.h new file mode 100644 index 0000000000..a15af93e6a --- /dev/null +++ b/src/lib/dhcpsrv/cfg_shared_networks.h @@ -0,0 +1,124 @@ +// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef CFG_SHARED_NETWORKS_H +#define CFG_SHARED_NETWORKS_H + +#include +#include +#include +#include +#include +#include + +namespace isc { +namespace dhcp { + +/// @brief This class holds configuration of shared networks. +/// +/// This is a generic class implementing basic functions such as shared network +/// addition, removal and retrieval. It also dumps configuration in the JSON +/// format. +/// +/// There are specializations of this class implemented as +/// @ref CfgSharedNetworks4 and @ref CfgSharedNetworks6 for IPv4 and IPv6 cases +/// repspectively. +/// +/// @tparam Type of the pointer to a shared network, i.e. @ref SharedNetwork4Ptr +/// or @ref SharedNetwork6Ptr. +template +class CfgSharedNetworks : public data::CfgToElement { +public: + + /// @brief Adds new shared network to the configuration. + /// + /// @param network Pointer to a network + /// + /// @throw isc::BadValue when name is a duplicate of existing network's + /// name. + void add(const SharedNetworkPtrType& network) { + if (getByName(network->getName())) { + isc_throw(BadValue, "duplicate network '" << network->getName() << + "' found in the configuration"); + } + + networks_.push_back(network); + } + + /// @brief Deletes shared network from the configuration. + /// + /// @param name Name of the network to be deleted. + /// + /// @throw isc::BadValue if the network can't be found. + void del(const std::string& name) { + auto& index = networks_.template get(); + auto shared_network = index.find(name); + if (shared_network != index.end()) { + index.erase(shared_network); + + } else { + isc_throw(BadValue, "unable to delete non-existing network '" + << name << "' from shared networks configuration"); + } + } + + /// @brief Retrieves shared network by name. + /// + /// @param name Name of the network to be retrieved. + /// + /// @return Pointer to the shared network or null pointer if the network + /// is not found. + SharedNetworkPtrType getByName(const std::string& name) const { + const auto& index = networks_.template get(); + auto shared_network = index.find(name); + if (shared_network != index.cend()) { + return (*shared_network); + } + return (SharedNetworkPtrType()); + } + + /// @brief Unparses shared networks configuration. + /// + /// @return Element object representing a list of shared networks held + /// within configuration. The networks are sorted by their names. + virtual data::ElementPtr toElement() const { + data::ElementPtr list = data::Element::createList(); + + // Insert shared networks sorted by their names into the list. + const auto& index = networks_.template get(); + for (auto shared_network = index.begin(); shared_network != index.end(); + ++shared_network) { + list->add((*shared_network)->toElement()); + } + return (list); + } + +protected: + + /// @brief Multi index container holding shared networks. + SharedNetworkCollection + networks_; +}; + +/// @brief Represents configuration of IPv4 shared networks. +class CfgSharedNetworks4 : public CfgSharedNetworks { +}; + +/// @brief Pointer to the configuration of IPv4 shared networks. +typedef boost::shared_ptr CfgSharedNetworks4Ptr; + +/// @brief Represents configuration of IPv6 shared networks. +class CfgSharedNetworks6 : public CfgSharedNetworks { +}; + +/// @brief Pointer to the configuration of IPv6 shared networks. +typedef boost::shared_ptr CfgSharedNetworks6Ptr; + + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif // CFG_SHARED_NETWORKS_H diff --git a/src/lib/dhcpsrv/cfg_shared_networks4.cc b/src/lib/dhcpsrv/cfg_shared_networks4.cc deleted file mode 100644 index 792fe2047a..0000000000 --- a/src/lib/dhcpsrv/cfg_shared_networks4.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include - -namespace isc { -namespace dhcp { - -void -CfgSharedNetworks4::add(const SharedNetwork4Ptr& network) { -} - -} // end of namespace isc::dhcp -} // end of namespace isc diff --git a/src/lib/dhcpsrv/cfg_shared_networks4.h b/src/lib/dhcpsrv/cfg_shared_networks4.h deleted file mode 100644 index 76805da5e9..0000000000 --- a/src/lib/dhcpsrv/cfg_shared_networks4.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef CFG_SHARED_NETWORKS4_H -#define CFG_SHARED_NETWORKS4_H - -#include -#include -#include - -namespace isc { -namespace dhcp { - -class CfgSharedNetworks4 : public data::CfgToElement { -public: - - void add(const SharedNetwork4Ptr& shared_network); - -}; - -typedef boost::shared_ptr CfgSharedNetworks4Ptr; - -} // end of namespace isc::dhcp -} // end of namespace isc - -#endif // CFG_SHARED_NETWORKS4_H diff --git a/src/lib/dhcpsrv/cfg_shared_networks6.h b/src/lib/dhcpsrv/cfg_shared_networks6.h deleted file mode 100644 index daf4952bf2..0000000000 --- a/src/lib/dhcpsrv/cfg_shared_networks6.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef CFG_SHARED_NETWORKS6_H -#define CFG_SHARED_NETWORKS6_H - -#include -#include - -namespace isc { -namespace dhcp { - -class CfgSharedNetworks6 : public data::CfgToElement { -public: - -}; - -typedef boost::shared_ptr CfgSharedNetworks6Ptr; - -} // end of namespace isc::dhcp -} // end of namespace isc - -#endif // CFG_SHARED_NETWORKS6_H diff --git a/src/lib/dhcpsrv/shared_network.h b/src/lib/dhcpsrv/shared_network.h index 3fab2fc4f9..67fb3705a0 100644 --- a/src/lib/dhcpsrv/shared_network.h +++ b/src/lib/dhcpsrv/shared_network.h @@ -13,6 +13,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -256,6 +261,39 @@ protected: }; +/// @brief A tag for accessing random access index. +struct SharedNetworkRandomAccessIndexTag { }; + +/// @brief A tag for accessing index by shared network name. +struct SharedNetworkNameIndexTag { }; + +/// @brief Multi index container holding shared networks. +/// +/// This is multi index container can hold pointers to @ref SharedNetwork4 +/// or @ref SharedNetwork6 objects. It provides indexes for shared network +/// lookups using properties such as shared network's name. +/// +/// @tparam SharedNetworkType Type of the shared network: @ref SharedNetwork4 +/// or @ref SharedNetwork6. +template +using SharedNetworkCollection = boost::multi_index_container< + // Multi index container holds pointers to the shared networks. + boost::shared_ptr, + boost::multi_index::indexed_by< + // First is the random access index allowing for accessing objects + // just like we'd do with vector. + boost::multi_index::random_access< + boost::multi_index::tag + >, + // Second index allows for access by shared network's name. + boost::multi_index::ordered_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun + > + > +>; + /// @brief Shared network holding IPv4 subnets. /// /// Specialization of the @ref SharedNetwork class for IPv4 subnets. @@ -335,12 +373,14 @@ private: /// @brief Collection of IPv4 subnets within shared network. Subnet4Collection subnets_; - }; /// @brief Pointer to @ref SharedNetwork4 object. typedef boost::shared_ptr SharedNetwork4Ptr; +/// @brief A collection of @ref SharedNetwork4 objects. +typedef SharedNetworkCollection SharedNetwork4Collection; + /// @brief Shared network holding IPv6 subnets. /// /// Specialization of the @ref SharedNetwork class for IPv6 subnets. @@ -425,6 +465,9 @@ private: /// @brief Pointer to @ref SharedNetwork6 object. typedef boost::shared_ptr SharedNetwork6Ptr; +/// @brief A collection of @ref SharedNetwork6 objects. +typedef SharedNetworkCollection SharedNetwork6Collection; + } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 0b68e8d2e7..6702cafc8a 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -74,6 +74,8 @@ libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_rsoo_unittest.cc +libdhcpsrv_unittests_SOURCES += cfg_shared_networks4_unittest.cc +libdhcpsrv_unittests_SOURCES += cfg_shared_networks6_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_subnets4_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_subnets6_unittest.cc libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc new file mode 100644 index 0000000000..47f5d553be --- /dev/null +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc @@ -0,0 +1,99 @@ +// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include + +using namespace isc; +using namespace isc::dhcp; + +namespace { + +// This test verifies that shared networks can be added to the configruation +// and retrieved by name. +TEST(CfgSharedNetworks4Test, getByName) { + SharedNetwork4Ptr network1(new SharedNetwork4("frog")); + SharedNetwork4Ptr network2(new SharedNetwork4("dog")); + + CfgSharedNetworks4 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + SharedNetwork4Ptr returned_network1 = cfg.getByName("frog"); + ASSERT_TRUE(returned_network1); + SharedNetwork4Ptr returned_network2 = cfg.getByName("dog"); + ASSERT_TRUE(returned_network2); +} + +// This test verifies that it is possible to delete a network. +TEST(CfgSharedNetworks4Test, deleteByName) { + SharedNetwork4Ptr network1(new SharedNetwork4("frog")); + SharedNetwork4Ptr network2(new SharedNetwork4("dog")); + + // Add two networks to the configuration. + CfgSharedNetworks4 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + // Try to delete non-existing network. This should throw. + ASSERT_THROW(cfg.del("lion"), BadValue); + + // Delete network #1. + ASSERT_NO_THROW(cfg.del(network1->getName())); + ASSERT_FALSE(cfg.getByName(network1->getName())); + ASSERT_TRUE(cfg.getByName(network2->getName())); + + // Delete network #2. + ASSERT_NO_THROW(cfg.del(network2->getName())); + ASSERT_FALSE(cfg.getByName(network1->getName())); + ASSERT_FALSE(cfg.getByName(network2->getName())); +} + +// This test verifies that shared networks must have unique names. +TEST(CfgSharedNetworks4Test, duplicateName) { + SharedNetwork4Ptr network1(new SharedNetwork4("frog")); + SharedNetwork4Ptr network2(new SharedNetwork4("frog")); + + CfgSharedNetworks4 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_THROW(cfg.add(network2), BadValue); +} + +// This test verifies that unparsing shared networks returns valid structure. +TEST(CfgSharedNetworks4Test, unparse) { + SharedNetwork4Ptr network1(new SharedNetwork4("frog")); + SharedNetwork4Ptr network2(new SharedNetwork4("dog")); + + network1->setIface("eth0"); + network2->setIface("eth1"); + + CfgSharedNetworks4 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + std::string expected = + "[\n" + " {\n" + " \"interface\": \"eth1\",\n" + " \"name\": \"dog\",\n" + " \"option-data\": [ ],\n" + " \"subnet4\": [ ]\n" + " },\n" + " {\n" + " \"interface\": \"eth0\",\n" + " \"name\": \"frog\",\n" + " \"option-data\": [ ],\n" + " \"subnet4\": [ ]\n" + " }\n" + "]\n"; + + test::runToElementTest(expected, cfg); +} + +} // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc new file mode 100644 index 0000000000..45f3bdcdee --- /dev/null +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc @@ -0,0 +1,99 @@ +// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include + +using namespace isc; +using namespace isc::dhcp; + +namespace { + +// This test verifies that shared networks can be added to the configruation +// and retrieved by name. +TEST(CfgSharedNetworks6Test, getByName) { + SharedNetwork6Ptr network1(new SharedNetwork6("frog")); + SharedNetwork6Ptr network2(new SharedNetwork6("dog")); + + CfgSharedNetworks6 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + SharedNetwork6Ptr returned_network1 = cfg.getByName("frog"); + ASSERT_TRUE(returned_network1); + SharedNetwork6Ptr returned_network2 = cfg.getByName("dog"); + ASSERT_TRUE(returned_network2); +} + +// This test verifies that it is possible to delete a network. +TEST(CfgSharedNetworks6Test, deleteByName) { + SharedNetwork6Ptr network1(new SharedNetwork6("frog")); + SharedNetwork6Ptr network2(new SharedNetwork6("dog")); + + // Add two networks to the configuration. + CfgSharedNetworks6 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + // Try to delete non-existing network. This should throw. + ASSERT_THROW(cfg.del("lion"), BadValue); + + // Delete network #1. + ASSERT_NO_THROW(cfg.del(network1->getName())); + ASSERT_FALSE(cfg.getByName(network1->getName())); + ASSERT_TRUE(cfg.getByName(network2->getName())); + + // Delete network #2. + ASSERT_NO_THROW(cfg.del(network2->getName())); + ASSERT_FALSE(cfg.getByName(network1->getName())); + ASSERT_FALSE(cfg.getByName(network2->getName())); +} + +// This test verifies that shared networks must have unique names. +TEST(CfgSharedNetworks6Test, duplicateName) { + SharedNetwork6Ptr network1(new SharedNetwork6("frog")); + SharedNetwork6Ptr network2(new SharedNetwork6("frog")); + + CfgSharedNetworks6 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_THROW(cfg.add(network2), BadValue); +} + +// This test verifies that unparsing shared networks returns valid structure. +TEST(CfgSharedNetworks6Test, unparse) { + SharedNetwork6Ptr network1(new SharedNetwork6("frog")); + SharedNetwork6Ptr network2(new SharedNetwork6("dog")); + + network1->setIface("eth0"); + network2->setIface("eth1"); + + CfgSharedNetworks6 cfg; + ASSERT_NO_THROW(cfg.add(network1)); + ASSERT_NO_THROW(cfg.add(network2)); + + std::string expected = + "[\n" + " {\n" + " \"interface\": \"eth1\",\n" + " \"name\": \"dog\",\n" + " \"option-data\": [ ],\n" + " \"subnet6\": [ ]\n" + " },\n" + " {\n" + " \"interface\": \"eth0\",\n" + " \"name\": \"frog\",\n" + " \"option-data\": [ ],\n" + " \"subnet6\": [ ]\n" + " }\n" + "]\n"; + + test::runToElementTest(expected, cfg); +} + +} // end of anonymous namespace