Browse Source

[3589] Created an object to hold the option configuration.

Marcin Siodelski 10 years ago
parent
commit
bbdef9791d

+ 4 - 4
src/bin/dhcp4/dhcp4_srv.cc

@@ -599,7 +599,7 @@ Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
     for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
          opt != requested_opts.end(); ++opt) {
         if (!msg->getOption(*opt)) {
-            Subnet::OptionDescriptor desc =
+            OptionDescriptor desc =
                 subnet->getOptionDescriptor("dhcp4", *opt);
             if (desc.option && !msg->getOption(*opt)) {
                 msg->addOption(desc.option);
@@ -650,7 +650,7 @@ Dhcpv4Srv::appendRequestedVendorOptions(const Pkt4Ptr& question, Pkt4Ptr& answer
     for (std::vector<uint8_t>::const_iterator code = requested_opts.begin();
          code != requested_opts.end(); ++code) {
         if  (!vendor_rsp->getOption(*code)) {
-            Subnet::OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id,
+            OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id,
                                                                               *code);
             if (desc.option) {
                 vendor_rsp->addOption(desc.option);
@@ -689,7 +689,7 @@ Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
         OptionPtr opt = msg->getOption(required_options[i]);
         if (!opt) {
             // Check whether option has been configured.
-            Subnet::OptionDescriptor desc =
+            OptionDescriptor desc =
                 subnet->getOptionDescriptor("dhcp4", required_options[i]);
             if (desc.option) {
                 msg->addOption(desc.option);
@@ -1949,7 +1949,7 @@ bool Dhcpv4Srv::classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp
 
         // Now try to set up file field in DHCPv4 packet. We will just copy
         // content of the boot-file option, which contains the same information.
-        Subnet::OptionDescriptor desc =
+        OptionDescriptor desc =
             subnet->getOptionDescriptor("dhcp4", DHO_BOOT_FILE_NAME);
 
         if (desc.option) {

+ 45 - 45
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -231,7 +231,7 @@ public:
     /// @return Descriptor of the option. If the descriptor holds a
     /// NULL option pointer, it means that there was no such option
     /// in the subnet.
-    Subnet::OptionDescriptor
+    OptionDescriptor
     getOptionFromSubnet(const IOAddress& subnet_address,
                         const uint16_t option_code,
                         const uint16_t expected_options_count = 1) {
@@ -243,7 +243,7 @@ public:
                           << subnet_address.toText()
                           << "does not exist in Config Manager";
         }
-        Subnet::OptionContainerPtr options =
+        OptionContainerPtr options =
             subnet->getOptionDescriptors("dhcp4");
         if (expected_options_count != options->size()) {
             ADD_FAILURE() << "The number of options in the subnet '"
@@ -253,13 +253,13 @@ public:
         }
 
         // Get the search index. Index #1 is to search using option code.
-        const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+        const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-                  Subnet::OptionContainerTypeIndex::const_iterator> range =
+        std::pair<OptionContainerTypeIndex::const_iterator,
+                  OptionContainerTypeIndex::const_iterator> range =
             idx.equal_range(option_code);
         if (std::distance(range.first, range.second) > 1) {
             ADD_FAILURE() << "There is more than one option having the"
@@ -267,7 +267,7 @@ public:
                           << subnet_address.toText() << "'. Expected "
                 " at most one option";
         } else if (std::distance(range.first, range.second) == 0) {
-            return (Subnet::OptionDescriptor(OptionPtr(), false));
+            return (OptionDescriptor(OptionPtr(), false));
         }
 
         return (*range.first);
@@ -319,7 +319,7 @@ public:
     /// @param expected_data_len length of the reference data.
     /// @param extra_data if true extra data is allowed in an option
     /// after tested data.
-    void testOption(const Subnet::OptionDescriptor& option_desc,
+    void testOption(const OptionDescriptor& option_desc,
                     uint16_t expected_code, const uint8_t* expected_data,
                     size_t expected_data_len,
                     bool extra_data = false) {
@@ -378,7 +378,7 @@ public:
         std::string config = createConfigWithOption(params);
         ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
         // The subnet should now hold one option with the specified option code.
-        Subnet::OptionDescriptor desc =
+        OptionDescriptor desc =
             getOptionFromSubnet(IOAddress("192.0.2.24"), option_code);
         ASSERT_TRUE(desc.option);
         testOption(desc, option_code, expected_data, expected_data_len);
@@ -1797,17 +1797,17 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
     ASSERT_EQ(2, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(56);
     // Expect single option with the code equal to 56.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -1884,16 +1884,16 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
                                                       classify_);
     ASSERT_TRUE(subnet);
     // Try to get the option from the space dhcp4.
-    Subnet::OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp4", 56);
+    OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp4", 56);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(56, desc1.option->getType());
     // Try to get the option from the space isc.
-    Subnet::OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 56);
+    OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 56);
     ASSERT_TRUE(desc2.option);
     EXPECT_EQ(56, desc1.option->getType());
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 56);
+    OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 56);
     ASSERT_FALSE(desc3.option);
 }
 
@@ -2039,12 +2039,12 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
     ASSERT_TRUE(options);
     ASSERT_EQ(1, options->size());
 
     // Get the option.
-    Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp4", 222);
+    OptionDescriptor desc = subnet->getOptionDescriptor("dhcp4", 222);
     EXPECT_TRUE(desc.option);
     EXPECT_EQ(222, desc.option->getType());
 
@@ -2104,17 +2104,17 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.24"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
     ASSERT_EQ(2, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(56);
     // Expect single option with the code equal to 100.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2150,7 +2150,7 @@ TEST_F(Dhcp4ParserTest, optionDataBoolean) {
                                      " boolean value"));
 
     // The subnet should now hold one option with the code 19.
-    Subnet::OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"),
+    OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"),
                                                         19);
     ASSERT_TRUE(desc.option);
 
@@ -2255,17 +2255,17 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
     Subnet4Ptr subnet1 = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.100"),
                                                        classify_);
     ASSERT_TRUE(subnet1);
-    Subnet::OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp4");
     ASSERT_EQ(1, options1->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx1 = options1->get<1>();
+    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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range1 =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range1 =
         idx1.equal_range(56);
     // Expect single option with the code equal to 56.
     ASSERT_EQ(1, std::distance(range1.first, range1.second));
@@ -2280,12 +2280,12 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
     Subnet4Ptr subnet2 = CfgMgr::instance().getSubnet4(IOAddress("192.0.3.102"),
                                                        classify_);
     ASSERT_TRUE(subnet2);
-    Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp4");
     ASSERT_EQ(1, options2->size());
 
-    const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
-    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range2 =
+    const OptionContainerTypeIndex& idx2 = options2->get<1>();
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range2 =
         idx2.equal_range(23);
     ASSERT_EQ(1, std::distance(range2.first, range2.second));
 
@@ -2358,17 +2358,17 @@ TEST_F(Dhcp4ParserTest, optionDataLowerCase) {
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
     ASSERT_EQ(1, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(56);
     // Expect single option with the code equal to 100.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2401,19 +2401,19 @@ TEST_F(Dhcp4ParserTest, stdOptionData) {
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options =
+    OptionContainerPtr options =
         subnet->getOptionDescriptors("dhcp4");
     ASSERT_TRUE(options);
     ASSERT_EQ(1, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(DHO_NIS_SERVERS);
     // Expect single option with the code equal to NIS_SERVERS option code.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2611,12 +2611,12 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
     ASSERT_TRUE(options);
     ASSERT_EQ(1, options->size());
 
     // Get the option.
-    Subnet::OptionDescriptor desc =
+    OptionDescriptor desc =
         subnet->getOptionDescriptor("dhcp4", DHO_VENDOR_ENCAPSULATED_OPTIONS);
     EXPECT_TRUE(desc.option);
     EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, desc.option->getType());
@@ -2695,17 +2695,17 @@ TEST_F(Dhcp4ParserTest, vendorOptionsHex) {
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
-    Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
+    OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(100, desc1.option->getType());
     // Try to get the option from the vendor space 1234
-    Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
+    OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
     ASSERT_TRUE(desc2.option);
     EXPECT_EQ(100, desc1.option->getType());
 
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 100);
+    OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 100);
     ASSERT_FALSE(desc3.option);
 }
 
@@ -2756,13 +2756,13 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
-    Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
+    OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(100, desc1.option->getType());
 
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
+    OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
     ASSERT_FALSE(desc2.option);
 }
 

+ 2 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -731,7 +731,7 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     // Get the list of options that client requested.
     const std::vector<uint16_t>& requested_opts = option_oro->getValues();
     BOOST_FOREACH(uint16_t opt, requested_opts) {
-        Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", opt);
+        OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", opt);
         if (desc.option) {
             answer->addOption(desc.option);
         }
@@ -777,7 +777,7 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer
     bool added = false;
     const std::vector<uint16_t>& requested_opts = oro->getValues();
     BOOST_FOREACH(uint16_t opt, requested_opts) {
-        Subnet::OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id, opt);
+        OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id, opt);
         if (desc.option) {
             vendor_rsp->addOption(desc.option);
             added = true;

+ 41 - 41
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -243,7 +243,7 @@ public:
     /// @return Descriptor of the option. If the descriptor holds a
     /// NULL option pointer, it means that there was no such option
     /// in the subnet.
-    Subnet::OptionDescriptor
+    OptionDescriptor
     getOptionFromSubnet(const IOAddress& subnet_address,
                         const uint16_t option_code,
                         const uint16_t expected_options_count = 1) {
@@ -255,7 +255,7 @@ public:
                           << subnet_address.toText()
                           << "does not exist in Config Manager";
         }
-        Subnet::OptionContainerPtr options =
+        OptionContainerPtr options =
             subnet->getOptionDescriptors("dhcp6");
         if (expected_options_count != options->size()) {
             ADD_FAILURE() << "The number of options in the subnet '"
@@ -265,13 +265,13 @@ public:
         }
 
         // Get the search index. Index #1 is to search using option code.
-        const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+        const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-                  Subnet::OptionContainerTypeIndex::const_iterator> range =
+        std::pair<OptionContainerTypeIndex::const_iterator,
+                  OptionContainerTypeIndex::const_iterator> range =
             idx.equal_range(option_code);
         if (std::distance(range.first, range.second) > 1) {
             ADD_FAILURE() << "There is more than one option having the"
@@ -279,7 +279,7 @@ public:
                           << subnet_address.toText() << "'. Expected "
                 " at most one option";
         } else if (std::distance(range.first, range.second) == 0) {
-            return (Subnet::OptionDescriptor(OptionPtr(), false));
+            return (OptionDescriptor(OptionPtr(), false));
         }
 
         return (*range.first);
@@ -413,7 +413,7 @@ public:
     /// @param expected_data_len length of the reference data.
     /// @param extra_data if true extra data is allowed in an option
     /// after tested data.
-    void testOption(const Subnet::OptionDescriptor& option_desc,
+    void testOption(const OptionDescriptor& option_desc,
                     uint16_t expected_code, const uint8_t* expected_data,
                     size_t expected_data_len,
                     bool extra_data = false) {
@@ -473,7 +473,7 @@ public:
         ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
 
         // The subnet should now hold one option with the specified code.
-        Subnet::OptionDescriptor desc =
+        OptionDescriptor desc =
             getOptionFromSubnet(IOAddress("2001:db8:1::5"), option_code);
         ASSERT_TRUE(desc.option);
         testOption(desc, option_code, expected_data, expected_data_len);
@@ -2030,17 +2030,17 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_EQ(2, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(D6O_SUBSCRIBER_ID);
     // Expect single option with the code equal to 38.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2126,16 +2126,16 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
                                                       classify_);
     ASSERT_TRUE(subnet);
     // Try to get the option from the space dhcp6.
-    Subnet::OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp6", 38);
+    OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp6", 38);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(38, desc1.option->getType());
     // Try to get the option from the space isc.
-    Subnet::OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 38);
+    OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 38);
     ASSERT_TRUE(desc2.option);
     EXPECT_EQ(38, desc1.option->getType());
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 38);
+    OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 38);
     ASSERT_FALSE(desc3.option);
 }
 
@@ -2283,12 +2283,12 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_TRUE(options);
     ASSERT_EQ(1, options->size());
 
     // Get the option.
-    Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", 100);
+    OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", 100);
     EXPECT_TRUE(desc.option);
     EXPECT_EQ(100, desc.option->getType());
 
@@ -2344,17 +2344,17 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
     Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
                                                        classify_);
     ASSERT_TRUE(subnet1);
-    Subnet::OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp6");
     ASSERT_EQ(1, options1->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx1 = options1->get<1>();
+    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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range1 =
+    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));
@@ -2370,12 +2370,12 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
     Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"),
                                                        classify_);
     ASSERT_TRUE(subnet2);
-    Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp6");
     ASSERT_EQ(1, options2->size());
 
-    const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
-    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range2 =
+    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));
 
@@ -2405,7 +2405,7 @@ TEST_F(Dhcp6ParserTest, optionDataBoolean) {
     CfgMgr::instance().commit();
 
     // The subnet should now hold one option with the code 1000.
-    Subnet::OptionDescriptor desc =
+    OptionDescriptor desc =
         getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000);
     ASSERT_TRUE(desc.option);
 
@@ -2541,17 +2541,17 @@ TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_EQ(1, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(D6O_SUBSCRIBER_ID);
     // Expect single option with the code equal to 38.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2584,17 +2584,17 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
                                                       classify_);
     ASSERT_TRUE(subnet);
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_EQ(1, options->size());
 
     // Get the search index. Index #1 is to search using option code.
-    const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    const 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<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(D6O_IA_NA);
     // Expect single option with the code equal to IA_NA option code.
     ASSERT_EQ(1, std::distance(range.first, range.second));
@@ -2664,17 +2664,17 @@ TEST_F(Dhcp6ParserTest, vendorOptionsHex) {
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
-    Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
+    OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(100, desc1.option->getType());
     // Try to get the option from the vendor space 1234
-    Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
+    OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
     ASSERT_TRUE(desc2.option);
     EXPECT_EQ(100, desc1.option->getType());
 
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 38);
+    OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 38);
     ASSERT_FALSE(desc3.option);
 }
 
@@ -2726,13 +2726,13 @@ TEST_F(Dhcp6ParserTest, vendorOptionsCsv) {
     ASSERT_TRUE(subnet);
 
     // Try to get the option from the vendor space 4491
-    Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
+    OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
     ASSERT_TRUE(desc1.option);
     EXPECT_EQ(100, desc1.option->getType());
 
     // Try to get the non-existing option from the non-existing
     // option space and  expect that option is not returned.
-    Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
+    OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
     ASSERT_FALSE(desc2.option);
 }
 
@@ -2865,12 +2865,12 @@ TEST_F(Dhcp6ParserTest, stdOptionDataEncapsulate) {
     ASSERT_TRUE(subnet);
 
     // We should have one option available.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_TRUE(options);
     ASSERT_EQ(1, options->size());
 
     // Get the option.
-    Subnet::OptionDescriptor desc =
+    OptionDescriptor desc =
         subnet->getOptionDescriptor("dhcp6", D6O_VENDOR_OPTS);
     EXPECT_TRUE(desc.option);
     EXPECT_EQ(D6O_VENDOR_OPTS, desc.option->getType());

+ 1 - 0
src/lib/dhcpsrv/Makefile.am

@@ -46,6 +46,7 @@ libkea_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
 libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
 libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
 libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
+libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
 libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
 libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
 libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h

+ 98 - 0
src/lib/dhcpsrv/cfg_option.cc

@@ -0,0 +1,98 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfg_option.h>
+#include <boost/lexical_cast.hpp>
+#include <limits>
+#include <string>
+
+namespace {
+
+uint32_t
+optionSpaceToVendorId(const std::string& option_space) {
+    if (option_space.size() < 8) {
+        // 8 is a minimal length of "vendor-X" format
+        return (0);
+    }
+    if (option_space.substr(0,7) != "vendor-") {
+        return (0);
+    }
+
+    // text after "vendor-", supposedly numbers only
+    std::string x = option_space.substr(7);
+
+    int64_t check;
+    try {
+        check = boost::lexical_cast<int64_t>(x);
+    } catch (const boost::bad_lexical_cast &) {
+        /// @todo: Should we throw here?
+        // isc_throw(BadValue, "Failed to parse vendor-X value (" << x
+        //           << ") as unsigned 32-bit integer.");
+        return (0);
+    }
+    if (check > std::numeric_limits<uint32_t>::max()) {
+        /// @todo: Should we throw here?
+        //isc_throw(BadValue, "Value " << x << "is too large"
+        //          << " for unsigned 32-bit integer.");
+        return (0);
+    }
+    if (check < 0) {
+        /// @todo: Should we throw here?
+        // isc_throw(BadValue, "Value " << x << "is negative."
+        //       << " Only 0 or larger are allowed for unsigned 32-bit integer.");
+        return (0);
+    }
+
+    // value is small enough to fit
+    return (static_cast<uint32_t>(check));
+}
+
+}
+
+namespace isc {
+namespace dhcp {
+
+void
+CfgOption::add(const OptionPtr& option, const bool persistent,
+               const std::string& option_space) {
+    if (!option) {
+        isc_throw(isc::BadValue, "option being configured must not be NULL");
+
+    } else  if (!OptionSpace::validateName(option_space)) {
+        isc_throw(isc::BadValue, "invalid option space name: '"
+                  << option_space << "'");
+    }
+
+    const uint32_t vendor_id = optionSpaceToVendorId(option_space);
+    if (vendor_id) {
+        vendor_options_.addItem(OptionDescriptor(option, persistent),
+                                vendor_id);
+    } else {
+        options_.addItem(OptionDescriptor(option, persistent), option_space);
+    }
+}
+
+OptionContainerPtr
+CfgOption::getAll(const std::string& option_space) const {
+    return (options_.getItems(option_space));
+}
+
+OptionContainerPtr
+CfgOption::getAll(const uint32_t vendor_id) const {
+    return (vendor_options_.getItems(vendor_id));
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc

+ 267 - 0
src/lib/dhcpsrv/cfg_option.h

@@ -0,0 +1,267 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CFG_OPTION_H
+#define CFG_OPTION_H
+
+#include <dhcp/option.h>
+#include <dhcpsrv/key_from_key.h>
+#include <dhcpsrv/option_space_container.h>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Option descriptor.
+///
+/// Option descriptor holds instance of an option and additional information
+/// for this option. This information comprises whether this option is sent
+/// to DHCP client only on request (persistent = false) or always
+/// (persistent = true).
+struct OptionDescriptor {
+    /// Option instance.
+    OptionPtr option;
+    /// Persistent flag, if true option is always sent to the client,
+    /// if false option is sent to the client on request.
+    bool persistent;
+
+    /// @brief Constructor.
+    ///
+    /// @param opt option
+    /// @param persist if true option is always sent.
+    OptionDescriptor(const OptionPtr& opt, bool persist)
+        : option(opt), persistent(persist) {};
+
+    /// @brief Constructor
+    ///
+    /// @param persist if true option is always sent.
+    OptionDescriptor(bool persist)
+        : option(OptionPtr()), persistent(persist) {};
+};
+
+/// A pointer to option descriptor.
+typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
+
+/// @brief Multi index container for DHCP option descriptors.
+///
+/// This container comprises three indexes to access option
+/// descriptors:
+/// - sequenced index: used to access elements in the order they
+/// have been added to the container,
+/// - option type index: used to search option descriptors containing
+/// options with specific option code (aka option type).
+/// - persistency flag index: used to search option descriptors with
+/// 'persistent' flag set to true.
+///
+/// This container is the equivalent of three separate STL containers:
+/// - std::list of all options,
+/// - std::multimap of options with option code used as a multimap key,
+/// - std::multimap of option descriptors with option persistency flag
+/// used as a multimap key.
+/// The major advantage of this container over 3 separate STL containers
+/// is automatic synchronization of all indexes when elements are added,
+/// removed or modified in the container. With separate containers,
+/// the synchronization would have to be guaranteed by the Subnet class
+/// code. This would increase code complexity and presumably it would
+/// be much harder to add new search criteria (indexes).
+///
+/// @todo we may want to search for options using option spaces when
+/// they are implemented.
+///
+/// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
+typedef boost::multi_index_container<
+    // Container comprises elements of OptionDescriptor type.
+    OptionDescriptor,
+    // Here we start enumerating various indexes.
+    boost::multi_index::indexed_by<
+        // Sequenced index allows accessing elements in the same way
+        // as elements in std::list.
+        // Sequenced is an index #0.
+        boost::multi_index::sequenced<>,
+        // Start definition of index #1.
+        boost::multi_index::hashed_non_unique<
+            // KeyFromKeyExtractor is the index key extractor that allows
+            // accessing option type being held by the OptionPtr through
+            // OptionDescriptor structure.
+            KeyFromKeyExtractor<
+                // Use option type as the index key. The type is held
+                // in OptionPtr object so we have to call Option::getType
+                // to retrieve this key for each element.
+                boost::multi_index::const_mem_fun<
+                    Option,
+                    uint16_t,
+                    &Option::getType
+                >,
+                // Indicate that OptionPtr is a member of
+                // OptionDescriptor structure.
+                boost::multi_index::member<
+                    OptionDescriptor,
+                    OptionPtr,
+                    &OptionDescriptor::option
+                 >
+            >
+        >,
+        // Start definition of index #2.
+        // Use 'persistent' struct member as a key.
+        boost::multi_index::hashed_non_unique<
+            boost::multi_index::member<
+                OptionDescriptor,
+                bool,
+                &OptionDescriptor::persistent
+            >
+        >
+    >
+> OptionContainer;
+
+/// Pointer to the OptionContainer object.
+typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
+/// Type of the index #1 - option type.
+typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
+/// Pair of iterators to represent the range of options having the
+/// same option type value. The first element in this pair represents
+/// the beginning of the range, the second element represents the end.
+typedef std::pair<OptionContainerTypeIndex::const_iterator,
+                  OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
+/// Type of the index #2 - option persistency flag.
+typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
+
+/// @brief Represents option data configuration for the DHCP server.
+///
+/// This class holds a collection of options to be sent to a DHCP client.
+/// Options are grouped by the option space or vendor identifier (for
+/// vendor options).
+///
+/// The server configuration allows for specifying two distinct collections
+/// of options: global options and per-subnet options in which some options
+/// may overlap.
+///
+/// The collection of global options specify options being sent to the client
+/// belonging to any subnets, i.e. global options are "inherited" by all
+/// subnets.
+///
+/// The per-subnet options are configured for a particular subnet and are sent
+/// to clients which belong to this subnet. The values of the options specified
+/// for a particular subnet override the values of the global options.
+///
+/// This class represents a single collection of options (either global or
+/// per-subnet). Each subnet holds its own object of the @c CfgOption type. The
+/// @c CfgMgr holds a @c CfgOption object representing global options.
+///
+/// Note that having a separate copy of the @c CfgOption to represent global
+/// options is useful when the client requests stateless configuration from
+/// the DHCP server and no subnet is selected for this client. This client
+/// will only receive global options.
+class CfgOption {
+public:
+
+    /// @brief Adds instance of the option to the configuration.
+    ///
+    /// There are two types of options which may be passed to this method:
+    /// - vendor options
+    /// - non-vendor options
+    ///
+    /// The non-vendor options are grouped by the name of the option space
+    /// (specified in textual format). The vendor options are grouped by the
+    /// vendor identifier, which is a 32-bit unsigned integer value.
+    ///
+    /// In order to add new vendor option to the list the option space name
+    /// (last argument of this method) should be specified as "vendor-X" where
+    /// "X" is a 32-bit unsigned integer, e.g. "vendor-1234". Options for which
+    /// the @c option_space argument doesn't follow this format are added as
+    /// non-vendor options.
+    ///
+    /// @param option Pointer to the option being added.
+    /// @param persistent Boolean value which specifies if the option should
+    /// be sent to the client regardless if requested (true), or nor (false)
+    /// @param option_space Option space name.
+    ///
+    /// @throw isc::BadValue if the option space is invalid.
+    void add(const OptionPtr& option, const bool persistent,
+             const std::string& option_space);
+
+    /// @brief Returns all options for the specified option space.
+    ///
+    /// This method will not return vendor options, i.e. having option space
+    /// name in the format of "vendor-X" where X is 32-bit unsiged integer.
+    ///
+    /// @param option_space Name of the option space.
+    ///
+    /// @return Pointer to the container holding returned options. This
+    /// container is empty if no options have been found.
+    OptionContainerPtr getAll(const std::string& option_space) const;
+
+    /// @brief Returns vendor options for the specified vendor id.
+    ///
+    /// @param vendor_id Vendor id for which options are to be returned.
+    ///
+    /// @return Pointer to the container holding returned options. This
+    /// container is empty if no options have been found.
+    OptionContainerPtr getAll(const uint32_t vendor_id) const;
+
+    /// @brief Returns option for the specified key and option code.
+    ///
+    /// The key should be a string, in which case it specifies an option space
+    /// name, or an uint32_t value, in which case it specifies a vendor
+    /// identifier.
+    ///
+    /// @param key Option space name or vendor identifier.
+    /// @param option_code Code of the option to be returned.
+    /// @tparam T one of: @c std::string or @c uint32_t
+    ///
+    /// @return Descriptor of the option. If option hasn't been found, the
+    /// descriptor holds NULL option.
+    template<typename T>
+    OptionDescriptor get(const T& key, const uint16_t option_code) const {
+        OptionContainerPtr options = getAll(key);
+        if (!options || options->empty()) {
+            return (OptionDescriptor(false));
+        }
+
+        const OptionContainerTypeIndex& idx = options->get<1>();
+        const OptionContainerTypeRange& range = idx.equal_range(option_code);
+        if (std::distance(range.first, range.second) == 0) {
+            return (OptionDescriptor(false));
+        }
+
+        return (*range.first);
+    }
+
+private:
+
+    /// @brief Type of the container holding options grouped by option space.
+    typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+                                 std::string> OptionSpaceCollection;
+    /// @brief Container holding options grouped by option space.
+    OptionSpaceCollection options_;
+
+    /// @brief Type of the container holding options grouped by vendor id.
+    typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+                                 uint32_t> VendorOptionSpaceCollection;
+    /// @brief Container holding options grouped by vendor id.
+    VendorOptionSpaceCollection vendor_options_;
+
+
+
+};
+
+}
+}
+
+#endif // CFG_OPTION_H

+ 11 - 10
src/lib/dhcpsrv/dhcp_parsers.cc

@@ -15,6 +15,7 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/dhcp_parsers.h>
 #include <hooks/hooks_manager.h>
 #include <util/encode/hex.h>
@@ -345,16 +346,16 @@ OptionDataParser::commit() {
     }
 
     uint16_t opt_type = option_descriptor_.option->getType();
-    Subnet::OptionContainerPtr options = options_->getItems(option_space_);
+    OptionContainerPtr options = options_->getItems(option_space_);
     // The getItems() should never return NULL pointer. If there are no
     // options configured for the particular option space a pointer
     // to an empty container should be returned.
     assert(options);
-    Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    OptionContainerTypeIndex& idx = options->get<1>();
     // Try to find options with the particular option code in the main
     // storage. If found, remove these options because they will be
     // replaced with new one.
-    Subnet::OptionContainerTypeRange range = idx.equal_range(opt_type);
+    OptionContainerTypeRange range = idx.equal_range(opt_type);
     if (std::distance(range.first, range.second) > 0) {
         idx.erase(range.first, range.second);
     }
@@ -540,7 +541,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
                                   code, data_tokens) :
                 def->optionFactory(global_context_->universe_,
                                    code, binary);
-            Subnet::OptionDescriptor desc(option, false);
+            OptionDescriptor desc(option, false);
             option_descriptor_.option = option;
             option_descriptor_.persistent = false;
         } catch (const isc::Exception& ex) {
@@ -1070,10 +1071,10 @@ SubnetConfigParser::appendSubOptions(const std::string& option_space,
     if (!encapsulated_space.empty()) {
         // Get the sub-options that belong to the encapsulated
         // option space.
-        const Subnet::OptionContainerPtr sub_opts =
+        const OptionContainerPtr sub_opts =
                 global_context_->options_->getItems(encapsulated_space);
         // Append sub-options to the option.
-        BOOST_FOREACH(Subnet::OptionDescriptor desc, *sub_opts) {
+        BOOST_FOREACH(OptionDescriptor desc, *sub_opts) {
             if (desc.option) {
                 option->addOption(desc.option);
             }
@@ -1152,7 +1153,7 @@ SubnetConfigParser::createSubnet() {
     std::list<std::string> space_names = options_->getOptionSpaceNames();
     BOOST_FOREACH(std::string option_space, space_names) {
         // Get all options within a particular option space.
-        BOOST_FOREACH(Subnet::OptionDescriptor desc,
+        BOOST_FOREACH(OptionDescriptor desc,
                       *options_->getItems(option_space)) {
             // The pointer should be non-NULL. The validation is expected
             // to be performed by the OptionDataParser before adding an
@@ -1161,7 +1162,7 @@ SubnetConfigParser::createSubnet() {
             // We want to check whether an option with the particular
             // option code has been already added. If so, we want
             // to issue a warning.
-            Subnet::OptionDescriptor existing_desc =
+            OptionDescriptor existing_desc =
                             subnet_->getOptionDescriptor("option_space",
                                                  desc.option->getType());
             if (existing_desc.option) {
@@ -1189,7 +1190,7 @@ SubnetConfigParser::createSubnet() {
     space_names = global_context_->options_->getOptionSpaceNames();
     BOOST_FOREACH(std::string option_space, space_names) {
         // Get all global options for the particular option space.
-        BOOST_FOREACH(Subnet::OptionDescriptor desc,
+        BOOST_FOREACH(OptionDescriptor desc,
                 *(global_context_->options_->getItems(option_space))) {
             // The pointer should be non-NULL. The validation is expected
             // to be performed by the OptionDataParser before adding an
@@ -1201,7 +1202,7 @@ SubnetConfigParser::createSubnet() {
             // subnet scope take precedence over globally configured
             // values we don't add option from the global storage
             // if there is one already.
-            Subnet::OptionDescriptor existing_desc =
+            OptionDescriptor existing_desc =
                     subnet_->getOptionDescriptor(option_space,
                                                 desc.option->getType());
             if (!existing_desc.option) {

+ 4 - 3
src/lib/dhcpsrv/dhcp_parsers.h

@@ -21,6 +21,7 @@
 #include <dhcpsrv/d2_client_cfg.h>
 #include <dhcpsrv/dhcp_config_parser.h>
 #include <dhcpsrv/cfg_iface.h>
+#include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/subnet.h>
 #include <exceptions/exceptions.h>
@@ -42,8 +43,8 @@ typedef boost::shared_ptr<OptionDefStorage> OptionDefStoragePtr;
 
 /// Collection of containers holding option spaces. Each container within
 /// a particular option space holds so-called option descriptors.
-typedef OptionSpaceContainer<Subnet::OptionContainer,
-    Subnet::OptionDescriptor, std::string> OptionStorage;
+typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+                             std::string> OptionStorage;
 /// @brief Shared pointer to option storage.
 typedef boost::shared_ptr<OptionStorage> OptionStoragePtr;
 
@@ -600,7 +601,7 @@ private:
     OptionStoragePtr options_;
 
     /// Option descriptor holds newly configured option.
-    Subnet::OptionDescriptor option_descriptor_;
+    OptionDescriptor option_descriptor_;
 
     /// Option space name where the option belongs to.
     std::string option_space_;

+ 4 - 4
src/lib/dhcpsrv/subnet.cc

@@ -104,12 +104,12 @@ Subnet::delOptions() {
     option_spaces_.clearItems();
 }
 
-Subnet::OptionContainerPtr
+OptionContainerPtr
 Subnet::getOptionDescriptors(const std::string& option_space) const {
     return (option_spaces_.getItems(option_space));
 }
 
-Subnet::OptionDescriptor
+OptionDescriptor
 Subnet::getOptionDescriptor(const std::string& option_space,
                             const uint16_t option_code) {
     OptionContainerPtr options = getOptionDescriptors(option_space);
@@ -133,12 +133,12 @@ void Subnet::addVendorOption(const OptionPtr& option, bool persistent,
     vendor_option_spaces_.addItem(OptionDescriptor(option, persistent), vendor_id);
 }
 
-Subnet::OptionContainerPtr
+OptionContainerPtr
 Subnet::getVendorOptionDescriptors(uint32_t vendor_id) const {
     return (vendor_option_spaces_.getItems(vendor_id));
 }
 
-Subnet::OptionDescriptor
+OptionDescriptor
 Subnet::getVendorOptionDescriptor(uint32_t vendor_id, uint16_t option_code) {
     OptionContainerPtr options = getVendorOptionDescriptors(vendor_id);
     if (!options || options->empty()) {

+ 3 - 121
src/lib/dhcpsrv/subnet.h

@@ -15,22 +15,17 @@
 #ifndef SUBNET_H
 #define SUBNET_H
 
-#include <boost/shared_ptr.hpp>
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
-#include <boost/multi_index/mem_fun.hpp>
-#include <boost/multi_index/member.hpp>
-
 #include <asiolink/io_address.h>
 #include <dhcp/option.h>
 #include <dhcp/classify.h>
-#include <dhcpsrv/key_from_key.h>
+#include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/triplet.h>
 #include <dhcpsrv/lease.h>
 
+#include <boost/shared_ptr.hpp>
+
 namespace isc {
 namespace dhcp {
 
@@ -54,119 +49,6 @@ typedef uint32_t SubnetID;
 class Subnet {
 public:
 
-    /// @brief Option descriptor.
-    ///
-    /// Option descriptor holds information about option configured for
-    /// a particular subnet. This information comprises the actual option
-    /// instance and information whether this option is sent to DHCP client
-    /// only on request (persistent = false) or always (persistent = true).
-    struct OptionDescriptor {
-        /// Option instance.
-        OptionPtr option;
-        /// Persistent flag, if true option is always sent to the client,
-        /// if false option is sent to the client on request.
-        bool persistent;
-
-        /// @brief Constructor.
-        ///
-        /// @param opt option
-        /// @param persist if true option is always sent.
-        OptionDescriptor(const OptionPtr& opt, bool persist)
-            : option(opt), persistent(persist) {};
-
-        /// @brief Constructor
-        ///
-        /// @param persist if true option is always sent.
-        OptionDescriptor(bool persist)
-            : option(OptionPtr()), persistent(persist) {};
-    };
-
-    /// A pointer to option descriptor.
-    typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
-
-    /// @brief Multi index container for DHCP option descriptors.
-    ///
-    /// This container comprises three indexes to access option
-    /// descriptors:
-    /// - sequenced index: used to access elements in the order they
-    /// have been added to the container,
-    /// - option type index: used to search option descriptors containing
-    /// options with specific option code (aka option type).
-    /// - persistency flag index: used to search option descriptors with
-    /// 'persistent' flag set to true.
-    ///
-    /// This container is the equivalent of three separate STL containers:
-    /// - std::list of all options,
-    /// - std::multimap of options with option code used as a multimap key,
-    /// - std::multimap of option descriptors with option persistency flag
-    /// used as a multimap key.
-    /// The major advantage of this container over 3 separate STL containers
-    /// is automatic synchronization of all indexes when elements are added,
-    /// removed or modified in the container. With separate containers,
-    /// the synchronization would have to be guaranteed by the Subnet class
-    /// code. This would increase code complexity and presumably it would
-    /// be much harder to add new search criteria (indexes).
-    ///
-    /// @todo we may want to search for options using option spaces when
-    /// they are implemented.
-    ///
-    /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
-    typedef boost::multi_index_container<
-        // Container comprises elements of OptionDescriptor type.
-        OptionDescriptor,
-        // Here we start enumerating various indexes.
-        boost::multi_index::indexed_by<
-            // Sequenced index allows accessing elements in the same way
-            // as elements in std::list.
-            // Sequenced is an index #0.
-            boost::multi_index::sequenced<>,
-            // Start definition of index #1.
-            boost::multi_index::hashed_non_unique<
-                // KeyFromKeyExtractor is the index key extractor that allows
-                // accessing option type being held by the OptionPtr through
-                // OptionDescriptor structure.
-                KeyFromKeyExtractor<
-                    // Use option type as the index key. The type is held
-                    // in OptionPtr object so we have to call Option::getType
-                    // to retrieve this key for each element.
-                    boost::multi_index::const_mem_fun<
-                        Option,
-                        uint16_t,
-                        &Option::getType
-                    >,
-                    // Indicate that OptionPtr is a member of
-                    // OptionDescriptor structure.
-                    boost::multi_index::member<
-                        OptionDescriptor,
-                        OptionPtr,
-                        &OptionDescriptor::option
-                    >
-                 >
-            >,
-            // Start definition of index #2.
-            // Use 'persistent' struct member as a key.
-            boost::multi_index::hashed_non_unique<
-                boost::multi_index::member<
-                    OptionDescriptor,
-                    bool,
-                    &OptionDescriptor::persistent
-                >
-            >
-        >
-    > OptionContainer;
-
-    /// Pointer to the OptionContainer object.
-    typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
-    /// Type of the index #1 - option type.
-    typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
-    /// Pair of iterators to represent the range of options having the
-    /// same option type value. The first element in this pair represents
-    /// the beginning of the range, the second element represents the end.
-    typedef std::pair<OptionContainerTypeIndex::const_iterator,
-                      OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
-    /// Type of the index #2 - option persistency flag.
-    typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
-
     /// @brief Holds optional information about relay.
     ///
     /// In some cases it is beneficial to have additional information about

+ 1 - 0
src/lib/dhcpsrv/tests/Makefile.am

@@ -56,6 +56,7 @@ libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
 libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
 libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
 libdhcpsrv_unittests_SOURCES += csv_lease_file4_unittest.cc

+ 243 - 0
src/lib/dhcpsrv/tests/cfg_option_unittest.cc

@@ -0,0 +1,243 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/cfg_option.h>
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+// This test verifies that multiple options can be added to the configuration
+// and that they can be retrieved using the option space name.
+TEST(CfgOptionTest, add) {
+    CfgOption cfg;
+
+    // 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(cfg.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(cfg.add(option, false, "isc"));
+    }
+
+    // Get options from the Subnet and check if all 10 are there.
+    OptionContainerPtr options = cfg.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 = cfg.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 = cfg.getAll("abcd");
+    ASSERT_TRUE(options);
+    EXPECT_TRUE(options->empty());
+}
+
+// This test verifies that single option can be retrieved from the configuration
+// using option code and option space.
+TEST(CfgOption, get) {
+    CfgOption cfg;
+
+    // Add 10 options to a "dhcp6" option space in the subnet.
+    for (uint16_t code = 100; code < 110; ++code) {
+        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+        ASSERT_NO_THROW(cfg.add(option, false, "dhcp6"));
+    }
+
+    // Check that we can get each added option descriptor using
+    // individually.
+    for (uint16_t code = 100; code < 110; ++code) {
+        std::ostringstream stream;
+        // First, try the invalid option space name.
+        OptionDescriptor desc = cfg.get("isc", code);
+        // Returned descriptor should contain NULL option ptr.
+        EXPECT_FALSE(desc.option);
+        // Now, try the valid option space.
+        desc = cfg.get("dhcp6", code);
+        // Test that the option code matches the expected code.
+        ASSERT_TRUE(desc.option);
+        EXPECT_EQ(code, desc.option->getType());
+    }
+}
+
+// This test verifies that the same options can be added to the configuration
+// under different option space.
+TEST(CfgOptionTest, addNonUniqueOptions) {
+    CfgOption cfg;
+
+    // Create a set of options with non-unique codes.
+    for (int i = 0;  i < 2; ++i) {
+        // In the inner loop we create options with unique codes (100-109).
+        for (uint16_t code = 100; code < 110; ++code) {
+            OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+            ASSERT_NO_THROW(cfg.add(option, false, "dhcp6"));
+        }
+    }
+
+    // Sanity check that all options are there.
+    OptionContainerPtr options = cfg.getAll("dhcp6");
+    ASSERT_EQ(20, options->size());
+
+    // Use container index #1 to get the options by their codes.
+    OptionContainerTypeIndex& idx = options->get<1>();
+    // Look for the codes 100-109.
+    for (uint16_t code = 100; code < 110; ++ code) {
+        // For each code we should get two instances of options->
+        std::pair<OptionContainerTypeIndex::const_iterator,
+                  OptionContainerTypeIndex::const_iterator> range =
+            idx.equal_range(code);
+        // Distance between iterators indicates how many options
+        // have been retured for the particular code.
+        ASSERT_EQ(2, distance(range.first, range.second));
+        // Check that returned options actually have the expected option code.
+        for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
+             option_desc != range.second; ++option_desc) {
+            ASSERT_TRUE(option_desc->option);
+            EXPECT_EQ(code, option_desc->option->getType());
+        }
+    }
+
+    // Let's try to find some non-exiting option.
+    const uint16_t non_existing_code = 150;
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
+        idx.equal_range(non_existing_code);
+    // Empty set is expected.
+    EXPECT_EQ(0, distance(range.first, range.second));
+}
+
+// This test verifies that the option with the persistency flag can be
+// added to the configuration and that options with the persistency flags
+// can be retrieved.
+TEST(Subnet6Test, addPersistentOption) {
+    CfgOption cfg;
+
+    // Add 10 options to the subnet with option codes 100 - 109.
+    for (uint16_t code = 100; code < 110; ++code) {
+        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+        // We create 10 options and want some of them to be flagged
+        // persistent and some non-persistent. Persistent options are
+        // those that server sends to clients regardless if they ask
+        // for them or not. We pick 3 out of 10 options and mark them
+        // non-persistent and 7 other options persistent.
+        // Code values: 102, 105 and 108 are divisible by 3
+        // and options with these codes will be flagged non-persistent.
+        // Options with other codes will be flagged persistent.
+        bool persistent = (code % 3) ? true : false;
+        ASSERT_NO_THROW(cfg.add(option, persistent, "dhcp6"));
+    }
+
+    // Get added options from the subnet.
+    OptionContainerPtr options = cfg.getAll("dhcp6");
+
+    // options->get<2> returns reference to container index #2. This
+    // index is used to access options by the 'persistent' flag.
+    OptionContainerPersistIndex& idx = options->get<2>();
+
+    // Get all persistent options->
+    std::pair<OptionContainerPersistIndex::const_iterator,
+              OptionContainerPersistIndex::const_iterator> range_persistent =
+        idx.equal_range(true);
+    // 3 out of 10 options have been flagged persistent.
+    ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
+
+    // Get all non-persistent options->
+    std::pair<OptionContainerPersistIndex::const_iterator,
+              OptionContainerPersistIndex::const_iterator> range_non_persistent =
+        idx.equal_range(false);
+    // 7 out of 10 options have been flagged persistent.
+    ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
+}
+
+// This test verifies that the vendor option can be added to the configuration.
+TEST(CfgOptionTest, addVendorOptions) {
+    CfgOption cfg;
+
+    // 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(cfg.add(option, false, "vendor-12345678"));
+    }
+
+    // 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(cfg.add(option, false, "vendor-87654321"));
+    }
+
+    // Get options from the Subnet and check if all 10 are there.
+    OptionContainerPtr options = cfg.getAll(12345678);
+    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 = cfg.getAll(87654321);
+    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 = cfg.getAll(1111111);
+    ASSERT_TRUE(options);
+    EXPECT_TRUE(options->empty());
+}
+
+
+} // end of anonymous namespace

+ 9 - 9
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -459,19 +459,19 @@ public:
     OptionPtr getOptionPtr(std::string space, uint32_t code)
     {
         OptionPtr option_ptr;
-        Subnet::OptionContainerPtr options =
+        OptionContainerPtr options =
                             parser_context_->options_->getItems(space);
         // Should always be able to get options list even if it is empty.
         EXPECT_TRUE(options);
         if (options) {
             // Attempt to find desired option.
-            const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-            const Subnet::OptionContainerTypeRange& range =
+            const OptionContainerTypeIndex& idx = options->get<1>();
+            const OptionContainerTypeRange& range =
                                                         idx.equal_range(code);
             int cnt = std::distance(range.first, range.second);
             EXPECT_EQ(1, cnt);
             if (cnt == 1) {
-                Subnet::OptionDescriptor desc = *(idx.begin());
+                OptionDescriptor desc = *(idx.begin());
                 option_ptr = desc.option;
                 EXPECT_TRUE(option_ptr);
             }
@@ -1122,11 +1122,11 @@ public:
     /// @param ctx A pointer to a context.
     /// @param opt_type Expected option type.
     void checkOptionType(const ParserContext& ctx, const uint16_t opt_type) {
-        Subnet::OptionContainerPtr options =
+        OptionContainerPtr options =
             ctx.options_->getItems("option-space");
         ASSERT_TRUE(options);
-        Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-        Subnet::OptionContainerTypeRange range = idx.equal_range(opt_type);
+        OptionContainerTypeIndex& idx = options->get<1>();
+        OptionContainerTypeRange range = idx.equal_range(opt_type);
         ASSERT_EQ(1, std::distance(range.first, range.second));
     }
 
@@ -1217,7 +1217,7 @@ public:
         // Add new option, with option code 10, to the context.
         ASSERT_TRUE(ctx.options_);
         OptionPtr opt1(new Option(Option::V6, 10));
-        Subnet::OptionDescriptor desc1(opt1, false);
+        OptionDescriptor desc1(opt1, false);
         std::string option_space = "option-space";
         ASSERT_TRUE(desc1.option);
         ctx.options_->addItem(desc1, option_space);
@@ -1430,7 +1430,7 @@ public:
             SCOPED_TRACE("Check that option remains the same in the new context"
                          " when the option in the original context is changed");
             ctx.options_->clearItems();
-            Subnet::OptionDescriptor desc(OptionPtr(new Option(Option::V6,
+            OptionDescriptor desc(OptionPtr(new Option(Option::V6,
                                                                100)),
                                           false);
 

+ 20 - 20
src/lib/dhcpsrv/tests/subnet_unittest.cc

@@ -657,13 +657,13 @@ TEST(Subnet6Test, addOptions) {
     }
 
     // Get options from the Subnet and check if all 10 are there.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_TRUE(options);
     ASSERT_EQ(10, options->size());
 
     // Validate codes of options added to dhcp6 option space.
     uint16_t expected_code = 100;
-    for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+    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());
@@ -676,7 +676,7 @@ TEST(Subnet6Test, addOptions) {
 
     // Validate codes of options added to isc option space.
     expected_code = 105;
-    for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+    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());
@@ -715,22 +715,22 @@ TEST(Subnet6Test, addNonUniqueOptions) {
     }
 
     // Sanity check that all options are there.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
     ASSERT_EQ(20, options->size());
 
     // Use container index #1 to get the options by their codes.
-    Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    OptionContainerTypeIndex& idx = options->get<1>();
     // Look for the codes 100-109.
     for (uint16_t code = 100; code < 110; ++ code) {
         // For each code we should get two instances of options->
-        std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
-                  Subnet::OptionContainerTypeIndex::const_iterator> range =
+        std::pair<OptionContainerTypeIndex::const_iterator,
+                  OptionContainerTypeIndex::const_iterator> range =
             idx.equal_range(code);
         // Distance between iterators indicates how many options
         // have been retured for the particular code.
         ASSERT_EQ(2, distance(range.first, range.second));
         // Check that returned options actually have the expected option code.
-        for (Subnet::OptionContainerTypeIndex::const_iterator option_desc = range.first;
+        for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
              option_desc != range.second; ++option_desc) {
             ASSERT_TRUE(option_desc->option);
             EXPECT_EQ(code, option_desc->option->getType());
@@ -739,8 +739,8 @@ TEST(Subnet6Test, addNonUniqueOptions) {
 
     // Let's try to find some non-exiting option.
     const uint16_t non_existing_code = 150;
-    std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
-              Subnet::OptionContainerTypeIndex::const_iterator> range =
+    std::pair<OptionContainerTypeIndex::const_iterator,
+              OptionContainerTypeIndex::const_iterator> range =
         idx.equal_range(non_existing_code);
     // Empty set is expected.
     EXPECT_EQ(0, distance(range.first, range.second));
@@ -789,22 +789,22 @@ TEST(Subnet6Test, addPersistentOption) {
     }
 
     // Get added options from the subnet.
-    Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+    OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
 
     // options->get<2> returns reference to container index #2. This
     // index is used to access options by the 'persistent' flag.
-    Subnet::OptionContainerPersistIndex& idx = options->get<2>();
+    OptionContainerPersistIndex& idx = options->get<2>();
 
     // Get all persistent options->
-    std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
-              Subnet::OptionContainerPersistIndex::const_iterator> range_persistent =
+    std::pair<OptionContainerPersistIndex::const_iterator,
+              OptionContainerPersistIndex::const_iterator> range_persistent =
         idx.equal_range(true);
     // 3 out of 10 options have been flagged persistent.
     ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
 
     // Get all non-persistent options->
-    std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
-              Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
+    std::pair<OptionContainerPersistIndex::const_iterator,
+              OptionContainerPersistIndex::const_iterator> range_non_persistent =
         idx.equal_range(false);
     // 7 out of 10 options have been flagged persistent.
     ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
@@ -829,7 +829,7 @@ TEST(Subnet6Test, getOptionDescriptor) {
     for (uint16_t code = 100; code < 110; ++code) {
         std::ostringstream stream;
         // First, try the invalid option space name.
-        Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("isc", code);
+        OptionDescriptor desc = subnet->getOptionDescriptor("isc", code);
         // Returned descriptor should contain NULL option ptr.
         EXPECT_FALSE(desc.option);
         // Now, try the valid option space.
@@ -864,13 +864,13 @@ TEST(Subnet6Test, addVendorOptions) {
     }
 
     // Get options from the Subnet and check if all 10 are there.
-    Subnet::OptionContainerPtr options = subnet->getVendorOptionDescriptors(vendor_id1);
+    OptionContainerPtr options = subnet->getVendorOptionDescriptors(vendor_id1);
     ASSERT_TRUE(options);
     ASSERT_EQ(10, options->size());
 
     // Validate codes of options added to dhcp6 option space.
     uint16_t expected_code = 100;
-    for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+    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());
@@ -883,7 +883,7 @@ TEST(Subnet6Test, addVendorOptions) {
 
     // Validate codes of options added to isc option space.
     expected_code = 105;
-    for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+    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());