From: Marcin Siodelski Date: Mon, 3 Oct 2016 07:49:29 +0000 (+0200) Subject: [5022] It is now possible to specify options for a prefix pool. X-Git-Tag: trac4631a_base~3^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6cfae24d71ba92658ab8e0c5ce34cb9618ee1cb7;p=thirdparty%2Fkea.git [5022] It is now possible to specify options for a prefix pool. --- diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 4cf6bb6204..3f8ae624bb 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -151,7 +151,8 @@ public: /// upon "commit" PdPoolParser(const std::string&, PoolStoragePtr pools) : uint32_values_(new Uint32Storage()), - string_values_(new StringStorage()), pools_(pools) { + string_values_(new StringStorage()), pools_(pools), + options_(new CfgOption()) { if (!pools_) { isc_throw(isc::dhcp::DhcpConfigError, "PdPoolParser context storage may not be NULL"); @@ -180,6 +181,12 @@ public: Uint32ParserPtr code_parser(new Uint32Parser(entry, uint32_values_)); parser = code_parser; + } else if (entry == "option-data") { + OptionDataListParserPtr option_parser(new OptionDataListParser(entry, + options_, + AF_INET6)); + parser = option_parser; + } else { isc_throw(DhcpConfigError, "unsupported parameter: " << entry << " (" << param.second->getPosition() << ")"); @@ -229,6 +236,9 @@ protected: /// Pointer to storage to which the local pool is written upon commit. isc::dhcp::PoolStoragePtr pools_; + + /// A storage for pool specific option values. + CfgOptionPtr options_; }; /// @brief Parser for a list of prefix delegation pools. diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 6b38ea062b..f47de6d369 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -2556,6 +2556,110 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) { sizeof(user_class_expected)); } +TEST_F(Dhcp6ParserTest, optionDataInMultiplePools) { + ConstElementPtr x; + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"pools\": [ { " + " \"pool\": \"2001:db8:1::10 - 2001:db8:1::100\"" +/* " \"option-data\": [ {" + " \"name\": \"subscriber-id\"," + " \"data\": \"0102030405060708090A\"," + " \"csv-format\": False" + " } ]" */ + " }," + " {" + " \"pool\": \"2001:db8:1::300 - 2001:db8:1::400\"" +/* " \"option-data\": [ {" + " \"name\": \"user-class\"," + " \"data\": \"FFFEFDFCFB\"," + " \"csv-format\": False" + " } ]" */ + " } ]," + " \"pd-pools\": [ { " + " \"prefix\": \"3000::\"," + " \"prefix-len\": 48," + " \"delegated-len\": 64," + " \"option-data\": [ {" + " \"name\": \"subscriber-id\"," + " \"data\": \"112233445566\"," + " \"csv-format\": False" + " } ]" + " }," + " {" + " \"prefix\": \"3001::\"," + " \"prefix-len\": 48," + " \"delegated-len\": 64," + " \"option-data\": [ {" + " \"name\": \"user-class\"," + " \"data\": \"aabbccddee\"," + " \"csv-format\": False" + " } ]" + " } ]," + " \"subnet\": \"2001:db8:1::/64\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json)); + checkResult(x, 0); + + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> + selectSubnet(IOAddress("2001:db8:1::5"), classify_); + ASSERT_TRUE(subnet); + + PoolPtr pool = subnet->getPool(Lease::TYPE_PD, IOAddress("3000::"), false); + ASSERT_TRUE(pool); + Pool6Ptr pool6 = boost::dynamic_pointer_cast(pool); + + + OptionContainerPtr options1 = pool6->getCfgOption()->getAll("dhcp6"); + ASSERT_EQ(1, options1->size()); + + // Get the search index. Index #1 is to search using option code. + const OptionContainerTypeIndex& idx1 = options1->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 range1 = + idx1.equal_range(D6O_SUBSCRIBER_ID); + // Expect single option with the code equal to 38. + ASSERT_EQ(1, std::distance(range1.first, range1.second)); + const uint8_t subid_expected[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A + }; + // Check if option is valid in terms of code and carried data. + testOption(*range1.first, D6O_SUBSCRIBER_ID, subid_expected, + sizeof(subid_expected)); + +/* // Test another subnet in the same way. + Subnet6Ptr subnet2 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> + selectSubnet(IOAddress("2001:db8:2::4"), classify_); + ASSERT_TRUE(subnet2); + OptionContainerPtr options2 = subnet2->getCfgOption()->getAll("dhcp6"); + ASSERT_EQ(1, options2->size()); + + const OptionContainerTypeIndex& idx2 = options2->get<1>(); + std::pair range2 = + idx2.equal_range(D6O_USER_CLASS); + ASSERT_EQ(1, std::distance(range2.first, range2.second)); + + const uint8_t user_class_expected[] = { + 0xFF, 0xFE, 0xFD, 0xFC, 0xFB + }; + testOption(*range2.first, D6O_USER_CLASS, user_class_expected, + sizeof(user_class_expected)); */ + +} + // The goal of this test is to check that the option carrying a boolean // value can be configured using one of the values: "true", "false", "0" // or "1". diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc index fa89aac580..13d3c05d02 100644 --- a/src/lib/dhcpsrv/pool.cc +++ b/src/lib/dhcpsrv/pool.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -17,7 +17,7 @@ namespace dhcp { Pool::Pool(Lease::Type type, const isc::asiolink::IOAddress& first, const isc::asiolink::IOAddress& last) :id_(getNextID()), first_(first), last_(last), type_(type), - capacity_(0) { + capacity_(0), cfg_option_(new CfgOption()) { } bool Pool::inRange(const isc::asiolink::IOAddress& addr) const { diff --git a/src/lib/dhcpsrv/pool.h b/src/lib/dhcpsrv/pool.h index d5b26aa28f..6a9747f255 100644 --- a/src/lib/dhcpsrv/pool.h +++ b/src/lib/dhcpsrv/pool.h @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -79,6 +80,18 @@ public: uint64_t getCapacity() const { return (capacity_); } + + /// @brief Returns pointer to the option data configuration for this pool. + CfgOptionPtr getCfgOption() { + return (cfg_option_); + } + + /// @brief Returns const pointer to the option data configuration for + /// this pool. + ConstCfgOptionPtr getCfgOption() const { + return (cfg_option_); + } + protected: /// @brief protected constructor @@ -128,6 +141,9 @@ protected: /// the result. Note that for very large pools, the number is capped at /// max value of uint64_t. uint64_t capacity_; + + /// @brief Pointer to the option data configuration for this pool. + CfgOptionPtr cfg_option_; }; /// @brief Pool information for IPv4 addresses diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc index 3c61ecd236..72d31eb2c0 100644 --- a/src/lib/dhcpsrv/tests/pool_unittest.cc +++ b/src/lib/dhcpsrv/tests/pool_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -282,5 +282,55 @@ TEST(Pool6Test, leasesCount) { EXPECT_EQ(65536, pool2.getCapacity()); } +// This test checks that it is possible to specify pool specific options. +TEST(Pool6Test, addOptions) { + // Create a pool to add options to it. + Pool6Ptr pool(new Pool6(Lease::TYPE_PD, IOAddress("3000::"), 64, 128)); + + // Differentiate options by their codes (100-109) + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "dhcp6")); + } + + // Add 7 options to another option space. The option codes partially overlap + // with option codes that we have added to dhcp6 option space. + for (uint16_t code = 105; code < 112; ++code) { + OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc")); + } + + // Get options from the pool and check if all 10 are there. + OptionContainerPtr options = pool->getCfgOption()->getAll("dhcp6"); + ASSERT_TRUE(options); + ASSERT_EQ(10, options->size()); + + // Validate codes of options added to dhcp6 option space. + uint16_t expected_code = 100; + for (OptionContainer::const_iterator option_desc = options->begin(); + option_desc != options->end(); ++option_desc) { + ASSERT_TRUE(option_desc->option_); + EXPECT_EQ(expected_code, option_desc->option_->getType()); + ++expected_code; + } + + options = pool->getCfgOption()->getAll("isc"); + ASSERT_TRUE(options); + ASSERT_EQ(7, options->size()); + + // Validate codes of options added to isc option space. + expected_code = 105; + for (OptionContainer::const_iterator option_desc = options->begin(); + option_desc != options->end(); ++option_desc) { + ASSERT_TRUE(option_desc->option_); + EXPECT_EQ(expected_code, option_desc->option_->getType()); + ++expected_code; + } + + // Try to get options from a non-existing option space. + options = pool->getCfgOption()->getAll("abcd"); + ASSERT_TRUE(options); + EXPECT_TRUE(options->empty()); +} }; // end of anonymous namespace