From: Marcin Siodelski Date: Mon, 29 Oct 2012 11:53:17 +0000 (+0100) Subject: [2318] Implemented global options configuration. X-Git-Tag: trac2487_base~28^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3271dcc47f185103c208585d1df8a92e50274f7a;p=thirdparty%2Fkea.git [2318] Implemented global options configuration. --- diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc index 490d8c060b..9285105d3c 100644 --- a/src/bin/dhcp6/config_parser.cc +++ b/src/bin/dhcp6/config_parser.cc @@ -61,6 +61,7 @@ typedef std::map StringStorage; /// no subnet object created yet to store them. typedef std::vector PoolStorage; +/// @brief Collection of options. typedef std::vector OptionStorage; /// @brief Global uint32 parameters that will be used as defaults. @@ -69,6 +70,9 @@ Uint32Storage uint32_defaults; /// @brief global string parameters that will be used as defaults. StringStorage string_defaults; +/// @brief Global storage for options that will be used as defaults. +OptionStorage option_defaults; + /// @brief a dummy configuration parser /// /// It is a debugging parser. It does not configure anything, @@ -652,7 +656,8 @@ class OptionDataListParser : public DhcpConfigParser { public: /// @brief Constructor. - OptionDataListParser(const std::string&) { } + OptionDataListParser(const std::string&) + : options_(&option_defaults) { } /// @brief Parses entries that define options' data for a subnet. /// @@ -798,10 +803,36 @@ public: subnet->addPool6(*it); } + // Add subnet specific options. BOOST_FOREACH(OptionPtr option, options_) { subnet->addOption(option); } + // Get all options that we have added to subnet so far. We will + // use them to check which of the global options must be added to + // the subnet. + Subnet::OptionContainer options = subnet->getOptions(); + // Get the search index #1 which is used to search options + // by their code (type). + Subnet::OptionContainerTypeIndex& idx = options.get<1>(); + // Check all global options and add them to the subnet object if + // they have been configured in the global scope. If they have been + // configured in the subnet scope we don't add global option because + // the one configured in the subnet scope always takes precedense. + BOOST_FOREACH(OptionPtr option, option_defaults) { + // Get local option descriptors using global option code. + std::pair range = + idx.equal_range(option->getType()); + // @todo: In the future we will be searching for options using either + // option code or namespace. Currently we have only the option + // code available so if there is at least one option found with the + // specific code we don't add globally configured option. + if (std::distance(range.first, range.second) == 0) { + subnet->addOption(option); + } + } + CfgMgr::instance().addSubnet6(subnet); } @@ -981,6 +1012,9 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) { factories.insert(pair( "subnet6", Subnets6ListConfigParser::Factory)); + factories.insert(pair( + "option-data", OptionDataListParser::Factory)); + factories.insert(pair( "version", StringParser::Factory)); @@ -1017,6 +1051,12 @@ configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) { "Null pointer is passed to configuration parser"); } + /// Reset global storage. Containers being reset below may contain + /// data from the previous configuration attempts. + option_defaults.clear(); + uint32_defaults.clear(); + string_defaults.clear(); + /// @todo: append most essential info here (like "2 new subnets configured") string config_details; diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 02ca20cd90..54389fb405 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -336,12 +336,77 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) { EXPECT_EQ(4000, subnet->getValid()); } +TEST_F(Dhcp6ParserTest, optionDataDefaults) { + ConstElementPtr x; + string config = "{ \"interface\": [ \"all\" ]," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000," + "\"renew-timer\": 1000," + "\"option-data\": [ {" + " \"name\": \"option_foo\"," + " \"code\": 100," + " \"data\": \"AB CDEF0105\"" + " }," + " {" + " \"name\": \"option_foo2\"," + " \"code\": 101," + " \"data\": \"01\"" + " } ]," + "\"subnet6\": [ { " + " \"pool\": [ \"2001:db8:1::/80\" ]," + " \"subnet\": \"2001:db8:1::/64\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json)); + ASSERT_TRUE(x); + comment_ = parseAnswer(rcode_, x); + ASSERT_EQ(0, rcode_); + + Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5")); + ASSERT_TRUE(subnet); + const Subnet::OptionContainer& options = subnet->getOptions(); + ASSERT_EQ(2, options.size()); + + // Get the search index. Index #1 is to search using option code. + const Subnet::OptionContainerTypeIndex& idx = options.get<1>(); + + // Get the options for specified index. Expecting one option to be + // returned but in theory we may have multiple options with the same + // code so we get the range. + std::pair range = + idx.equal_range(100); + // Expect single option with the code equal to 100. + ASSERT_EQ(1, std::distance(range.first, range.second)); + const uint8_t foo_expected[] = { + 0xAB, 0xCD, 0xEF, 0x01, 0x05 + }; + // Check if option is valid in terms of code and carried data. + testOption(*range.first, 100, foo_expected, sizeof(foo_expected)); + + range = idx.equal_range(101); + ASSERT_EQ(1, std::distance(range.first, range.second)); + // Do another round of testing with second option. + const uint8_t foo2_expected[] = { + 0x01 + }; + testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected)); +} + TEST_F(Dhcp6ParserTest, optionDataInSingleSubnet) { ConstElementPtr x; string config = "{ \"interface\": [ \"all\" ]," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " + "\"option-data\": [ {" + " \"name\": \"option_foo\"," + " \"code\": 100," + " \"data\": \"AB\"" + " } ]," "\"subnet6\": [ { " " \"pool\": [ \"2001:db8:1::/80\" ]," " \"subnet\": \"2001:db8:1::/64\", "