BIND 10 trac2269, updated. 938d8b3145666d6f7d7084668b0ee665b3458e4a [2269] Documentation update in progress
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Oct 1 14:47:49 UTC 2012
The branch, trac2269 has been updated
via 938d8b3145666d6f7d7084668b0ee665b3458e4a (commit)
via 680279e6e9ac7a15d23b8a4d6d03a391166a7c8b (commit)
via 6f29861b92742da34be9ae76968e82222b5bfd7d (commit)
from ff837bb1fc512920556a796c40cacc20407b165c (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 938d8b3145666d6f7d7084668b0ee665b3458e4a
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Oct 1 16:47:31 2012 +0200
[2269] Documentation update in progress
commit 680279e6e9ac7a15d23b8a4d6d03a391166a7c8b
Merge: ff837bb 6f29861
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Oct 1 15:32:19 2012 +0200
[2269] Merge branch 'trac2238' into trac2269
Conflicts:
src/lib/dhcp/tests/cfgmgr_unittest.cc
src/lib/dhcp/triplet.h
-----------------------------------------------------------------------
Summary of changes:
doc/devel/02-dhcp.dox | 23 ---
src/bin/dhcp6/config_parser.cc | 118 ++++++++++++++--
src/bin/dhcp6/config_parser.h | 15 ++
src/bin/dhcp6/dhcp6.dox | 80 +++++++++++
src/lib/dhcp/tests/Makefile.am | 3 +-
src/lib/dhcp/tests/cfgmgr_unittest.cc | 239 --------------------------------
src/lib/dhcp/tests/pool_unittest.cc | 109 +++++++++++++++
src/lib/dhcp/tests/subnet_unittest.cc | 114 +++++++++++++++
src/lib/dhcp/tests/triplet_unittest.cc | 104 ++++++++++++++
src/lib/dhcp/triplet.h | 2 +
10 files changed, 532 insertions(+), 275 deletions(-)
create mode 100644 src/bin/dhcp6/dhcp6.dox
create mode 100644 src/lib/dhcp/tests/pool_unittest.cc
create mode 100644 src/lib/dhcp/tests/subnet_unittest.cc
create mode 100644 src/lib/dhcp/tests/triplet_unittest.cc
-----------------------------------------------------------------------
diff --git a/doc/devel/02-dhcp.dox b/doc/devel/02-dhcp.dox
index 5217f73..a4bbff9 100644
--- a/doc/devel/02-dhcp.dox
+++ b/doc/devel/02-dhcp.dox
@@ -57,29 +57,6 @@
* that does not support msgq. That is useful for embedded environments.
* It may also be useful in validation.
*
- * @page dhcpv6 DHCPv6 Server Component
- *
- * BIND10 offers DHCPv6 server implementation. It is implemented as
- * b10-dhcp6 component. Its primary code is located in
- * isc::dhcp::Dhcpv6Srv class. It uses \ref libdhcp extensively,
- * especially lib::dhcp::Pkt6, isc::dhcp::Option and
- * isc::dhcp::IfaceMgr classes. Currently this code offers skeleton
- * functionality, i.e. it is able to receive and process incoming
- * requests and trasmit responses. However, it does not have database
- * management, so it returns only one, hardcoded lease to whoever asks
- * for it.
- *
- * DHCPv6 server component does not support relayed traffic yet, as
- * support for relay decapsulation is not implemented yet.
- *
- * DHCPv6 server component does not use BIND10 logging yet.
- *
- * @section dhcpv6Session BIND10 message queue integration
- *
- * DHCPv4 server component is now integrated with BIND10 message queue.
- * It follows the same principle as DHCPv4. See \ref dhcpv4Session for
- * details.
- *
* @page libdhcp libdhcp++
*
* @section libdhcpIntro Libdhcp++ Library Introduction
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index efe8d84..271c3b1 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -39,20 +39,33 @@ using namespace isc::asiolink;
namespace isc {
namespace dhcp {
-typedef boost::shared_ptr<Dhcp6ConfigParser> ParserPtr;
+/// @brief auxiliary type used for storing element name and its parser
typedef pair<string, ConstElementPtr> ConfigPair;
-typedef std::vector<ParserPtr> ParserCollection;
+
+/// @brief a factory method that will create a parser for a given element name
typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id);
+
+/// @brief a collection of factories that creates parsers for specified element names
typedef std::map<std::string, ParserFactory*> FactoryMap;
+
+/// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
typedef std::map<string, uint32_t> Uint32Storage;
-/// @brief That is a map with global parameters that will be used as defaults
-Uint32Storage uint32_defaults;
+/// @brief a collection of elements that store string values
typedef std::map<string, string> StringStorage;
-StringStorage string_defaults;
+/// @brief a collection of pools
+///
+/// That type is used as intermediate storage, when pools are parsed, but there is
+/// no subnet object created yet to store them.
typedef std::vector<Pool6Ptr> PoolStorage;
+/// @brief Global uint32 parameters that will be used as defaults.
+Uint32Storage uint32_defaults;
+
+/// @brief global string parameters that will be used as defaults.
+StringStorage string_defaults;
+
/// @brief a dummy configuration parser
///
/// It is a debugging parser. It does not configure anything,
@@ -74,6 +87,8 @@ public:
/// @brief builds parameter value
///
/// See \ref Dhcp6ConfigParser class for details.
+ ///
+ /// @param new_config pointer to the new configuration
virtual void build(ConstElementPtr new_config) {
std::cout << "Build for token: [" << param_name_ << "] = ["
<< value_->str() << "]" << std::endl;
@@ -109,7 +124,7 @@ protected:
ConstElementPtr value_;
};
-/// @brief Configuration parser for uint32 types
+/// @brief Configuration parser for uint32 parameters
///
/// This class is a generic parser that is able to handle any uint32 integer
/// type. By default it stores the value in external global container
@@ -117,19 +132,21 @@ protected:
/// in subnet config), it can be pointed to a different storage, using
/// setStorage() method. This class follows the parser interface, laid out
/// in its base class, \ref Dhcp6ConfigParser.
-
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcpv6-config-inherit page.
class Uint32Parser : public Dhcp6ConfigParser {
public:
/// @brief constructor for Uint32Parser
- /// @param param_name name of the parameter that is going to be parsed
+ /// @param param_name name of the configuration parameter being parsed
Uint32Parser(const std::string& param_name)
:storage_(&uint32_defaults), param_name_(param_name) {
}
/// @brief builds parameter value
///
- /// Parses configuration entry and stored it in storage. See
+ /// Parses configuration entry and stores it in a storage. See
/// \ref setStorage() for details.
///
/// @param value pointer to the content of parsed values
@@ -154,76 +171,153 @@ public:
virtual void commit() {
}
- /// @brief factory that constructs DummyParser objects
+ /// @brief factory that constructs Uint32Parser objects
///
/// @param param_name name of the parameter to be parsed
static Dhcp6ConfigParser* Factory(const std::string& param_name) {
return (new Uint32Parser(param_name));
}
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcpv6-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
void setStorage(Uint32Storage* storage) {
storage_ = storage;
}
protected:
+ /// pointer to the storage, where parsed value will be stored
Uint32Storage * storage_;
+
+ /// name of the parameter to be parsed
std::string param_name_;
+
+ /// the actual parsed value
uint32_t value_;
};
+/// @brief Configuration parser for string parameters
+///
+/// This class is a generic parser that is able to handle any string
+/// parameter. By default it stores the value in external global container
+/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref Dhcp6ConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcpv6-config-inherit page.
class StringParser : public Dhcp6ConfigParser {
public:
+
+ /// @brief constructor for StringParser
+ /// @param param_name name of the configuration parameter being parsed
StringParser(const std::string& param_name)
:storage_(&string_defaults), param_name_(param_name) {
}
+ /// @brief builds parameter value
+ ///
+ /// Parses configuration entry and stored it in storage. See
+ /// \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
virtual void build(ConstElementPtr value) {
value_ = value->str();
boost::erase_all(value_, "\"");
storage_->insert(pair<string, string>(param_name_, value_));
}
+ /// @brief does nothing
+ ///
+ /// This method is required for all parser. The value itself
+ /// is not commited anywhere. Higher level parsers are expected to
+ /// use values stored in the storage, e.g. renew-timer for a given
+ /// subnet is stored in subnet-specific storage. It is not commited
+ /// here, but is rather used by its parent parser when constructing
+ /// an object, e.g. the subnet.
virtual void commit() {
}
+ /// @brief factory that constructs StringParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
static Dhcp6ConfigParser* Factory(const std::string& param_name) {
return (new StringParser(param_name));
}
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcpv6-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
void setStorage(StringStorage * storage) {
storage_ = storage;
}
protected:
+ /// pointer to the storage, where parsed value will be stored
StringStorage * storage_;
+
+ /// name of the parameter to be parsed
std::string param_name_;
+
+ /// the actual parsed value
std::string value_;
};
+
+/// @brief parser for interface list definition
+///
+/// This parser handles Dhcp6/interface entry.
+/// It contains a list of network interfaces that the server listens on.
+/// In particular, it can contain an entry called "all" or "any" that
+/// designates all interfaces.
class InterfaceListConfigParser : public Dhcp6ConfigParser {
public:
+
+ /// @brief constructor
+ ///
+ /// As this is a dedicated parser, it must be used to parse
+ /// "interface" parameter only. All other types will throw exception.
+ ///
+ /// @param param_name name of the configuration parameter being parsed
InterfaceListConfigParser(const std::string& param_name) {
if (param_name != "interface") {
isc_throw(NotImplemented, "Internal error. Interface configuration "
"parser called for the wrong parameter: " << param_name);
}
}
+
+ /// @brief parses parameters value
+ ///
+ /// Parses configuration entry (list of parameters) and stores it in
+ /// storage. See \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
virtual void build(ConstElementPtr value) {
BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
interfaces_.push_back(iface->str());
}
}
+ /// @brief commits interfaces list configuration
virtual void commit() {
- /// @todo: Implement per interface listening. Currently always listening on all
- /// interfaces.
+ /// @todo: Implement per interface listening. Currently always listening
+ /// on all interfaces.
}
+ /// @brief factory that constructs InterfaceListConfigParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
static Dhcp6ConfigParser* Factory(const std::string& param_name) {
return (new InterfaceListConfigParser(param_name));
}
protected:
+ /// contains list of network interfaces
vector<string> interfaces_;
};
diff --git a/src/bin/dhcp6/config_parser.h b/src/bin/dhcp6/config_parser.h
index 5c941d5..79dae8d 100644
--- a/src/bin/dhcp6/config_parser.h
+++ b/src/bin/dhcp6/config_parser.h
@@ -28,6 +28,12 @@ class Dhcpv6Srv;
/// \c Dhcpv6Srv object.
class Dhcp6ConfigError : public isc::Exception {
public:
+
+/// @brief constructor
+///
+/// @param file name of the file, where exception occurred
+/// @param line line of the file, where exception occurred
+/// @param what text description of the issue that caused exception
Dhcp6ConfigError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
@@ -103,6 +109,15 @@ public:
virtual void commit() = 0;
};
+/// @brief a pointer to configuration parser
+typedef boost::shared_ptr<Dhcp6ConfigParser> ParserPtr;
+
+/// @brief a collection of parsers
+///
+/// This container is used to store pointer to parsers for a given scope.
+typedef std::vector<ParserPtr> ParserCollection;
+
+
/// Configure an \c Dhcpv6Srv object with a set of configuration values.
///
/// This function parses configuration information stored in \c config_set
diff --git a/src/bin/dhcp6/dhcp6.dox b/src/bin/dhcp6/dhcp6.dox
new file mode 100644
index 0000000..aafd4d6
--- /dev/null
+++ b/src/bin/dhcp6/dhcp6.dox
@@ -0,0 +1,80 @@
+/**
+ * @page dhcpv6 DHCPv6 Server Component
+ *
+ * BIND10 offers DHCPv6 server implementation. It is implemented as
+ * b10-dhcp6 component. Its primary code is located in
+ * isc::dhcp::Dhcpv6Srv class. It uses \ref libdhcp extensively,
+ * especially lib::dhcp::Pkt6, isc::dhcp::Option and
+ * isc::dhcp::IfaceMgr classes. Currently this code offers skeleton
+ * functionality, i.e. it is able to receive and process incoming
+ * requests and trasmit responses. However, it does not have database
+ * management, so it returns only one, hardcoded lease to whoever asks
+ * for it.
+ *
+ * DHCPv6 server component does not support relayed traffic yet, as
+ * support for relay decapsulation is not implemented yet.
+ *
+ * DHCPv6 server component does not use BIND10 logging yet.
+ *
+ * @section dhcpv6Session BIND10 message queue integration
+ *
+ * DHCPv4 server component is now integrated with BIND10 message queue.
+ * It follows the same principle as DHCPv4. See \ref dhcpv4Session for
+ * details.
+
+ @section dhcpv6-config-parser Configuration Parser in DHCPv6
+
+ b10-dhcp6 component uses BIND10 cfgmgr for commands and configuration. During
+ initial configuration (See \ref ControlledDhcpv6Srv::establishSession()),
+ the configuration handler callback is installed
+ (see ControlledDhcpv6Srv::dhcp6ConfigHandler(). It is called every time there
+ is a new configuration. In particular, it is called every time during daemon
+ start process. It contains a ConstElementPtr to a new configuration. This
+ simple handler calls \ref isc::dhcp::configureDhcp6Server() method that
+ processes received configuration.
+
+ This method iterates over list of received configuration elements and creates
+ a list of parsers for each received entry. Parser is an object that is derived
+ from a \ref Dhcp6ConfigParser class. Once a parser is created (constructor),
+ its value is set (using build() method). Once all parsers are build, the
+ configuration is then applied ("commited") and commit() method is called.
+
+ All parsers are defined in src/bin/dhcp6/config_parser.cc file. Some
+ of them are generic (e.g. \ref Uint32Parser that is able to handle
+ any unsigned 32 bit integer), but some are very specialized
+ (e.g. \ref Subnets6ListConfigParser parses definitions of Subnet6 lists). In
+ some cases, e.g. subnet6 definitions, the configuration entry is not a simple
+ value, but a map or a list itself. In such case, the parser iterates over
+ all elements and creates parsers for a given scope. This process may be
+ repeated (sort of) recursively.
+
+ @section dhcpv6-config-inherit DHCPv6 Configuration Inheritance
+
+ One notable useful features of DHCP configuration is its parameter inheritance.
+ For example, renew-timer value may be specified at a global scope and it
+ then applies to all subnets. However, some subnets may have it overwritten
+ with more specific values that takes precedence over global values that are
+ considered defaults. Some parsers (e.g. \ref Uint32ConfigParser and
+ \StringParser) implement that inheritance. By default, they store values in
+ global uint32_defaults and string_defaults storages. However, it is possible
+ to instruct them to store parsed values in more specific storages. That
+ capability is used, e.g. in \ref Subnet6ConfigParser that has its own storage
+ that is unique for each subnet. Finally, during commit phase (commit() method),
+ appropriate parsers can use apply parameter inheritance.
+
+ Debugging configuration parser may be confusing. Therefore there is a special
+ class called \ref DummyParser. It does not configure anything, but just accepts
+ any parameter of any type. If requested to commit configuration, it will print
+ out received parameter name and its value. This class is not currently used,
+ but it is convenient to have it every time a new parameter is added to DHCP
+ configuration. For that purpose it should be left in the code.
+
+ Parameter inheritance is done during reconfiguration phase, as reconfigurations
+ are rare, so extra logic here is not a problem. On the other hand, values of
+ those parameters may be used thousands times per second, so its use must be as
+ simple as possible. In fact, currently the code has to call Subnet6->getT1() and
+ do not implement any fancy inheritance logic.
+
+ */
+
+
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 70c87c8..9fd3492 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -41,7 +41,8 @@ libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
libdhcpsrv_unittests_SOURCES = run_unittests.cc
-libdhcpsrv_unittests_SOURCES += ../cfgmgr.cc ../cfgmgr.h cfgmgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc triplet_unittest.cc
+libdhcpsrv_unittests_SOURCES += pool_unittest.cc subnet_unittest.cc
libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
diff --git a/src/lib/dhcp/tests/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
index bdd9a37..7bd4823 100644
--- a/src/lib/dhcp/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcp/tests/cfgmgr_unittest.cc
@@ -32,245 +32,6 @@ using boost::scoped_ptr;
namespace {
-// constructor validation
-TEST(TripletTest, constructor) {
-
- const uint32_t min = 10;
- const uint32_t value = 20;
- const uint32_t max = 30;
-
- Triplet<uint32_t> x(min, value, max);
-
- EXPECT_EQ(min, x.getMin());
- EXPECT_EQ(value, x.get());
- EXPECT_EQ(max, x.getMax());
-
- // requested values below min should return allowed min value
- EXPECT_EQ(min, x.get(min - 5));
-
- EXPECT_EQ(min, x.get(min));
-
- // requesting a value from within the range (min < x < max) should
- // return the requested value
- EXPECT_EQ(17, x.get(17));
-
- EXPECT_EQ(max, x.get(max));
-
- EXPECT_EQ(max, x.get(max + 5));
-
- // this will be boring. It is expected to return 42 no matter what
- Triplet<uint32_t> y(42);
-
- EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
- EXPECT_EQ(42, y.get()); // it returns ...
- EXPECT_EQ(42, y.getMax()); // the exact value...
-
- // requested values below or above are ignore
- EXPECT_EQ(42, y.get(5)); // all...
- EXPECT_EQ(42, y.get(42)); // the...
- EXPECT_EQ(42, y.get(80)); // time!
-}
-
-// Triplets must be easy to use.
-// Simple to/from int conversions must be done on the fly.
-TEST(TripletTest, operator) {
-
- uint32_t x = 47;
-
- Triplet<uint32_t> foo(1,2,3);
- Triplet<uint32_t> bar(4,5,6);
-
- foo = bar;
-
- EXPECT_EQ(4, foo.getMin());
- EXPECT_EQ(5, foo.get());
- EXPECT_EQ(6, foo.getMax());
-
- // assignment operator: uint32_t => triplet
- Triplet<uint32_t> y(0);
- y = x;
-
- EXPECT_EQ(x, y.get());
-
- // let's try the other way around: triplet => uint32_t
- uint32_t z = 0;
- z = y;
-
- EXPECT_EQ(x, z);
-}
-
-// check if specified values are sane
-TEST(TripletTest, sanity_check) {
-
- // min is larger than default
- EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
-
- // max is smaller than default
- EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
-
-}
-
-TEST(Pool6Test, constructor_first_last) {
-
- // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
- IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"));
-
- EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
- EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
- EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
- pool1.getLastAddress());
-
- // This is Pool6, IPv4 addresses do not belong here
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
- IOAddress("192.168.0.5")), BadValue);
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
- IOAddress("2001:db8::1")), BadValue);
-
- // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
- // the other way around.
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
- IOAddress("2001:db8::1")), BadValue);
-}
-
-TEST(Pool6Test, constructor_prefix_len) {
-
- // let's construct 2001:db8:1::/96 pool
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
-
- EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
- EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
- EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
-
- // No such thing as /130 prefix
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
- BadValue);
-
- // /0 prefix does not make sense
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
- BadValue);
-
- // This is Pool6, IPv4 addresses do not belong here
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
- BadValue);
-}
-
-TEST(Pool6Test, in_range) {
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
- IOAddress("2001:db8:1::f"));
-
- EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
- EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
- EXPECT_FALSE(pool1.inRange(IOAddress("::")));
-}
-
-// This test creates 100 pools and verifies that their IDs are unique.
-TEST(Pool6Test, unique_id) {
-
- const int num_pools = 100;
- vector<Pool6Ptr> pools;
-
- for (int i = 0; i < num_pools; ++i) {
- pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
- IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"))));
- }
-
- for (int i = 0; i < num_pools; ++i) {
- for (int j = i + 1; j < num_pools; ++j) {
- if (pools[i]->getId() == pools[j]->getId()) {
- FAIL() << "Pool-ids must be unique";
- }
- }
- }
-
-}
-
-
-TEST(Subnet6Test, constructor) {
-
- EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
- 1, 2, 3, 4));
-
- EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
- BadValue); // invalid prefix length
- EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
- BadValue); // IPv4 addresses are not allowed in Subnet6
-}
-
-TEST(Subnet6Test, in_range) {
- Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
-
- EXPECT_EQ(1000, subnet.getT1());
- EXPECT_EQ(2000, subnet.getT2());
- EXPECT_EQ(3000, subnet.getPreferred());
- EXPECT_EQ(4000, subnet.getValid());
-
-
- EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
- EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
- EXPECT_FALSE(subnet.inRange(IOAddress("::")));
-}
-
-TEST(Subnet6Test, Pool6InSubnet6) {
-
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
- Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
- Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
-
- subnet->addPool6(pool1);
-
- // If there's only one pool, get that pool
- Pool6Ptr mypool = subnet->getPool6();
- EXPECT_EQ(mypool, pool1);
-
-
- subnet->addPool6(pool2);
- subnet->addPool6(pool3);
-
- // If there are more than one pool and we didn't provide hint, we
- // should get the first pool
- mypool = subnet->getPool6();
-
- EXPECT_EQ(mypool, pool1);
-
- // If we provide a hint, we should get a pool that this hint belongs to
- mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
-
- EXPECT_EQ(mypool, pool3);
-
-}
-
-TEST(Subnet6Test, Subnet6_Pool6_checks) {
-
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // this one is in subnet
- Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
- subnet->addPool6(pool1);
-
- // this one is larger than the subnet!
- Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
-
- EXPECT_THROW(subnet->addPool6(pool2), BadValue);
-
-
- // this one is totally out of blue
- Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
- EXPECT_THROW(subnet->addPool6(pool3), BadValue);
-
-
- Pool6Ptr pool4(new Pool6(Pool6::TYPE_IA, IOAddress("4001:db8:1::"), 80));
- EXPECT_THROW(subnet->addPool6(pool4), BadValue);
-}
-
// This test verifies if the configuration manager is able to hold and return
// valid leases
TEST(CfgMgrTest, subnet6) {
diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc
new file mode 100644
index 0000000..61d4c4a
--- /dev/null
+++ b/src/lib/dhcp/tests/pool_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2012 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 <iostream>
+#include <vector>
+#include <sstream>
+#include <gtest/gtest.h>
+#include <dhcp/pool.h>
+#include <asiolink/io_address.h>
+
+using boost::scoped_ptr;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+
+TEST(Pool6Test, constructor_first_last) {
+
+ // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"));
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
+ EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+ pool1.getLastAddress());
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+ IOAddress("192.168.0.5")), BadValue);
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ IOAddress("2001:db8::1")), BadValue);
+
+ // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
+ // the other way around.
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
+ IOAddress("2001:db8::1")), BadValue);
+}
+
+TEST(Pool6Test, constructor_prefix_len) {
+
+ // let's construct 2001:db8:1::/96 pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
+ EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
+
+ // No such thing as /130 prefix
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
+ BadValue);
+
+ // /0 prefix does not make sense
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
+ BadValue);
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
+ BadValue);
+}
+
+TEST(Pool6Test, in_range) {
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
+ IOAddress("2001:db8:1::f"));
+
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("::")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool6Test, unique_id) {
+
+ const int num_pools = 100;
+ std::vector<Pool6Ptr> pools;
+
+ for (int i = 0; i < num_pools; ++i) {
+ pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"))));
+ }
+
+ for (int i = 0; i < num_pools; ++i) {
+ for (int j = i + 1; j < num_pools; ++j) {
+ if (pools[i]->getId() == pools[j]->getId()) {
+ FAIL() << "Pool-ids must be unique";
+ }
+ }
+ }
+
+}
+
+}; // end of anonymous namespace
+
diff --git a/src/lib/dhcp/tests/subnet_unittest.cc b/src/lib/dhcp/tests/subnet_unittest.cc
new file mode 100644
index 0000000..4ea2c70
--- /dev/null
+++ b/src/lib/dhcp/tests/subnet_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright (C) 2012 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/subnet.h>
+#include <exceptions/exceptions.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+#include <asiolink/io_address.h>
+
+// don't import the entire boost namespace. It will unexpectedly hide uint8_t
+// for some systems.
+using boost::scoped_ptr;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+
+TEST(Subnet6Test, constructor) {
+
+ EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
+ 1, 2, 3, 4));
+
+ EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
+ BadValue); // invalid prefix length
+ EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
+ BadValue); // IPv4 addresses are not allowed in Subnet6
+}
+
+TEST(Subnet6Test, in_range) {
+ Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
+
+ EXPECT_EQ(1000, subnet.getT1());
+ EXPECT_EQ(2000, subnet.getT2());
+ EXPECT_EQ(3000, subnet.getPreferred());
+ EXPECT_EQ(4000, subnet.getValid());
+
+
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("::")));
+}
+
+TEST(Subnet6Test, Pool6InSubnet6) {
+
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+ Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
+ Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
+
+ subnet->addPool6(pool1);
+
+ // If there's only one pool, get that pool
+ Pool6Ptr mypool = subnet->getPool6();
+ EXPECT_EQ(mypool, pool1);
+
+
+ subnet->addPool6(pool2);
+ subnet->addPool6(pool3);
+
+ // If there are more than one pool and we didn't provide hint, we
+ // should get the first pool
+ mypool = subnet->getPool6();
+
+ EXPECT_EQ(mypool, pool1);
+
+ // If we provide a hint, we should get a pool that this hint belongs to
+ mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
+
+ EXPECT_EQ(mypool, pool3);
+
+}
+
+TEST(Subnet6Test, Subnet6_Pool6_checks) {
+
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // this one is in subnet
+ Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+ subnet->addPool6(pool1);
+
+ // this one is larger than the subnet!
+ Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
+
+ EXPECT_THROW(subnet->addPool6(pool2), BadValue);
+
+
+ // this one is totally out of blue
+ Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
+ EXPECT_THROW(subnet->addPool6(pool3), BadValue);
+
+
+ Pool6Ptr pool4(new Pool6(Pool6::TYPE_IA, IOAddress("4001:db8:1::"), 80));
+ EXPECT_THROW(subnet->addPool6(pool4), BadValue);
+}
+
+};
diff --git a/src/lib/dhcp/tests/triplet_unittest.cc b/src/lib/dhcp/tests/triplet_unittest.cc
new file mode 100644
index 0000000..727eb8a
--- /dev/null
+++ b/src/lib/dhcp/tests/triplet_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright (C) 2012 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 <stdint.h>
+#include <gtest/gtest.h>
+#include <dhcp/triplet.h>
+#include <exceptions/exceptions.h>
+
+using namespace isc::dhcp;
+using namespace isc;
+
+namespace {
+
+// constructor validation
+TEST(TripletTest, constructor) {
+
+ const uint32_t min = 10;
+ const uint32_t value = 20;
+ const uint32_t max = 30;
+
+ Triplet<uint32_t> x(min, value, max);
+
+ EXPECT_EQ(min, x.getMin());
+ EXPECT_EQ(value, x.get());
+ EXPECT_EQ(max, x.getMax());
+
+ // requested values below min should return allowed min value
+ EXPECT_EQ(min, x.get(min - 5));
+
+ EXPECT_EQ(min, x.get(min));
+
+ // requesting a value from within the range (min < x < max) should
+ // return the requested value
+ EXPECT_EQ(17, x.get(17));
+
+ EXPECT_EQ(max, x.get(max));
+
+ EXPECT_EQ(max, x.get(max + 5));
+
+ // this will be boring. It is expected to return 42 no matter what
+ Triplet<uint32_t> y(42);
+
+ EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
+ EXPECT_EQ(42, y.get()); // it returns ...
+ EXPECT_EQ(42, y.getMax()); // the exact value...
+
+ // requested values below or above are ignore
+ EXPECT_EQ(42, y.get(5)); // all...
+ EXPECT_EQ(42, y.get(42)); // the...
+ EXPECT_EQ(42, y.get(80)); // time!
+}
+
+// Triplets must be easy to use.
+// Simple to/from int conversions must be done on the fly.
+TEST(TripletTest, operator) {
+
+ uint32_t x = 47;
+
+ Triplet<uint32_t> foo(1,2,3);
+ Triplet<uint32_t> bar(4,5,6);
+
+ foo = bar;
+
+ EXPECT_EQ(4, foo.getMin());
+ EXPECT_EQ(5, foo.get());
+ EXPECT_EQ(6, foo.getMax());
+
+ // assignment operator: uint32_t => triplet
+ Triplet<uint32_t> y(0);
+ y = x;
+
+ EXPECT_EQ(x, y.get());
+
+ // let's try the other way around: triplet => uint32_t
+ uint32_t z = 0;
+ z = y;
+
+ EXPECT_EQ(x, z);
+}
+
+// check if specified values are sane
+TEST(TripletTest, sanity_check) {
+
+ // min is larger than default
+ EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
+
+ // max is smaller than default
+ EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
+
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcp/triplet.h b/src/lib/dhcp/triplet.h
index f5fa20b..d9388fe 100644
--- a/src/lib/dhcp/triplet.h
+++ b/src/lib/dhcp/triplet.h
@@ -15,6 +15,8 @@
#ifndef TRIPLET_H
#define TRIPLET_H
+#include <exceptions/exceptions.h>
+
namespace isc {
namespace dhcp {
More information about the bind10-changes
mailing list