return (cfg_mgr);
}
+ void
+ CfgMgr::addOptionSpace4(const OptionSpacePtr& space) {
+ if (!space) {
+ isc_throw(InvalidOptionSpace,
+ "provided option space object is NULL.");
+ }
+ OptionSpaceCollection::iterator it = spaces4_.find(space->getName());
+ if (it != spaces4_.end()) {
+ isc_throw(InvalidOptionSpace, "option space " << space->getName()
+ << " already added.");
+ }
+ spaces4_.insert(std::pair<std::string,
+ OptionSpacePtr>(space->getName(), space));
+ }
+
+ void
+ CfgMgr::addOptionSpace6(const OptionSpacePtr& space) {
+ if (!space) {
+ isc_throw(InvalidOptionSpace,
+ "provided option space object is NULL.");
+ }
+ OptionSpaceCollection::iterator it = spaces6_.find(space->getName());
+ if (it != spaces6_.end()) {
+ isc_throw(InvalidOptionSpace, "option space " << space->getName()
+ << " already added.");
+ }
+ spaces6_.insert(std::pair<std::string,
+ OptionSpacePtr>(space->getName(), space));
+ }
+
+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) {
+ // Option definition must point to a valid object.
+ isc_throw(MalformedOptionDefinition, "option definition must not be NULL");
+
+ } else if (getOptionDef(option_space, def->getCode())) {
+ // Option definition must not be overriden.
+ isc_throw(DuplicateOptionDefinition, "option definition already added"
+ << " to option space " << option_space);
+
+ } else if ((option_space == "dhcp4" &&
+ LibDHCP::isStandardOption(Option::V4, def->getCode())) ||
+ (option_space == "dhcp6" &&
+ LibDHCP::isStandardOption(Option::V6, def->getCode()))) {
+ // We must not override standard (assigned) option. The standard options
+ // belong to dhcp4 or dhcp6 option space.
+ isc_throw(BadValue, "unable to override definition of option '"
+ << def->getCode() << "' in standard option space '"
+ << option_space << "'.");
+
+ }
+ // Get existing option definitions for the option space.
+ OptionDefContainerPtr defs = getOptionDefs(option_space);
+ // getOptionDefs always returns a valid pointer to
+ // the container. Let's make an assert to make sure.
+ assert(defs);
+ // Actually add the new definition.
+ defs->push_back(def);
+ option_def_spaces_[option_space] = defs;
+}
+
+OptionDefContainerPtr
+CfgMgr::getOptionDefs(const std::string& option_space) const {
+ // @todo Validate the option space once the #2313 is implemented.
+
+ // Get all option definitions for the particular option space.
+ const OptionDefsMap::const_iterator& defs =
+ option_def_spaces_.find(option_space);
+ // If there are no option definitions for the particular option space
+ // then return empty container.
+ if (defs == option_def_spaces_.end()) {
+ return (OptionDefContainerPtr(new OptionDefContainer()));
+ }
+ // If option definitions found, return them.
+ return (defs->second);
+}
+
+OptionDefinitionPtr
+CfgMgr::getOptionDef(const std::string& option_space,
+ const uint16_t option_code) const {
+ // @todo Validate the option space once the #2313 is implemented.
+
+ // Get a reference to option definitions for a particular option space.
+ OptionDefContainerPtr defs = getOptionDefs(option_space);
+ // If there are no matching option definitions then return the empty pointer.
+ if (!defs || defs->empty()) {
+ return (OptionDefinitionPtr());
+ }
+ // If there are some option definitions for a particular option space
+ // use an option code to get the one we want.
+ const OptionDefContainerTypeIndex& idx = defs->get<1>();
+ const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+ // If there is no definition that matches option code, return empty pointer.
+ if (std::distance(range.first, range.second) == 0) {
+ return (OptionDefinitionPtr());
+ }
+ // If there is more than one definition matching an option code, return
+ // the first one. This should not happen because we check for duplicates
+ // when addOptionDef is called.
+ return (*range.first);
+}
+
Subnet6Ptr
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
+ #include <dhcpsrv/option_space.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
#include <util/buffer.h>
/// Parameter inheritance is likely to be implemented in configuration handling
/// routines, so there is no storage capability in a global scope for
/// subnet-specific parameters.
--///
/// @todo: Implement Subnet4 support (ticket #2237)
/// @todo: Implement option definition support
/// @todo: Implement parameter inheritance
/// accessing it.
static CfgMgr& instance();
+ /// @brief Add new option definition.
+ ///
+ /// @param def option definition to be added.
+ /// @param option_space name of the option space to add definition to.
+ ///
+ /// @throw isc::dhcp::DuplicateOptionDefinition when the particular
+ /// option definition already exists.
+ /// @throw isc::dhcp::MalformedOptionDefinition when the pointer to
+ /// an option definition is NULL.
+ /// @throw isc::BadValue when the option space name is empty or
+ /// when trying to override the standard option (in dhcp4 or dhcp6
+ /// option space).
+ void addOptionDef(const OptionDefinitionPtr& def,
+ const std::string& option_space);
+
+ /// @brief Return option definitions for particular option space.
+ ///
+ /// @param option_space option space.
+ ///
+ /// @return pointer to the collection of option definitions for
+ /// the particular option space. The option collection is empty
+ /// if no option exists for the option space specified.
+ OptionDefContainerPtr
+ 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 Adds new DHCPv4 option space to the collection.
+ ///
+ /// @param space option space to be added.
+ ///
+ /// @throw isc::dhcp::InvalidOptionSpace invalid option space
+ /// has been specified.
+ void addOptionSpace4(const OptionSpacePtr& space);
+
+ /// @brief Adds new DHCPv6 option space to the collection.
+ ///
+ /// @param space option space to be added.
+ ///
+ /// @throw isc::dhcp::InvalidOptionSpace invalid option space
+ /// has been specified.
+ void addOptionSpace6(const OptionSpacePtr& space);
+
+ /// @brief Return option spaces for DHCPv4.
+ ///
+ /// @return A collection of option spaces.
+ const OptionSpaceCollection& getOptionSpaces4() const {
+ return (spaces4_);
+ }
+
+ /// @brief Return option spaces for DHCPv6.
+ ///
+ /// @return A collection of option spaces.
+ const OptionSpaceCollection& getOptionSpaces6() const {
+ return (spaces6_);
+ }
+
/// @brief get IPv6 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// a match is found.
Subnet4Collection subnets4_;
+private:
+
+ /// A map containing option definitions for various option spaces.
+ /// They key of this map is the name of the option space. The
+ /// value is the the option container holding option definitions
+ /// for the particular option space.
+ typedef std::map<std::string, OptionDefContainerPtr> OptionDefsMap;
+
+ /// A map containing option definitions for different option spaces.
+ /// The map key holds an option space name.
+ OptionDefsMap option_def_spaces_;
+
+ /// @brief Container for defined DHCPv6 option spaces.
+ OptionSpaceCollection spaces6_;
+
+ /// @brief Container for defined DHCPv4 option spaces.
+ OptionSpaceCollection spaces4_;
++
};
} // namespace isc::dhcp
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
+ EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("5000::1")));
+ // Check that deletion of the subnets works.
cfg_mgr.deleteSubnets6();
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("200::123")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("3000::123")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("4000::123")));
+ EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("200::123")));
+ EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123")));
+ EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123")));
}
+ // This test verifies that new DHCPv4 option spaces can be added to
+ // the configuration manager and that duplicated option space is
+ // rejected.
+ TEST_F(CfgMgrTest, optionSpace4) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ // Create some option spaces.
+ OptionSpacePtr space1(new OptionSpace("isc", false));
+ OptionSpacePtr space2(new OptionSpace("xyz", true));
+
+ // Add option spaces with different names and expect they
+ // are accepted.
+ ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space1));
+ ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space2));
+
+ // Validate that the option spaces have been added correctly.
+ const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces4();
+
+ ASSERT_EQ(2, spaces.size());
+ EXPECT_FALSE(spaces.find("isc") == spaces.end());
+ EXPECT_FALSE(spaces.find("xyz") == spaces.end());
+
+ // Create another option space with the name that duplicates
+ // the existing option space.
+ OptionSpacePtr space3(new OptionSpace("isc", true));
+ // Expect that the duplicate option space is rejected.
+ ASSERT_THROW(
+ cfg_mgr.addOptionSpace4(space3), isc::dhcp::InvalidOptionSpace
+ );
+
+ // @todo decode if a duplicate vendor space is allowed.
+ }
+
+ // This test verifies that new DHCPv6 option spaces can be added to
+ // the configuration manager and that duplicated option space is
+ // rejected.
+ TEST_F(CfgMgrTest, optionSpace6) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ // Create some option spaces.
+ OptionSpacePtr space1(new OptionSpace("isc", false));
+ OptionSpacePtr space2(new OptionSpace("xyz", true));
+
+ // Add option spaces with different names and expect they
+ // are accepted.
+ ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space1));
+ ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space2));
+
+ // Validate that the option spaces have been added correctly.
+ const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces6();
+
+ ASSERT_EQ(2, spaces.size());
+ EXPECT_FALSE(spaces.find("isc") == spaces.end());
+ EXPECT_FALSE(spaces.find("xyz") == spaces.end());
+
+ // Create another option space with the name that duplicates
+ // the existing option space.
+ OptionSpacePtr space3(new OptionSpace("isc", true));
+ // Expect that the duplicate option space is rejected.
+ ASSERT_THROW(
+ cfg_mgr.addOptionSpace6(space3), isc::dhcp::InvalidOptionSpace
+ );
+
+ // @todo decide if a duplicate vendor space is allowed.
+ }
+
} // end of anonymous namespace