Commit c6981a0e authored by Marcin Siodelski's avatar Marcin Siodelski

[2315] Added storage for option definitions.

parent 0fe0d44a
// 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
......@@ -42,6 +42,14 @@ public:
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
......@@ -21,15 +21,54 @@ using namespace isc::util;
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) {
......@@ -101,6 +140,10 @@ void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
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
......@@ -17,6 +17,7 @@
#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>
......@@ -77,6 +78,34 @@ public:
/// 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
......@@ -86,6 +115,8 @@ public:
/// (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
......@@ -93,12 +124,19 @@ public:
/// 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
......@@ -125,6 +163,8 @@ public:
/// (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
......@@ -169,6 +209,11 @@ protected:
/// 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
......
......@@ -43,9 +43,118 @@ public:
~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
......@@ -79,7 +188,6 @@ TEST_F(CfgMgrTest, subnet4) {
// This test verifies if the configuration manager is able to hold and return
// valid leases
TEST_F(CfgMgrTest, subnet6) {
CfgMgr& cfg_mgr = CfgMgr::instance();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment