BIND 10 master, updated. 741fe7bc96c70df35d9a79016b0aa1488e9b3ac8 [master] Merge branch 'trac2315'
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Jan 8 13:48:21 UTC 2013
The branch, master has been updated
via 741fe7bc96c70df35d9a79016b0aa1488e9b3ac8 (commit)
via b789222291eeb63126dc1c249ed89d4f4517db63 (commit)
via 2548205bf705e3f2d9aeb75e35eb112206476d03 (commit)
via bf592d0607a639ff454dcdc820a76ae0eaacbbf4 (commit)
via 2ed60b95b8cbdff758e08062fc82c8d8f7b367ac (commit)
via c6e109f7d68347703baa542d0a913e97394b8057 (commit)
via d831b49beab09fe65b95d39858486824e9b9a4da (commit)
via c6981a0eed4cb0c68f747fa7f758e53dbfdaf5f7 (commit)
via 0fe0d44af6e81f2e5230515237fcc84b42f37d85 (commit)
via 5530bff261fd921726fce87c2d296da5271c639f (commit)
from 856d60a96bbed5735541659d7c12c51fc055a6cb (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 741fe7bc96c70df35d9a79016b0aa1488e9b3ac8
Merge: 856d60a b789222
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Jan 8 14:09:43 2013 +0100
[master] Merge branch 'trac2315'
Conflicts:
src/bin/dhcp4/config_parser.cc
src/bin/dhcp6/config_parser.cc
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp4/config_parser.cc | 10 +-
src/bin/dhcp4/tests/config_parser_unittest.cc | 38 +++---
src/bin/dhcp6/config_parser.cc | 11 +-
src/bin/dhcp6/dhcp6_srv.cc | 6 +-
src/bin/dhcp6/tests/config_parser_unittest.cc | 36 +++---
src/lib/dhcp/libdhcp++.cc | 28 +++++
src/lib/dhcp/libdhcp++.h | 15 +++
src/lib/dhcp/option_definition.h | 13 +-
src/lib/dhcp/tests/libdhcp++_unittest.cc | 60 +++++++++
src/lib/dhcpsrv/cfgmgr.cc | 85 ++++++++++++-
src/lib/dhcpsrv/cfgmgr.h | 63 +++++++++-
src/lib/dhcpsrv/subnet.cc | 57 ++++++++-
src/lib/dhcpsrv/subnet.h | 47 +++++--
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc | 163 ++++++++++++++++++++++++-
src/lib/dhcpsrv/tests/subnet_unittest.cc | 116 +++++++++++++-----
15 files changed, 652 insertions(+), 96 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp4/config_parser.cc b/src/bin/dhcp4/config_parser.cc
index 193b1de..a6b857d 100644
--- a/src/bin/dhcp4/config_parser.cc
+++ b/src/bin/dhcp4/config_parser.cc
@@ -1117,8 +1117,8 @@ private:
subnet_->addPool4(*it);
}
- const Subnet::OptionContainer& options = subnet_->getOptions();
- const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+ Subnet::OptionContainerPtr options = subnet_->getOptionDescriptors("dhcp4");
+ const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Add subnet specific options.
BOOST_FOREACH(Subnet::OptionDescriptor desc, options_) {
@@ -1127,7 +1127,7 @@ private:
LOG_WARN(dhcp4_logger, DHCP4_CONFIG_OPTION_DUPLICATE)
.arg(desc.option->getType()).arg(addr.toText());
}
- subnet_->addOption(desc.option);
+ subnet_->addOption(desc.option, false, "dhcp4");
}
// Check all global options and add them to the subnet object if
@@ -1137,6 +1137,8 @@ private:
BOOST_FOREACH(Subnet::OptionDescriptor desc, option_defaults) {
// Get all options specified locally in the subnet and having
// code equal to global option's code.
+ Subnet::OptionContainerPtr options = subnet_->getOptionDescriptors("dhcp4");
+ const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
Subnet::OptionContainerTypeRange range = idx.equal_range(desc.option->getType());
// @todo: In the future we will be searching for options using either
// an option code or namespace. Currently we have only the option
@@ -1147,7 +1149,7 @@ private:
// want to issue a warning about dropping the configuration of
// a global option if one already exsists.
if (std::distance(range.first, range.second) == 0) {
- subnet_->addOption(desc.option);
+ subnet_->addOption(desc.option, false, "dhcp4");
}
}
}
diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc
index 498cedb..c6af514 100644
--- a/src/bin/dhcp4/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp4/tests/config_parser_unittest.cc
@@ -471,11 +471,11 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(2, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -542,11 +542,11 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.24"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(2, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -609,11 +609,11 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
Subnet4Ptr subnet1 = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.100"));
ASSERT_TRUE(subnet1);
- const Subnet::OptionContainer& options1 = subnet1->getOptions();
- ASSERT_EQ(1, options1.size());
+ Subnet::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 Subnet::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
@@ -633,10 +633,10 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
// Test another subnet in the same way.
Subnet4Ptr subnet2 = CfgMgr::instance().getSubnet4(IOAddress("192.0.3.102"));
ASSERT_TRUE(subnet2);
- const Subnet::OptionContainer& options2 = subnet2->getOptions();
- ASSERT_EQ(1, options2.size());
+ Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp4");
+ ASSERT_EQ(1, options2->size());
- const Subnet::OptionContainerTypeIndex& idx2 = options2.get<1>();
+ const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
Subnet::OptionContainerTypeIndex::const_iterator> range2 =
idx2.equal_range(23);
@@ -718,11 +718,11 @@ TEST_F(Dhcp4ParserTest, optionDataLowerCase) {
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(1, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -761,11 +761,13 @@ TEST_F(Dhcp4ParserTest, stdOptionData) {
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(1, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index aec182a..dd50c30 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -1151,9 +1151,8 @@ private:
subnet_->addPool6(*it);
}
- // Get the options search index.
- const Subnet::OptionContainer& options = subnet_->getOptions();
- const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+ Subnet::OptionContainerPtr options = subnet_->getOptionDescriptors("dhcp6");
+ const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Add subnet specific options.
BOOST_FOREACH(Subnet::OptionDescriptor desc, options_) {
@@ -1162,7 +1161,7 @@ private:
LOG_WARN(dhcp6_logger, DHCP6_CONFIG_OPTION_DUPLICATE)
.arg(desc.option->getType()).arg(addr.toText());
}
- subnet_->addOption(desc.option);
+ subnet_->addOption(desc.option, false, "dhcp6");
}
// Check all global options and add them to the subnet object if
@@ -1172,6 +1171,8 @@ private:
BOOST_FOREACH(Subnet::OptionDescriptor desc, option_defaults) {
// Get all options specified locally in the subnet and having
// code equal to global option's code.
+ Subnet::OptionContainerPtr options = subnet_->getOptionDescriptors("dhcp6");
+ const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
Subnet::OptionContainerTypeRange range = idx.equal_range(desc.option->getType());
// @todo: In the future we will be searching for options using either
// an option code or namespace. Currently we have only the option
@@ -1182,7 +1183,7 @@ private:
// want to issue a warning about dropping the configuration of
// a global option if one already exsists.
if (std::distance(range.first, range.second) == 0) {
- subnet_->addOption(desc.option);
+ subnet_->addOption(desc.option, false, "dhcp6");
}
}
}
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index ad8fb8c..b90c33e 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
@@ -340,8 +340,8 @@ void 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();
// Get the list of options configured for a subnet.
- const Subnet::OptionContainer& options = subnet->getOptions();
- const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+ Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Try to match requested options with those configured for a subnet.
// If match is found, append configured option to the answer message.
BOOST_FOREACH(uint16_t opt, requested_opts) {
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index e40f4cc..be5bbf8 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -463,11 +463,11 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(2, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -541,11 +541,11 @@ TEST_F(Dhcp6ParserTest, optionDataInSingleSubnet) {
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(2, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -609,11 +609,11 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet1);
- const Subnet::OptionContainer& options1 = subnet1->getOptions();
- ASSERT_EQ(1, options1.size());
+ Subnet::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 Subnet::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
@@ -633,10 +633,10 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
// Test another subnet in the same way.
Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"));
ASSERT_TRUE(subnet2);
- const Subnet::OptionContainer& options2 = subnet2->getOptions();
- ASSERT_EQ(1, options2.size());
+ Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp6");
+ ASSERT_EQ(1, options2->size());
- const Subnet::OptionContainerTypeIndex& idx2 = options2.get<1>();
+ const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
Subnet::OptionContainerTypeIndex::const_iterator> range2 =
idx2.equal_range(101);
@@ -727,11 +727,11 @@ TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(1, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
@@ -769,11 +769,11 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet);
- const Subnet::OptionContainer& options = subnet->getOptions();
- ASSERT_EQ(1, options.size());
+ Subnet::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 Subnet::OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index b19ed21..a3921cc 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -74,6 +74,34 @@ LibDHCP::getOptionDef(const Option::Universe u, const uint16_t code) {
return (OptionDefinitionPtr());
}
+bool
+LibDHCP::isStandardOption(const Option::Universe u, const uint16_t code) {
+ if (u == Option::V6) {
+ if (code < 79 &&
+ code != 10 &&
+ code != 35) {
+ return (true);
+ }
+
+ } else if (u == Option::V4) {
+ if (!(code == 84 ||
+ code == 96 ||
+ (code > 101 && code < 112) ||
+ code == 115 ||
+ code == 126 ||
+ code == 127 ||
+ (code > 146 && code < 150) ||
+ (code > 177 && code < 208) ||
+ (code > 213 && code < 220) ||
+ (code > 221 && code < 224))) {
+ return (true);
+ }
+
+ }
+
+ return (false);
+}
+
OptionPtr
LibDHCP::optionFactory(Option::Universe u,
uint16_t type,
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index c325aa5..bc47405 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -55,6 +55,21 @@ public:
static OptionDefinitionPtr getOptionDef(const Option::Universe u,
const uint16_t code);
+ /// @brief Check if the specified option is a standard option.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param code option code.
+ ///
+ /// @return true if the specified option is a standard option.
+ /// @todo We arleady create option definitions for the subset if
+ /// standard options. We are aiming that this function checks
+ /// the presence of the standard option definition and if it finds
+ /// it, then the true value is returned. However, at this point
+ /// this is not doable because some of the definitions (for less
+ /// important options) are not created yet.
+ static bool isStandardOption(const Option::Universe u,
+ const uint16_t code);
+
/// @brief Factory function to create instance of option.
///
/// Factory method creates instance of specified option. The option
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index 468210f..efcaba0 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -42,6 +42,14 @@ public:
isc::Exception(file, line, what) { };
};
+/// @brief Exception to be thrown when the particular option definition
+/// duplicates existing option definition.
+class DuplicateOptionDefinition : public Exception {
+public:
+ DuplicateOptionDefinition(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
/// @brief Forward declaration to OptionDefinition.
class OptionDefinition;
@@ -492,6 +500,9 @@ typedef boost::multi_index_container<
>
> OptionDefContainer;
+/// Pointer to an option definition container.
+typedef boost::shared_ptr<OptionDefContainer> OptionDefContainerPtr;
+
/// Type of the index #1 - option type.
typedef OptionDefContainer::nth_index<1>::type OptionDefContainerTypeIndex;
/// Pair of iterators to represent the range of options definitions
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index e44ef58..a59da12 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -453,6 +453,66 @@ TEST_F(LibDhcpTest, unpackOptions4) {
EXPECT_TRUE(x == options.end()); // option 2 not found
}
+TEST_F(LibDhcpTest, isStandardOption4) {
+ // Get all option codes that are not occupied by standard options.
+ const uint16_t unassigned_codes[] = { 84, 96, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 115, 126, 127, 147, 148, 149,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195,
+ 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 214, 215, 216, 217, 218, 219,
+ 222, 223 };
+ const size_t unassigned_num = sizeof(unassigned_codes) / sizeof(unassigned_codes[0]);
+
+ // Try all possible option codes.
+ for (size_t i = 0; i < 256; ++i) {
+ // Some ranges of option codes are unassigned and thus the isStandardOption
+ // should return false for them.
+ bool check_unassigned = false;
+ // Check the array of unassigned options to find out whether option code
+ // is assigned to standard option or unassigned.
+ for (size_t j = 0; j < unassigned_num; ++j) {
+ // If option code is found within the array of unassigned options
+ // we the isStandardOption function should return false.
+ if (unassigned_codes[j] == i) {
+ check_unassigned = true;
+ EXPECT_FALSE(LibDHCP::isStandardOption(Option::V4,
+ unassigned_codes[j]))
+ << "Test failed for option code " << unassigned_codes[j];
+ break;
+ }
+ }
+ // If the option code belongs to the standard option then the
+ // isStandardOption should return true.
+ if (!check_unassigned) {
+ EXPECT_TRUE(LibDHCP::isStandardOption(Option::V4, i))
+ << "Test failed for the option code " << i;
+ }
+ }
+}
+
+TEST_F(LibDhcpTest, isStandardOption6) {
+ // All option codes in the range from 0 to 78 (except 10 and 35)
+ // identify the standard options.
+ for (uint16_t code = 0; code < 79; ++code) {
+ if (code != 10 && code != 35) {
+ EXPECT_TRUE(LibDHCP::isStandardOption(Option::V6, code))
+ << "Test failed for option code " << code;
+ }
+ }
+
+ // Check the option codes 10 and 35. They are unassigned.
+ EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, 10));
+ EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, 35));
+
+ // Check a range of option codes above 78. Those are option codes
+ // identifying non-standard options.
+ for (uint16_t code = 79; code < 512; ++code) {
+ EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, code))
+ << "Test failed for option code " << code;
+ }
+}
+
TEST_F(LibDhcpTest, stdOptionDefs4) {
// Create a buffer that holds dummy option data.
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index cd41b4e..ce28575 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <asiolink/io_address.h>
+#include <dhcp/libdhcp++.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_log.h>
@@ -28,6 +29,84 @@ CfgMgr::instance() {
return (cfg_mgr);
}
+void
+CfgMgr::addOptionDef(const OptionDefinitionPtr& def,
+ const std::string& option_space) {
+ // @todo we need better validation of the provided option space name here.
+ // This will be implemented when #2313 is merged.
+ if (option_space.empty()) {
+ isc_throw(BadValue, "option space name must not be empty");
+ } else if (!def) {
+ // Option definition must point to a valid object.
+ isc_throw(MalformedOptionDefinition, "option definition must not be NULL");
+
+ } else if (getOptionDef(option_space, def->getCode())) {
+ // Option definition must not be overriden.
+ isc_throw(DuplicateOptionDefinition, "option definition already added"
+ << " to option space " << option_space);
+
+ } else if ((option_space == "dhcp4" &&
+ LibDHCP::isStandardOption(Option::V4, def->getCode())) ||
+ (option_space == "dhcp6" &&
+ LibDHCP::isStandardOption(Option::V6, def->getCode()))) {
+ // We must not override standard (assigned) option. The standard options
+ // belong to dhcp4 or dhcp6 option space.
+ isc_throw(BadValue, "unable to override definition of option '"
+ << def->getCode() << "' in standard option space '"
+ << option_space << "'.");
+
+ }
+ // Get existing option definitions for the option space.
+ OptionDefContainerPtr defs = getOptionDefs(option_space);
+ // getOptionDefs always returns a valid pointer to
+ // the container. Let's make an assert to make sure.
+ assert(defs);
+ // Actually add the new definition.
+ defs->push_back(def);
+ option_def_spaces_[option_space] = defs;
+}
+
+OptionDefContainerPtr
+CfgMgr::getOptionDefs(const std::string& option_space) const {
+ // @todo Validate the option space once the #2313 is implemented.
+
+ // Get all option definitions for the particular option space.
+ const OptionDefsMap::const_iterator& defs =
+ option_def_spaces_.find(option_space);
+ // If there are no option definitions for the particular option space
+ // then return empty container.
+ if (defs == option_def_spaces_.end()) {
+ return (OptionDefContainerPtr(new OptionDefContainer()));
+ }
+ // If option definitions found, return them.
+ return (defs->second);
+}
+
+OptionDefinitionPtr
+CfgMgr::getOptionDef(const std::string& option_space,
+ const uint16_t option_code) const {
+ // @todo Validate the option space once the #2313 is implemented.
+
+ // Get a reference to option definitions for a particular option space.
+ OptionDefContainerPtr defs = getOptionDefs(option_space);
+ // If there are no matching option definitions then return the empty pointer.
+ if (!defs || defs->empty()) {
+ return (OptionDefinitionPtr());
+ }
+ // If there are some option definitions for a particular option space
+ // use an option code to get the one we want.
+ const OptionDefContainerTypeIndex& idx = defs->get<1>();
+ const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+ // If there is no definition that matches option code, return empty pointer.
+ if (std::distance(range.first, range.second) == 0) {
+ return (OptionDefinitionPtr());
+ }
+ // If there is more than one definition matching an option code, return
+ // the first one. This should not happen because we check for duplicates
+ // when addOptionDef is called.
+ return (*range.first);
+}
+
Subnet6Ptr
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
@@ -119,6 +198,10 @@ void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
subnets4_.push_back(subnet);
}
+void CfgMgr::deleteOptionDefs() {
+ option_def_spaces_.clear();
+}
+
void CfgMgr::deleteSubnets4() {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET4);
subnets4_.clear();
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index ac1b3f5..9628f24 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -17,6 +17,7 @@
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
#include <util/buffer.h>
@@ -77,6 +78,41 @@ public:
/// accessing it.
static CfgMgr& instance();
+ /// @brief Add new option definition.
+ ///
+ /// @param def option definition to be added.
+ /// @param option_space name of the option space to add definition to.
+ ///
+ /// @throw isc::dhcp::DuplicateOptionDefinition when the particular
+ /// option definition already exists.
+ /// @throw isc::dhcp::MalformedOptionDefinition when the pointer to
+ /// an option definition is NULL.
+ /// @throw isc::BadValue when the option space name is empty or
+ /// when trying to override the standard option (in dhcp4 or dhcp6
+ /// option space).
+ void addOptionDef(const OptionDefinitionPtr& def,
+ const std::string& option_space);
+
+ /// @brief Return option definitions for particular option space.
+ ///
+ /// @param option_space option space.
+ ///
+ /// @return pointer to the collection of option definitions for
+ /// the particular option space. The option collection is empty
+ /// if no option exists for the option space specified.
+ OptionDefContainerPtr
+ getOptionDefs(const std::string& option_space) const;
+
+ /// @brief Return option definition for a particular option space and code.
+ ///
+ /// @param option_space option space.
+ /// @param option_code option code.
+ ///
+ /// @return an option definition or NULL pointer if option definition
+ /// has not been found.
+ OptionDefinitionPtr getOptionDef(const std::string& option_space,
+ const uint16_t option_code) const;
+
/// @brief get IPv6 subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
@@ -86,6 +122,8 @@ public:
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
+ ///
+ /// @return a subnet object
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
/// @brief get IPv6 subnet by interface-id
@@ -93,12 +131,19 @@ public:
/// Another possibility to find a subnet is based on interface-id.
///
/// @param interface_id content of interface-id option returned by a relay
+ ///
+ /// @return a subnet object
/// @todo This method is not currently supported.
Subnet6Ptr getSubnet6(OptionPtr interface_id);
/// @brief adds an IPv6 subnet
+ ///
+ /// @param subnet new subnet to be added.
void addSubnet6(const Subnet6Ptr& subnet);
+ /// @brief Delete all option definitions.
+ void deleteOptionDefs();
+
/// @todo: Add subnet6 removal routines. Currently it is not possible
/// to remove subnets. The only case where subnet6 removal would be
/// needed is a dynamic server reconfiguration - a use case that is not
@@ -125,6 +170,8 @@ public:
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
+ ///
+ /// @return a subnet object
Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);
/// @brief adds a subnet4
@@ -141,6 +188,7 @@ public:
/// 192.0.2.0/23 and 192.0.2.0/24 the same subnet or is it something
/// completely new?
void deleteSubnets4();
+
protected:
/// @brief Protected constructor.
@@ -169,6 +217,19 @@ protected:
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet4Collection subnets4_;
+
+private:
+
+ /// A map containing option definitions for various option spaces.
+ /// They key of this map is the name of the option space. The
+ /// value is the the option container holding option definitions
+ /// for the particular option space.
+ typedef std::map<std::string, OptionDefContainerPtr> OptionDefsMap;
+
+ /// A map containing option definitions for different option spaces.
+ /// The map key holds an option space name.
+ OptionDefsMap option_def_spaces_;
+
};
} // namespace isc::dhcp
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index c23ecda..3f31130 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -44,14 +44,63 @@ bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
}
void
-Subnet::addOption(OptionPtr& option, bool persistent /* = false */) {
+Subnet::addOption(OptionPtr& option, bool persistent,
+ const std::string& option_space) {
+ // @todo Once the #2313 is merged we need to use the OptionSpace object to
+ // validate the option space name here. For now, let's check that the name
+ // is not empty as the empty namespace has a special meaning here - it is
+ // returned when desired namespace is not found when getOptions is called.
+ if (option_space.empty()) {
+ isc_throw(isc::BadValue, "option space name must not be empty");
+ }
validateOption(option);
- options_.push_back(OptionDescriptor(option, persistent));
+
+ OptionContainerPtr container = getOptionDescriptors(option_space);
+ // getOptionDescriptors is expected to return the pointer to the
+ // valid container. Let's make sure it does by performing an assert.
+ assert(container);
+ // Actually add the new descriptor.
+ container->push_back(OptionDescriptor(option, persistent));
+ option_spaces_[option_space] = container;
}
void
Subnet::delOptions() {
- options_.clear();
+ option_spaces_.clear();
+}
+
+Subnet::OptionContainerPtr
+Subnet::getOptionDescriptors(const std::string& option_space) const {
+ // Search the map to get the options container for the particular
+ // option space.
+ const OptionSpacesPtr::const_iterator& options =
+ option_spaces_.find(option_space);
+ // If the option space has not been found it means that no option
+ // has been configured for this option space yet. Thus we have to
+ // return an empty container to the caller.
+ if (options == option_spaces_.end()) {
+ // The default constructor creates an empty container.
+ return (OptionContainerPtr(new OptionContainer()));
+ }
+ // We found some option container for the option space specified.
+ // Let's return a const reference to it.
+ return (options->second);
+}
+
+Subnet::OptionDescriptor
+Subnet::getOptionDescriptor(const std::string& option_space,
+ const uint16_t option_code) {
+ OptionContainerPtr options = getOptionDescriptors(option_space);
+ 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);
}
std::string Subnet::toText() const {
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
index c7d7ac7..442369f 100644
--- a/src/lib/dhcpsrv/subnet.h
+++ b/src/lib/dhcpsrv/subnet.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -78,6 +78,9 @@ public:
: option(OptionPtr()), persistent(persist) {};
};
+ /// A pointer to option descriptor.
+ typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
+
/// @brief Extractor class to extract key with another key.
///
/// This class solves the problem of accessing index key values
@@ -198,6 +201,8 @@ public:
>
> 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
@@ -216,9 +221,11 @@ public:
/// @param option option instance.
/// @param persistent if true, send an option regardless if client
/// requested it or not.
+ /// @param option_space name of the option space to add an option to.
///
/// @throw isc::BadValue if invalid option provided.
- void addOption(OptionPtr& option, bool persistent = false);
+ void addOption(OptionPtr& option, bool persistent,
+ const std::string& option_space);
/// @brief Delete all options configured for the subnet.
void delOptions();
@@ -252,14 +259,24 @@ public:
return (t2_);
}
- /// @brief Return a collection of options.
+ /// @brief Return a collection of option descriptors.
///
- /// @return reference to collection of options configured for a subnet.
- /// The returned reference is valid as long as the Subnet object which
- /// returned it still exists.
- const OptionContainer& getOptions() const {
- return (options_);
- }
+ /// @param option_space name of the option space.
+ ///
+ /// @return pointer to collection of options configured for a subnet.
+ OptionContainerPtr
+ getOptionDescriptors(const std::string& option_space) const;
+
+ /// @brief Return single option descriptor.
+ ///
+ /// @param option_space name of the option space.
+ /// @param option_code code of the option to be returned.
+ ///
+ /// @return option descriptor found for the specified option space
+ /// and option code.
+ OptionDescriptor
+ getOptionDescriptor(const std::string& option_space,
+ const uint16_t option_code);
/// @brief returns the last address that was tried from this pool
///
@@ -353,9 +370,6 @@ protected:
/// @brief a tripet (min/default/max) holding allowed valid lifetime values
Triplet<uint32_t> valid_;
- /// @brief a collection of DHCP options configured for a subnet.
- OptionContainer options_;
-
/// @brief last allocated address
///
/// This is the last allocated address that was previously allocated from
@@ -366,6 +380,15 @@ protected:
/// that purpose it should be only considered a help that should not be
/// fully trusted.
isc::asiolink::IOAddress last_allocated_;
+
+private:
+
+ /// Container holding options grouped by option space names.
+ typedef std::map<std::string, OptionContainerPtr> OptionSpacesPtr;
+
+ /// @brief a collection of DHCP option spaces holding options
+ /// configured for a subnet.
+ OptionSpacesPtr option_spaces_;
};
/// @brief A configuration holder for IPv4 subnet.
diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
index 353d833..7f73ee3 100644
--- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
@@ -44,9 +44,171 @@ public:
~CfgMgrTest() {
CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().deleteSubnets6();
+ CfgMgr::instance().deleteOptionDefs();
}
};
+// This test verifies that multiple option definitions can be added
+// under different option spaces.
+TEST_F(CfgMgrTest, getOptionDefs) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+ // Create a set of option definitions with codes between 100 and 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ std::ostringstream option_name;
+ // Option name is unique, e.g. option-100, option-101 etc.
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ // Add option definition to "isc" option space.
+ // Option codes are not duplicated so expect no error
+ // when adding them.
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
+ }
+
+ // Create a set of option definitions with codes between 105 and 114 and
+ // add them to the different option space.
+ for (uint16_t code = 105; code < 115; ++code) {
+ std::ostringstream option_name;
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
+ }
+
+ // Sanity check that all 10 option definitions are there.
+ OptionDefContainerPtr option_defs1 = cfg_mgr.getOptionDefs("isc");
+ ASSERT_TRUE(option_defs1);
+ ASSERT_EQ(10, option_defs1->size());
+
+ // Iterate over all option definitions and check that they have
+ // valid codes. Also, their order should be the same as they
+ // were added (codes 100-109).
+ uint16_t code = 100;
+ for (OptionDefContainer::const_iterator it = option_defs1->begin();
+ it != option_defs1->end(); ++it, ++code) {
+ OptionDefinitionPtr def(*it);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Sanity check that all 10 option definitions are there.
+ OptionDefContainerPtr option_defs2 = cfg_mgr.getOptionDefs("abcde");
+ ASSERT_TRUE(option_defs2);
+ ASSERT_EQ(10, option_defs2->size());
+
+ // Check that the option codes are valid.
+ code = 105;
+ for (OptionDefContainer::const_iterator it = option_defs2->begin();
+ it != option_defs2->end(); ++it, ++code) {
+ OptionDefinitionPtr def(*it);
+ ASSERT_TRUE(def);
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Let's make one more check that the empty set is returned when
+ // invalid option space is used.
+ OptionDefContainerPtr option_defs3 = cfg_mgr.getOptionDefs("non-existing");
+ ASSERT_TRUE(option_defs3);
+ EXPECT_TRUE(option_defs3->empty());
+}
+
+// This test verifies that single option definition is correctly
+// returned with getOptionDef function.
+TEST_F(CfgMgrTest, getOptionDef) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+ // Create a set of option definitions with codes between 100 and 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ std::ostringstream option_name;
+ // Option name is unique, e.g. option-100, option-101 etc.
+ option_name << "option-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ // Add option definition to "isc" option space.
+ // Option codes are not duplicated so expect no error
+ // when adding them.
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
+ }
+
+ // Create a set of option definitions with codes between 105 and 114 and
+ // add them to the different option space.
+ for (uint16_t code = 105; code < 115; ++code) {
+ std::ostringstream option_name;
+ option_name << "option-other-" << code;
+ OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
+ "uint16"));
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
+ }
+
+ // Try to get option definitions one by one using all codes
+ // that we expect to be there.
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("isc", code);
+ ASSERT_TRUE(def);
+ // Check that the option name is in the format of 'option-[code]'.
+ // That way we make sure that the options that have the same codes
+ // within different option spaces are different.
+ std::ostringstream option_name;
+ option_name << "option-" << code;
+ EXPECT_EQ(option_name.str(), def->getName());
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Check that the option codes are valid.
+ for (uint16_t code = 105; code < 115; ++code) {
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("abcde", code);
+ ASSERT_TRUE(def);
+ // Check that the option name is in the format of 'option-other-[code]'.
+ // That way we make sure that the options that have the same codes
+ // within different option spaces are different.
+ std::ostringstream option_name;
+ option_name << "option-other-" << code;
+ EXPECT_EQ(option_name.str(), def->getName());
+
+ EXPECT_EQ(code, def->getCode());
+ }
+
+ // Check that an option definition can be added to the standard
+ // (dhcp4 and dhcp6) option spaces when the option code is not
+ // reserved by the standard option.
+ OptionDefinitionPtr def6(new OptionDefinition("option-foo", 79, "uint16"));
+ EXPECT_NO_THROW(cfg_mgr.addOptionDef(def6, "dhcp6"));
+
+ OptionDefinitionPtr def4(new OptionDefinition("option-foo", 222, "uint16"));
+ EXPECT_NO_THROW(cfg_mgr.addOptionDef(def4, "dhcp4"));
+
+ // Try to query the option definition from an non-existing
+ // option space and expect NULL pointer.
+ OptionDefinitionPtr def = cfg_mgr.getOptionDef("non-existing", 56);
+ EXPECT_FALSE(def);
+
+ // Try to get the non-existing option definition from an
+ // existing option space.
+ EXPECT_FALSE(cfg_mgr.getOptionDef("isc", 56));
+
+}
+
+// This test verifies that the function that adds new option definition
+// throws exceptions when arguments are invalid.
+TEST_F(CfgMgrTest, addOptionDefNegative) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+ // The option code 65 is reserved for standard options either in
+ // DHCPv4 or DHCPv6. Thus we expect that adding an option to this
+ // option space fails.
+ OptionDefinitionPtr def(new OptionDefinition("option-foo", 65, "uint16"));
+
+ // Try reserved option space names.
+ ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp4"), isc::BadValue);
+ ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp6"), isc::BadValue);
+ // Try empty option space name.
+ ASSERT_THROW(cfg_mgr.addOptionDef(def, ""), isc::BadValue);
+ // Try NULL option definition.
+ ASSERT_THROW(cfg_mgr.addOptionDef(OptionDefinitionPtr(), "isc"),
+ isc::dhcp::MalformedOptionDefinition);
+ // Try adding option definition twice and make sure that it
+ // fails on the second attempt.
+ ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
+ EXPECT_THROW(cfg_mgr.addOptionDef(def, "isc"), DuplicateOptionDefinition);
+}
// This test verifies if the configuration manager is able to hold and return
// valid leases
@@ -86,7 +248,6 @@ TEST_F(CfgMgrTest, subnet4) {
// This test verifies if the configuration manager is able to hold and return
// valid leases
-
TEST_F(CfgMgrTest, subnet6) {
CfgMgr& cfg_mgr = CfgMgr::instance();
diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc
index 9ebef9c..2fc9f7e 100644
--- a/src/lib/dhcpsrv/tests/subnet_unittest.cc
+++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -115,13 +115,15 @@ TEST(Subnet4Test, addInvalidOption) {
// Create option with invalid universe (V6 instead of V4).
// Attempt to add this option should result in exception.
OptionPtr option1(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
- EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+ EXPECT_THROW(subnet->addOption(option1, false, "dhcp4"),
+ isc::BadValue);
// Create NULL pointer option. Attempt to add NULL option
// should result in exception.
OptionPtr option2;
ASSERT_FALSE(option2);
- EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+ EXPECT_THROW(subnet->addOption(option2, false, "dhcp4"),
+ isc::BadValue);
}
// This test verifies that inRange() and inPool() methods work properly.
@@ -261,26 +263,59 @@ TEST(Subnet6Test, addOptions) {
// 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(subnet->addOption(option));
+ ASSERT_NO_THROW(subnet->addOption(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(subnet->addOption(option, false, "isc"));
}
// Get options from the Subnet and check if all 10 are there.
- Subnet::OptionContainer options = subnet->getOptions();
- ASSERT_EQ(10, options.size());
+ Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ ASSERT_TRUE(options);
+ ASSERT_EQ(10, options->size());
- // Validate codes of added options.
+ // Validate codes of options added to dhcp6 option space.
uint16_t expected_code = 100;
- for (Subnet::OptionContainer::const_iterator option_desc = options.begin();
- option_desc != options.end(); ++option_desc) {
+ for (Subnet::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 = subnet->getOptionDescriptors("isc");
+ ASSERT_TRUE(options);
+ ASSERT_EQ(7, options->size());
+
+ // Validate codes of options added to isc option space.
+ expected_code = 105;
+ for (Subnet::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 = subnet->getOptionDescriptors("abcd");
+ ASSERT_TRUE(options);
+ EXPECT_TRUE(options->empty());
+
+ // Delete options from all spaces.
subnet->delOptions();
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
+ // Make sure that all options have been removed.
+ options = subnet->getOptionDescriptors("dhcp6");
+ ASSERT_TRUE(options);
+ EXPECT_TRUE(options->empty());
+
+ options = subnet->getOptionDescriptors("isc");
+ ASSERT_TRUE(options);
+ EXPECT_TRUE(options->empty());
}
TEST(Subnet6Test, addNonUniqueOptions) {
@@ -292,19 +327,19 @@ TEST(Subnet6Test, addNonUniqueOptions) {
// 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(subnet->addOption(option));
+ ASSERT_NO_THROW(subnet->addOption(option, false, "dhcp6"));
}
}
// Sanity check that all options are there.
- Subnet::OptionContainer options = subnet->getOptions();
- ASSERT_EQ(20, options.size());
+ Subnet::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>();
+ Subnet::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.
+ // For each code we should get two instances of options->
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
Subnet::OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(code);
@@ -329,8 +364,8 @@ TEST(Subnet6Test, addNonUniqueOptions) {
subnet->delOptions();
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
+ options = subnet->getOptionDescriptors("dhcp6");
+ EXPECT_EQ(0, options->size());
}
TEST(Subnet6Test, addInvalidOption) {
@@ -342,13 +377,13 @@ TEST(Subnet6Test, addInvalidOption) {
// Create option with invalid universe (V4 instead of V6).
// Attempt to add this option should result in exception.
OptionPtr option1(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
- EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+ EXPECT_THROW(subnet->addOption(option1, false, "dhcp6"), isc::BadValue);
// Create NULL pointer option. Attempt to add NULL option
// should result in exception.
OptionPtr option2;
ASSERT_FALSE(option2);
- EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+ EXPECT_THROW(subnet->addOption(option2, false, "dhcp6"), isc::BadValue);
}
TEST(Subnet6Test, addPersistentOption) {
@@ -367,24 +402,24 @@ TEST(Subnet6Test, addPersistentOption) {
// 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(subnet->addOption(option, persistent));
+ ASSERT_NO_THROW(subnet->addOption(option, persistent, "dhcp6"));
}
// Get added options from the subnet.
- Subnet::OptionContainer options = subnet->getOptions();
+ Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
- // options.get<2> returns reference to container index #2. This
+ // 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>();
+ Subnet::OptionContainerPersistIndex& idx = options->get<2>();
- // Get all persistent options.
+ // Get all persistent options->
std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
Subnet::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.
+ // Get all non-persistent options->
std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
idx.equal_range(false);
@@ -393,8 +428,33 @@ TEST(Subnet6Test, addPersistentOption) {
subnet->delOptions();
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
+ options = subnet->getOptionDescriptors("dhcp6");
+ EXPECT_EQ(0, options->size());
+}
+
+TEST(Subnet6Test, getOptionDescriptor) {
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 56, 1, 2, 3, 4));
+
+ // 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(subnet->addOption(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.
+ Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("isc", code);
+ // Returned descriptor should contain NULL option ptr.
+ EXPECT_FALSE(desc.option);
+ // Now, try the valid option space.
+ desc = subnet->getOptionDescriptor("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 inRange() and inPool() methods work properly.
More information about the bind10-changes
mailing list