-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
isc::Exception(file, line, what) { };
};
+/// @brief Exception to be thrown when the particular option definition
+/// duplicates existing option definition.
+class DuplicateOptionDefinition : public Exception {
+public:
+ DuplicateOptionDefinition(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
/// @brief Forward declaration to OptionDefinition.
class OptionDefinition;
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
namespace isc {
namespace dhcp {
-
-
-
CfgMgr&
CfgMgr::instance() {
static CfgMgr cfg_mgr;
return (cfg_mgr);
}
+void
+CfgMgr::addOptionDef(const OptionDefinitionPtr& def,
+ const std::string& option_space) {
+ // @todo we need better validation of the provided option space name here.
+ // This will be implemented when #2313 is merged.
+ if (option_space.empty()) {
+ isc_throw(BadValue, "option space name must not be empty");
+ } else if (!def) {
+ isc_throw(MalformedOptionDefinition, "option definition must not be NULL");
+ } else if (getOptionDef(option_space, def->getCode())) {
+ isc_throw(DuplicateOptionDefinition, "option definition already added"
+ << " to option space " << option_space);
+ }
+ option_def_spaces_[option_space].push_back(def);
+}
+
+const OptionDefContainer&
+CfgMgr::getOptionDefs(const std::string& option_space) const {
+ const std::map<std::string, OptionDefContainer>::const_iterator& defs =
+ option_def_spaces_.find(option_space);
+ if (defs == option_def_spaces_.end()) {
+ static OptionDefContainer empty_container;
+ return (empty_container);
+ }
+ return (defs->second);
+}
+
+OptionDefinitionPtr
+CfgMgr::getOptionDef(const std::string& option_space,
+ const uint16_t option_code) const {
+ const OptionDefContainer& defs = getOptionDefs(option_space);
+ if (defs.empty()) {
+ return (OptionDefinitionPtr());
+ }
+ const OptionDefContainerTypeIndex& idx = defs.get<1>();
+ const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+ if (std::distance(range.first, range.second) == 0) {
+ return (OptionDefinitionPtr());
+ }
+ return (*range.first);
+}
+
Subnet6Ptr
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
subnets4_.push_back(subnet);
}
+void CfgMgr::deleteOptionDefs() {
+ option_def_spaces_.clear();
+}
+
void CfgMgr::deleteSubnets4() {
subnets4_.clear();
}
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
#include <util/buffer.h>
/// accessing it.
static CfgMgr& instance();
+ /// @brief Add new option definition.
+ ///
+ /// @param def option definition to be added.
+ ///
+ /// @throw isc::dhcp::DuplicateOptionDefinition when the particular
+ /// option definition already exists.
+ void addOptionDef(const OptionDefinitionPtr& def,
+ const std::string& option_space);
+
+ /// @brief Return option definitions for particular option space.
+ ///
+ /// @param option_space option space.
+ ///
+ /// @return collection of option definitions for a particular
+ /// option space.
+ const OptionDefContainer&
+ getOptionDefs(const std::string& option_space) const;
+
+ /// @brief Return option definition for a particular option space and code.
+ ///
+ /// @param option_space option space.
+ /// @param option_code option code.
+ ///
+ /// @return an option definition or NULL pointer if option definition
+ /// has not been found.
+ OptionDefinitionPtr getOptionDef(const std::string& option_space,
+ const uint16_t option_code) const;
+
/// @brief get IPv6 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
+ ///
+ /// @return a subnet object
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
/// @brief get IPv6 subnet by interface-id
/// Another possibility to find a subnet is based on interface-id.
///
/// @param interface_id content of interface-id option returned by a relay
+ ///
+ /// @return a subnet object
/// @todo This method is not currently supported.
Subnet6Ptr getSubnet6(OptionPtr interface_id);
/// @brief adds an IPv6 subnet
+ ///
+ /// @param subnet new subnet to be added.
void addSubnet6(const Subnet6Ptr& subnet);
+ /// @brief Delete all option definitions.
+ void deleteOptionDefs();
+
/// @todo: Add subnet6 removal routines. Currently it is not possible
/// to remove subnets. The only case where subnet6 removal would be
/// needed is a dynamic server reconfiguration - a use case that is not
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
+ ///
+ /// @return a subnet object
Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);
/// @brief adds a subnet4
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet4Collection subnets4_;
+
+private:
+
+ /// A map containing option definitions for different option spaces.
+ std::map<std::string, OptionDefContainer> option_def_spaces_;
};
} // namespace isc::dhcp
~CfgMgrTest() {
CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().deleteOptionDefs();
}
};
+// This test verifies that multiple option definitions can be added
+// under different option spaces.
+TEST_F(CfgMgrTest, getOptionDefs) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+ // Create a set of option definitions with codes between 100 and 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ std::ostringstream option_name;
+ // Option name is unique, e.g. option-100, option-101 etc.
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ // Add option definition to "isc" option space.
+ // Option codes are not duplicated so expect no error
+ // when adding them.
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
+ }
+
+ // Create a set of option definitions with codes between 105 and 114 and
+ // add them to the different option space.
+ for (uint16_t code = 105; code < 115; ++code) {
+ std::ostringstream option_name;
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
+ }
+
+ // Sanity check that all 10 option definitions are there.
+ const OptionDefContainer& option_defs1 = cfg_mgr.getOptionDefs("isc");
+ ASSERT_EQ(10, option_defs1.size());
+
+ // Iterate over all option definitions and check that they have
+ // valid codes. Also, their order should be the same as they
+ // were added (codes 100-109).
+ uint16_t code = 100;
+ for (OptionDefContainer::const_iterator it = option_defs1.begin();
+ it != option_defs1.end(); ++it, ++code) {
+ OptionDefinitionPtr def(*it);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Sanity check that all 10 option definitions are there.
+ const OptionDefContainer& option_defs2 = cfg_mgr.getOptionDefs("abcde");
+ ASSERT_EQ(10, option_defs2.size());
+
+ // Check that the option codes are valid.
+ code = 105;
+ for (OptionDefContainer::const_iterator it = option_defs2.begin();
+ it != option_defs2.end(); ++it, ++code) {
+ OptionDefinitionPtr def(*it);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Let's make one more check that the empty set is returned when
+ // invalid option space is used.
+ const OptionDefContainer& option_defs3 = cfg_mgr.getOptionDefs("non-existing");
+ ASSERT_TRUE(option_defs3.empty());
+}
+
+// This test verifies that single option definition is correctly
+// returned with getOptionDef function.
+TEST_F(CfgMgrTest, getOptionDef) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+ // Create a set of option definitions with codes between 100 and 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ std::ostringstream option_name;
+ // Option name is unique, e.g. option-100, option-101 etc.
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ // Add option definition to "isc" option space.
+ // Option codes are not duplicated so expect no error
+ // when adding them.
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
+ }
+
+ // Create a set of option definitions with codes between 105 and 114 and
+ // add them to the different option space.
+ for (uint16_t code = 105; code < 115; ++code) {
+ std::ostringstream option_name;
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
+ }
+
+ // Try to get option definitions one by one using all codes
+ // that we expect to be there.
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("isc", code);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Check that the option codes are valid.
+ for (uint16_t code = 105; code < 115; ++code) {
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("abcde", code);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Try to query the option definition from an non-existing
+ // option space and expect NULL pointer.
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("non-existing", 56);
+ ASSERT_FALSE(def);
+}
// This test verifies if the configuration manager is able to hold and return
// valid leases
// This test verifies if the configuration manager is able to hold and return
// valid leases
-
TEST_F(CfgMgrTest, subnet6) {
CfgMgr& cfg_mgr = CfgMgr::instance();