From: Marcin Siodelski Date: Wed, 9 Jan 2013 08:01:53 +0000 (+0100) Subject: [master] Merge branch 'trac2313' X-Git-Tag: bind10-1.0.0-rc-release~95^2~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=37a27e19be874725ea3d560065e5591a845daa89;p=thirdparty%2Fkea.git [master] Merge branch 'trac2313' Conflicts: src/lib/dhcpsrv/cfgmgr.cc src/lib/dhcpsrv/cfgmgr.h --- 37a27e19be874725ea3d560065e5591a845daa89 diff --cc src/lib/dhcpsrv/cfgmgr.cc index ce28575537,beb2df2157..26ee978b1d --- a/src/lib/dhcpsrv/cfgmgr.cc +++ b/src/lib/dhcpsrv/cfgmgr.cc @@@ -29,84 -27,36 +29,114 @@@ CfgMgr::instance() 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(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(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) { diff --cc src/lib/dhcpsrv/cfgmgr.h index 9628f24225,523cd101fd..c1f1dd6e6a --- a/src/lib/dhcpsrv/cfgmgr.h +++ b/src/lib/dhcpsrv/cfgmgr.h @@@ -17,7 -17,7 +17,8 @@@ #include #include +#include + #include #include #include #include @@@ -65,7 -65,7 +66,6 @@@ namespace dhcp /// 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 @@@ -78,41 -78,36 +78,71 @@@ public /// 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 @@@ -218,18 -201,11 +248,24 @@@ protected /// 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 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 diff --cc src/lib/dhcpsrv/tests/cfgmgr_unittest.cc index 7f73ee399a,7d3d9caa71..ab1d5864d4 --- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc @@@ -272,13 -104,78 +272,79 @@@ TEST_F(CfgMgrTest, subnet6) 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