Browse Source

[5022] It is now possible to specify options for a prefix pool.

Marcin Siodelski 8 years ago
parent
commit
6cfae24d71

+ 11 - 1
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.

+ 104 - 0
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<Pool6>(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<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> 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<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> 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".

+ 2 - 2
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 {

+ 17 - 1
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 <asiolink/io_address.h>
 #include <boost/shared_ptr.hpp>
+#include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/lease.h>
 
 #include <vector>
@@ -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

+ 51 - 1
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