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
--- /dev/null
+// 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
+++ /dev/null
-// 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
+++ /dev/null
-// 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
+++ /dev/null
-// 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
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#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 <string>
};
+/// @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.
///
/// Specialization of the @ref SharedNetwork class for IPv4 subnets.
/// @brief Collection of IPv4 subnets within shared network.
Subnet4Collection subnets_;
-
};
/// @brief Pointer to @ref SharedNetwork4 object.
typedef boost::shared_ptr<SharedNetwork4> SharedNetwork4Ptr;
+/// @brief A collection of @ref SharedNetwork4 objects.
+typedef SharedNetworkCollection<SharedNetwork4> SharedNetwork4Collection;
+
/// @brief Shared network holding IPv6 subnets.
///
/// Specialization of the @ref SharedNetwork class for IPv6 subnets.
/// @brief Pointer to @ref SharedNetwork6 object.
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
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
--- /dev/null
+// 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
--- /dev/null
+// 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