Browse Source

[5305] Implemented CfgSharedNetworks class.

Marcin Siodelski 7 years ago
parent
commit
c98545fa0f

+ 1 - 2
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.cc cfg_option.h
 libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.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_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_subnets4.cc cfg_subnets4.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
 libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
 libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h

+ 124 - 0
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 <cc/cfg_to_element.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/shared_network.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+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<typename SharedNetworkPtrType>
+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<SharedNetworkNameIndexTag>();
+        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<SharedNetworkNameIndexTag>();
+        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<SharedNetworkNameIndexTag>();
+        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<typename SharedNetworkPtrType::element_type>
+    networks_;
+};
+
+/// @brief Represents configuration of IPv4 shared networks.
+class CfgSharedNetworks4 : public CfgSharedNetworks<SharedNetwork4Ptr> {
+};
+
+/// @brief Pointer to the configuration of IPv4 shared networks.
+typedef boost::shared_ptr<CfgSharedNetworks4> CfgSharedNetworks4Ptr;
+
+/// @brief Represents configuration of IPv6 shared networks.
+class CfgSharedNetworks6 : public CfgSharedNetworks<SharedNetwork6Ptr> {
+};
+
+/// @brief Pointer to the configuration of IPv6 shared networks.
+typedef boost::shared_ptr<CfgSharedNetworks6> CfgSharedNetworks6Ptr;
+
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif // CFG_SHARED_NETWORKS_H

+ 0 - 17
src/lib/dhcpsrv/cfg_shared_networks4.cc

@@ -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 <dhcpsrv/cfg_shared_networks4.h>
-
-namespace isc {
-namespace dhcp {
-
-void
-CfgSharedNetworks4::add(const SharedNetwork4Ptr& network) {
-}
-
-} // end of namespace isc::dhcp
-} // end of namespace isc

+ 0 - 29
src/lib/dhcpsrv/cfg_shared_networks4.h

@@ -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 <cc/cfg_to_element.h>
-#include <dhcpsrv/shared_network.h>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dhcp {
-
-class CfgSharedNetworks4 : public data::CfgToElement {
-public:
-
-    void add(const SharedNetwork4Ptr& shared_network);
-
-};
-
-typedef boost::shared_ptr<CfgSharedNetworks4> CfgSharedNetworks4Ptr;
-
-} // end of namespace isc::dhcp
-} // end of namespace isc
-
-#endif // CFG_SHARED_NETWORKS4_H

+ 0 - 26
src/lib/dhcpsrv/cfg_shared_networks6.h

@@ -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 <cc/cfg_to_element.h>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dhcp {
-
-class CfgSharedNetworks6 : public data::CfgToElement {
-public:
-
-};
-
-typedef boost::shared_ptr<CfgSharedNetworks6> CfgSharedNetworks6Ptr;
-
-} // end of namespace isc::dhcp
-} // end of namespace isc
-
-#endif // CFG_SHARED_NETWORKS6_H

+ 44 - 1
src/lib/dhcpsrv/shared_network.h

@@ -13,6 +13,11 @@
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet_id.h>
 #include <dhcpsrv/subnet_id.h>
 #include <boost/enable_shared_from_this.hpp>
 #include <boost/enable_shared_from_this.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/indexed_by.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/random_access_index.hpp>
+#include <boost/multi_index_container.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 #include <string>
 #include <string>
 
 
@@ -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<typename SharedNetworkType>
+using SharedNetworkCollection = boost::multi_index_container<
+    // Multi index container holds pointers to the shared networks.
+    boost::shared_ptr<SharedNetworkType>,
+    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<SharedNetworkRandomAccessIndexTag>
+        >,
+        // Second index allows for access by shared network's name.
+        boost::multi_index::ordered_unique<
+            boost::multi_index::tag<SharedNetworkNameIndexTag>,
+            boost::multi_index::const_mem_fun<SharedNetwork, std::string,
+                                              &SharedNetwork::getName>
+        >
+    >
+>;
+
 /// @brief Shared network holding IPv4 subnets.
 /// @brief Shared network holding IPv4 subnets.
 ///
 ///
 /// Specialization of the @ref SharedNetwork class for IPv4 subnets.
 /// Specialization of the @ref SharedNetwork class for IPv4 subnets.
@@ -335,12 +373,14 @@ private:
 
 
     /// @brief Collection of IPv4 subnets within shared network.
     /// @brief Collection of IPv4 subnets within shared network.
     Subnet4Collection subnets_;
     Subnet4Collection subnets_;
-
 };
 };
 
 
 /// @brief Pointer to @ref SharedNetwork4 object.
 /// @brief Pointer to @ref SharedNetwork4 object.
 typedef boost::shared_ptr<SharedNetwork4> SharedNetwork4Ptr;
 typedef boost::shared_ptr<SharedNetwork4> SharedNetwork4Ptr;
 
 
+/// @brief A collection of @ref SharedNetwork4 objects.
+typedef SharedNetworkCollection<SharedNetwork4> SharedNetwork4Collection;
+
 /// @brief Shared network holding IPv6 subnets.
 /// @brief Shared network holding IPv6 subnets.
 ///
 ///
 /// Specialization of the @ref SharedNetwork class for IPv6 subnets.
 /// Specialization of the @ref SharedNetwork class for IPv6 subnets.
@@ -425,6 +465,9 @@ private:
 /// @brief Pointer to @ref SharedNetwork6 object.
 /// @brief Pointer to @ref SharedNetwork6 object.
 typedef boost::shared_ptr<SharedNetwork6> SharedNetwork6Ptr;
 typedef boost::shared_ptr<SharedNetwork6> SharedNetwork6Ptr;
 
 
+/// @brief A collection of @ref SharedNetwork6 objects.
+typedef SharedNetworkCollection<SharedNetwork6> SharedNetwork6Collection;
+
 } // end of namespace isc::dhcp
 } // end of namespace isc::dhcp
 } // end of namespace isc
 } // end of namespace isc
 
 

+ 2 - 0
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_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_rsoo_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_subnets4_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_subnets6_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_subnets6_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc

+ 99 - 0
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 <config.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/cfg_shared_networks.h>
+#include <testutils/test_to_element.h>
+#include <gtest/gtest.h>
+
+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<CfgSharedNetworks4>(expected, cfg);
+}
+
+} // end of anonymous namespace

+ 99 - 0
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 <config.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/cfg_shared_networks.h>
+#include <testutils/test_to_element.h>
+#include <gtest/gtest.h>
+
+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<CfgSharedNetworks6>(expected, cfg);
+}
+
+} // end of anonymous namespace