BIND 10 master, updated. a66dc23ea5d6c6ecd34d9598d7e111d1c0ce696d [master] Added entry 731 for Trac 3033.
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Jan 15 13:48:43 UTC 2014
The branch, master has been updated
via a66dc23ea5d6c6ecd34d9598d7e111d1c0ce696d (commit)
via 0ba859834503f2b9b908cd7bc572e0286ca9201f (commit)
via e50f125ad256d2622c73c2df4448489e818a86e0 (commit)
via fb678e639cd130cc718cff735e351f019d0c9164 (commit)
via 6625b4d9366bd09afc859e88e41d7197c9b7ba06 (commit)
via b9063db0e6dac5389202131438a4b99a396740fc (commit)
via d508d4ac19b7260805fa0838ea627f2f05b960c5 (commit)
from 1e8fea4a8987ece65543c5f30f09cdc4d5dc5746 (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 a66dc23ea5d6c6ecd34d9598d7e111d1c0ce696d
Author: Thomas Markwalder <tmark at isc.org>
Date: Wed Jan 15 08:48:14 2014 -0500
[master] Added entry 731 for Trac 3033.
commit 0ba859834503f2b9b908cd7bc572e0286ca9201f
Merge: 1e8fea4 e50f125
Author: Thomas Markwalder <tmark at isc.org>
Date: Wed Jan 15 08:33:54 2014 -0500
[master] Merge branch 'trac3033'
Adds support for DHCP-DDNS configuration parameters to b10-dhcp4.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 +
configure.ac | 1 +
src/bin/dhcp4/config_parser.cc | 10 +-
src/bin/dhcp4/dhcp4.spec | 98 ++++++-
src/bin/dhcp4/tests/config_parser_unittest.cc | 131 ++++++++-
.../dhcp4}/tests/test_data_files_config.h.in | 7 +-
src/lib/dhcp_ddns/ncr_io.cc | 30 ++
src/lib/dhcp_ddns/ncr_io.h | 29 ++
src/lib/dhcp_ddns/ncr_msg.cc | 21 ++
src/lib/dhcp_ddns/ncr_msg.h | 19 ++
src/lib/dhcp_ddns/tests/ncr_unittests.cc | 23 +-
src/lib/dhcpsrv/Makefile.am | 2 +
src/lib/dhcpsrv/cfgmgr.cc | 19 +-
src/lib/dhcpsrv/cfgmgr.h | 22 ++
src/lib/dhcpsrv/d2_client.cc | 185 ++++++++++++
src/lib/dhcpsrv/d2_client.h | 278 ++++++++++++++++++
src/lib/dhcpsrv/dhcp_parsers.cc | 106 ++++++-
src/lib/dhcpsrv/dhcp_parsers.h | 76 ++++-
src/lib/dhcpsrv/dhcpsrv_messages.mes | 3 +
src/lib/dhcpsrv/tests/Makefile.am | 2 +
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc | 6 +-
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc | 46 ++-
src/lib/dhcpsrv/tests/d2_client_unittest.cc | 294 ++++++++++++++++++++
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc | 285 ++++++++++++++++++-
.../dhcpsrv/tests/memfile_lease_mgr_unittest.cc | 4 +-
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc | 24 +-
26 files changed, 1683 insertions(+), 46 deletions(-)
copy src/{hooks/dhcp/user_chk => bin/dhcp4}/tests/test_data_files_config.h.in (83%)
create mode 100644 src/lib/dhcpsrv/d2_client.cc
create mode 100644 src/lib/dhcpsrv/d2_client.h
create mode 100644 src/lib/dhcpsrv/tests/d2_client_unittest.cc
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 9bd379a..a1784e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+731. [func] tmark
+ b10-dhcp4 now parses parameters which support DHCP-DDNS updates via
+ the DHCP-DDNS module, b10-dhcp-ddns. These parameters are part of new
+ configuration element, dhcp-ddns, defined in dhcp4.spec. The parameters
+ parse, store and retrieve but do not yet govern behavior. That will be
+ provided under separate ticket.
+ (Trac# 3033, git 0ba859834503f2b9b908cd7bc572e0286ca9201f)
+
730. [bug] tomek
b10-dhcp4, b10-dhcp6: Both servers used to unnecessarily increase
subnet-id values after reconfiguration. The subnet-ids are now reset
diff --git a/configure.ac b/configure.ac
index afa9ade..336fbdc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1389,6 +1389,7 @@ AC_CONFIG_FILES([compatcheck/Makefile
src/bin/dhcp4/spec_config.h.pre
src/bin/dhcp4/tests/Makefile
src/bin/dhcp4/tests/marker_file.h
+ src/bin/dhcp4/tests/test_data_files_config.h
src/bin/dhcp4/tests/test_libraries.h
src/bin/dhcp6/Makefile
src/bin/dhcp6/spec_config.h.pre
diff --git a/src/bin/dhcp4/config_parser.cc b/src/bin/dhcp4/config_parser.cc
index 0e45fde..ea9323b 100644
--- a/src/bin/dhcp4/config_parser.cc
+++ b/src/bin/dhcp4/config_parser.cc
@@ -396,6 +396,8 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("echo-client-id") == 0) {
parser = new BooleanParser(config_id, globalContext()->boolean_values_);
+ } else if (config_id.compare("dhcp-ddns") == 0) {
+ parser = new D2ClientConfigParser(config_id);
} else {
isc_throw(NotImplemented,
"Parser error: Global configuration parameter not supported: "
@@ -452,7 +454,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Some of the parsers alter the state of the system in a way that can't
// easily be undone. (Or alter it in a way such that undoing the change has
// the same risk of failure as doing the change.)
- ParserPtr hooks_parser_;
+ ParserPtr hooks_parser;
// The subnet parsers implement data inheritance by directly
// accessing global storage. For this reason the global data
@@ -493,7 +495,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Executing commit will alter currently-loaded hooks
// libraries. Check if the supplied libraries are valid,
// but defer the commit until everything else has committed.
- hooks_parser_ = parser;
+ hooks_parser = parser;
parser->build(config_pair.second);
} else {
// Those parsers should be started before other
@@ -561,8 +563,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// This occurs last as if it succeeds, there is no easy way
// revert it. As a result, the failure to commit a subsequent
// change causes problems when trying to roll back.
- if (hooks_parser_) {
- hooks_parser_->commit();
+ if (hooks_parser) {
+ hooks_parser->commit();
}
}
catch (const isc::Exception& ex) {
diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec
index 9372dfd..c6d2c32 100644
--- a/src/bin/dhcp4/dhcp4.spec
+++ b/src/bin/dhcp4/dhcp4.spec
@@ -292,7 +292,103 @@
}
} ]
}
- }
+ },
+
+ { "item_name": "dhcp-ddns",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {"enable-updates": false},
+ "item_description" : "Contains parameters pertaining DHCP-driven DDNS updates",
+ "map_item_spec": [
+ {
+ "item_name": "enable-updates",
+ "item_type": "boolean",
+ "item_optional": false,
+ "item_default": false,
+ "item_description" : "Enables DDNS update processing"
+ },
+ {
+ "item_name": "server-ip",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "127.0.0.1",
+ "item_description" : "IP address of b10-dhcp-ddns (IPv4 or IPv6)"
+ },
+ {
+ "item_name": "server-port",
+ "item_type": "integer",
+ "item_optional": true,
+ "item_default": 53001,
+ "item_description" : "port number of b10-dhcp-ddns"
+ },
+ {
+ "item_name": "ncr-protocol",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "UDP",
+ "item_description" : "Socket protocol to use with b10-dhcp-ddns"
+ },
+ {
+ "item_name": "ncr-format",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "JSON",
+ "item_description" : "Format of the update request packet"
+ },
+ {
+ "item_name": "remove-on-renew",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Enable requesting a DNS Remove, before a DNS Update on renewals"
+ },
+ {
+
+ "item_name": "always-include-fqdn",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Enable always including the FQDN option in its response"
+ },
+ {
+ "item_name": "override-no-update",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Do update, even if client requested no updates with N flag"
+ },
+ {
+ "item_name": "override-client-update",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Server performs an update even if client requested delegation"
+ },
+ {
+ "item_name": "replace-client-name",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": false,
+ "item_description": "Should server replace the domain-name supplied by the client"
+ },
+ {
+ "item_name": "generated-prefix",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "myhost",
+ "item_description": "Prefix to use when generating the client's name"
+ },
+
+ {
+ "item_name": "qualifying-suffix",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "example.com",
+ "item_description": "Fully qualified domain-name suffix if partial name provided by client"
+ },
+ ]
+ },
+
],
"commands": [
{
diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc
index 433a612..14c4f80 100644
--- a/src/bin/dhcp4/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp4/tests/config_parser_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -30,6 +30,7 @@
#include "marker_file.h"
#include "test_libraries.h"
+#include "test_data_files_config.h"
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
@@ -50,6 +51,23 @@ using namespace std;
namespace {
+/// @brief Prepends the given name with the DHCP4 source directory
+///
+/// @param name file name of the desired file
+/// @return string containing the absolute path of the file in the DHCP source
+/// directory.
+std::string specfile(const std::string& name) {
+ return (std::string(DHCP4_SRC_DIR) + "/" + name);
+}
+
+/// @brief Tests that the spec file is valid.
+/// Verifies that the BIND10 DHCP-DDNS configuration specification file
+// is valid.
+TEST(Dhcp4SpecTest, basicSpec) {
+ (isc::config::moduleSpecFromFile(specfile("dhcp4.spec")));
+ ASSERT_NO_THROW(isc::config::moduleSpecFromFile(specfile("dhcp4.spec")));
+}
+
class Dhcp4ParserTest : public ::testing::Test {
public:
Dhcp4ParserTest()
@@ -321,6 +339,7 @@ public:
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000, "
"\"subnet4\": [ ], "
+ "\"dhcp-ddns\": { \"enable-updates\" : false }, "
"\"option-def\": [ ], "
"\"option-data\": [ ] }";
static_cast<void>(executeConfiguration(config,
@@ -2486,6 +2505,116 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
}
+// This test checks the ability of the server to parse a configuration
+// containing a full, valid dhcp-ddns (D2ClientConfig) entry.
+TEST_F(Dhcp4ParserTest, d2ClientConfig) {
+ ConstElementPtr status;
+
+ // Verify that the D2 configuraiton can be fetched and is set to disabled.
+ D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+ // Verify that the convenience method agrees.
+ ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+ string config_str = "{ \"interfaces\": [ \"*\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ " \"dhcp-ddns\" : {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.168.2.1\", "
+ " \"server-port\" : 777, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"allow-client-update\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" },"
+ "\"valid-lifetime\": 4000 }";
+
+ // Convert the JSON string to configuration elements.
+ ElementPtr config;
+ ASSERT_NO_THROW(config = Element::fromJSON(config_str));
+
+ // Pass the configuration in for parsing.
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));
+
+ // check if returned status is OK
+ checkResult(status, 0);
+
+ // Verify that DHCP-DDNS updating is enabled.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+
+ // Verify that the D2 configuration can be retrieved.
+ d2_client_config = CfgMgr::instance().getD2ClientConfig();
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the configuration values are correct.
+ EXPECT_TRUE(d2_client_config->getEnableUpdates());
+ EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText());
+ EXPECT_EQ(777, d2_client_config->getServerPort());
+ EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
+ EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
+ EXPECT_TRUE(d2_client_config->getRemoveOnRenew());
+ EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());
+ EXPECT_TRUE(d2_client_config->getOverrideNoUpdate());
+ EXPECT_TRUE(d2_client_config->getOverrideClientUpdate());
+ EXPECT_TRUE(d2_client_config->getReplaceClientName());
+ EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
+ EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
+}
+
+// This test checks the ability of the server to handle a configuration
+// containing an invalid dhcp-ddns (D2ClientConfig) entry.
+TEST_F(Dhcp4ParserTest, invalidD2ClientConfig) {
+ ConstElementPtr status;
+
+ // Configuration string with an invalid D2 client config,
+ // "server-ip" is missing.
+ string config_str = "{ \"interfaces\": [ \"*\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ " \"dhcp-ddns\" : {"
+ " \"enable-updates\" : true, "
+ " \"server-port\" : 5301, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"allow-client-update\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" },"
+ "\"valid-lifetime\": 4000 }";
+
+ // Convert the JSON string to configuration elements.
+ ElementPtr config;
+ ASSERT_NO_THROW(config = Element::fromJSON(config_str));
+
+ // Configuration should not throw, but should fail.
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));
+ // check if returned status is failed.
+ checkResult(status, 1);
+
+ // Verify that the D2 configuraiton can be fetched and is set to disabled.
+ D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+ // Verify that the convenience method agrees.
+ ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
+}
}
diff --git a/src/bin/dhcp4/tests/test_data_files_config.h.in b/src/bin/dhcp4/tests/test_data_files_config.h.in
new file mode 100644
index 0000000..0b778cf
--- /dev/null
+++ b/src/bin/dhcp4/tests/test_data_files_config.h.in
@@ -0,0 +1,17 @@
+// Copyright (C) 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
+// 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.
+
+/// @brief Path to dhcp4 source dir so tests against the dhcp4.spec file
+/// can find it reliably.
+#define DHCP4_SRC_DIR "@abs_top_srcdir@/src/bin/dhcp4"
diff --git a/src/lib/dhcp_ddns/ncr_io.cc b/src/lib/dhcp_ddns/ncr_io.cc
index 4f3f1d7..7e7174a 100644
--- a/src/lib/dhcp_ddns/ncr_io.cc
+++ b/src/lib/dhcp_ddns/ncr_io.cc
@@ -15,9 +15,39 @@
#include <dhcp_ddns/dhcp_ddns_log.h>
#include <dhcp_ddns/ncr_io.h>
+#include <boost/algorithm/string/predicate.hpp>
+
namespace isc {
namespace dhcp_ddns {
+NameChangeProtocol stringToNcrProtocol(const std::string& protocol_str) {
+ if (boost::iequals(protocol_str, "UDP")) {
+ return (NCR_UDP);
+ }
+
+ if (boost::iequals(protocol_str, "TCP")) {
+ return (NCR_TCP);
+ }
+
+ isc_throw(BadValue, "Invalid NameChangeRequest protocol:" << protocol_str);
+}
+
+std::string ncrProtocolToString(NameChangeProtocol protocol) {
+ switch (protocol) {
+ case NCR_UDP:
+ return ("UDP");
+ case NCR_TCP:
+ return ("TCP");
+ default:
+ break;
+ }
+
+ std::ostringstream stream;
+ stream << "UNKNOWN(" << protocol << ")";
+ return (stream.str());
+}
+
+
//************************** NameChangeListener ***************************
NameChangeListener::NameChangeListener(RequestReceiveHandler&
diff --git a/src/lib/dhcp_ddns/ncr_io.h b/src/lib/dhcp_ddns/ncr_io.h
index 94d08f7..a5e513a 100644
--- a/src/lib/dhcp_ddns/ncr_io.h
+++ b/src/lib/dhcp_ddns/ncr_io.h
@@ -66,6 +66,35 @@
namespace isc {
namespace dhcp_ddns {
+/// @brief Defines the list of socket protocols supported.
+/// Currently only UDP is implemented.
+/// @todo TCP is intended to be implemented prior 1.0 release.
+/// @todo Give some thought to an ANY protocol which might try
+/// first as UDP then as TCP, etc.
+enum NameChangeProtocol {
+ NCR_UDP,
+ NCR_TCP
+};
+
+/// @brief Function which converts labels to NameChangeProtocol enum values.
+///
+/// @param protocol_str text to convert to an enum.
+/// Valid string values: "UDP", "TCP"
+///
+/// @return NameChangeProtocol value which maps to the given string.
+///
+/// @throw isc::BadValue if given a string value which does not map to an
+/// enum value.
+extern NameChangeProtocol stringToNcrProtocol(const std::string& protocol_str);
+
+/// @brief Function which converts NameChangeProtocol enums to text labels.
+///
+/// @param protocol enum value to convert to label
+///
+/// @return std:string containing the text label if the value is valid, or
+/// "UNKNOWN" if not.
+extern std::string ncrProtocolToString(NameChangeProtocol protocol);
+
/// @brief Exception thrown if an NcrListenerError encounters a general error.
class NcrListenerError : public isc::Exception {
public:
diff --git a/src/lib/dhcp_ddns/ncr_msg.cc b/src/lib/dhcp_ddns/ncr_msg.cc
index 418eaa0..13bc5bc 100644
--- a/src/lib/dhcp_ddns/ncr_msg.cc
+++ b/src/lib/dhcp_ddns/ncr_msg.cc
@@ -18,15 +18,36 @@
#include <asiolink/io_error.h>
#include <cryptolink/cryptolink.h>
+#include <boost/algorithm/string/predicate.hpp>
#include <botan/sha2_32.h>
#include <sstream>
#include <limits>
+
namespace isc {
namespace dhcp_ddns {
+NameChangeFormat stringToNcrFormat(const std::string& fmt_str) {
+ if (boost::iequals(fmt_str, "JSON")) {
+ return FMT_JSON;
+ }
+
+ isc_throw(BadValue, "Invalid NameChangeRequest format:" << fmt_str);
+}
+
+
+std::string ncrFormatToString(NameChangeFormat format) {
+ if (format == FMT_JSON) {
+ return ("JSON");
+ }
+
+ std::ostringstream stream;
+ stream << "UNKNOWN(" << format << ")";
+ return (stream.str());
+}
+
/********************************* D2Dhcid ************************************/
namespace {
diff --git a/src/lib/dhcp_ddns/ncr_msg.h b/src/lib/dhcp_ddns/ncr_msg.h
index 47a7be6..5dab9e8 100644
--- a/src/lib/dhcp_ddns/ncr_msg.h
+++ b/src/lib/dhcp_ddns/ncr_msg.h
@@ -70,6 +70,25 @@ enum NameChangeFormat {
FMT_JSON
};
+/// @brief Function which converts labels to NameChangeFormat enum values.
+///
+/// @param format_str text to convert to an enum.
+/// Valid string values: "JSON"
+///
+/// @return NameChangeFormat value which maps to the given string.
+///
+/// @throw isc::BadValue if given a string value which does not map to an
+/// enum value.
+extern NameChangeFormat stringToNcrFormat(const std::string& fmt_str);
+
+/// @brief Function which converts NameChangeFormat enums to text labels.
+///
+/// @param format enum value to convert to label
+///
+/// @return std:string containing the text label if the value is valid, or
+/// "UNKNOWN" if not.
+extern std::string ncrFormatToString(NameChangeFormat format);
+
/// @brief Container class for handling the DHCID value within a
/// NameChangeRequest. It provides conversion to and from string for JSON
/// formatting, but stores the data internally as unsigned bytes.
diff --git a/src/lib/dhcp_ddns/tests/ncr_unittests.cc b/src/lib/dhcp_ddns/tests/ncr_unittests.cc
index 9386a5f..c66b891 100644
--- a/src/lib/dhcp_ddns/tests/ncr_unittests.cc
+++ b/src/lib/dhcp_ddns/tests/ncr_unittests.cc
@@ -12,7 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <dhcp_ddns/ncr_msg.h>
+#include <dhcp_ddns/ncr_io.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <util/time_utilities.h>
@@ -608,5 +608,26 @@ TEST(NameChangeRequestTest, ipAddresses) {
ASSERT_THROW(ncr.setIpAddress("x001:1::f3"),NcrMessageError);
}
+/// @brief Tests conversion of NameChangeFormat between enum and strings.
+TEST(NameChangeFormatTest, formatEnumConversion){
+ ASSERT_EQ(stringToNcrFormat("JSON"), dhcp_ddns::FMT_JSON);
+ ASSERT_EQ(stringToNcrFormat("jSoN"), dhcp_ddns::FMT_JSON);
+ ASSERT_THROW(stringToNcrFormat("bogus"), isc::BadValue);
+
+ ASSERT_EQ(ncrFormatToString(dhcp_ddns::FMT_JSON), "JSON");
+}
+
+/// @brief Tests conversion of NameChangeProtocol between enum and strings.
+TEST(NameChangeProtocolTest, protocolEnumConversion){
+ ASSERT_EQ(stringToNcrProtocol("UDP"), dhcp_ddns::NCR_UDP);
+ ASSERT_EQ(stringToNcrProtocol("udP"), dhcp_ddns::NCR_UDP);
+ ASSERT_EQ(stringToNcrProtocol("TCP"), dhcp_ddns::NCR_TCP);
+ ASSERT_EQ(stringToNcrProtocol("Tcp"), dhcp_ddns::NCR_TCP);
+ ASSERT_THROW(stringToNcrProtocol("bogus"), isc::BadValue);
+
+ ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_UDP), "UDP");
+ ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_TCP), "TCP");
+}
+
} // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
index b3c4206..69b14b2 100644
--- a/src/lib/dhcpsrv/Makefile.am
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -39,6 +39,7 @@ libb10_dhcpsrv_la_SOURCES =
libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libb10_dhcpsrv_la_SOURCES += callout_handle_store.h
+libb10_dhcpsrv_la_SOURCES += d2_client.cc d2_client.h
libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
libb10_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
@@ -64,6 +65,7 @@ libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libb10-hooks.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index 7789c74..6f008f1 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -348,9 +348,26 @@ CfgMgr::getUnicast(const std::string& iface) const {
return (&(*addr).second);
}
+void
+CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
+ d2_client_mgr_.setD2ClientConfig(new_config);
+}
+
+bool
+CfgMgr::ddnsEnabled() {
+ return (d2_client_mgr_.ddnsEnabled());
+}
+
+const D2ClientConfigPtr&
+CfgMgr::getD2ClientConfig() const {
+ return (d2_client_mgr_.getD2ClientConfig());
+}
+
+
CfgMgr::CfgMgr()
: datadir_(DHCP_DATA_DIR),
- all_ifaces_active_(false), echo_v4_client_id_(true) {
+ all_ifaces_active_(false), echo_v4_client_id_(true),
+ d2_client_mgr_() {
// DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
// Note: the definition of DHCP_DATA_DIR needs to include quotation marks
// See AM_CPPFLAGS definition in Makefile.am
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index cda59f2..fcec8bf 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -19,6 +19,7 @@
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcp/option_space.h>
+#include <dhcpsrv/d2_client.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
@@ -332,6 +333,24 @@ public:
return (echo_v4_client_id_);
}
+ /// @brief Updates the DHCP-DDNS client configuration to the given value.
+ ///
+ /// @param new_config pointer to the new client configuration.
+ ///
+ /// @throw Underlying method(s) will throw D2ClientError if given an empty
+ /// pointer.
+ void setD2ClientConfig(D2ClientConfigPtr& new_config);
+
+ /// @param Convenience method for checking if DHCP-DDNS updates are enabled.
+ ///
+ /// @return True if the D2 configuration is enabled.
+ bool ddnsEnabled();
+
+ /// @brief Fetches the DHCP-DDNS configuration pointer.
+ ///
+ /// @return a reference to the current configuration pointer.
+ const D2ClientConfigPtr& getD2ClientConfig() const;
+
protected:
/// @brief Protected constructor.
@@ -411,6 +430,9 @@ private:
/// Indicates whether v4 server should send back client-id
bool echo_v4_client_id_;
+
+ /// @brief Manages the DHCP-DDNS client and its configuration.
+ D2ClientMgr d2_client_mgr_;
};
} // namespace isc::dhcp
diff --git a/src/lib/dhcpsrv/d2_client.cc b/src/lib/dhcpsrv/d2_client.cc
new file mode 100644
index 0000000..d1b06ae
--- /dev/null
+++ b/src/lib/dhcpsrv/d2_client.cc
@@ -0,0 +1,185 @@
+// Copyright (C) 2013-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 <dhcpsrv/d2_client.h>
+#include <dhcpsrv/dhcpsrv_log.h>
+
+#include <string>
+
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+D2ClientConfig::D2ClientConfig(const bool enable_updates,
+ const isc::asiolink::IOAddress& server_ip,
+ const size_t server_port,
+ const dhcp_ddns::
+ NameChangeProtocol& ncr_protocol,
+ const dhcp_ddns::
+ NameChangeFormat& ncr_format,
+ const bool remove_on_renew,
+ const bool always_include_fqdn,
+ const bool override_no_update,
+ const bool override_client_update,
+ const bool replace_client_name,
+ const std::string& generated_prefix,
+ const std::string& qualifying_suffix)
+ : enable_updates_(enable_updates),
+ server_ip_(server_ip.getAddress()),
+ server_port_(server_port),
+ ncr_protocol_(ncr_protocol),
+ ncr_format_(ncr_format),
+ remove_on_renew_(remove_on_renew),
+ always_include_fqdn_(always_include_fqdn),
+ override_no_update_(override_no_update),
+ override_client_update_(override_client_update),
+ replace_client_name_(replace_client_name),
+ generated_prefix_(generated_prefix),
+ qualifying_suffix_(qualifying_suffix) {
+ validateContents();
+}
+
+D2ClientConfig::D2ClientConfig()
+ : enable_updates_(false),
+ server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
+ server_port_(0),
+ ncr_protocol_(dhcp_ddns::NCR_UDP),
+ ncr_format_(dhcp_ddns::FMT_JSON),
+ remove_on_renew_(false),
+ always_include_fqdn_(false),
+ override_no_update_(false),
+ override_client_update_(false),
+ replace_client_name_(false),
+ generated_prefix_(""),
+ qualifying_suffix_("") {
+ validateContents();
+}
+
+D2ClientConfig::~D2ClientConfig(){};
+
+void
+D2ClientConfig::validateContents() {
+ if (ncr_format_ != dhcp_ddns::FMT_JSON) {
+ isc_throw(D2ClientError, "D2ClientConfig: NCR Format:"
+ << dhcp_ddns::ncrFormatToString(ncr_format_)
+ << " is not yet supported");
+ }
+
+ if (ncr_protocol_ != dhcp_ddns::NCR_UDP) {
+ isc_throw(D2ClientError, "D2ClientConfig: NCR Protocol:"
+ << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
+ << " is not yet supported");
+ }
+
+ // @todo perhaps more validation we should do yet?
+ // Are there any invalid combinations of options we need to test against?
+ // Also do we care about validating contents if it's disabled?
+}
+
+bool
+D2ClientConfig::operator == (const D2ClientConfig& other) const {
+ return ((enable_updates_ == other.enable_updates_) &&
+ (server_ip_ == other.server_ip_) &&
+ (server_port_ == other.server_port_) &&
+ (ncr_protocol_ == other.ncr_protocol_) &&
+ (ncr_format_ == other.ncr_format_) &&
+ (remove_on_renew_ == other.remove_on_renew_) &&
+ (always_include_fqdn_ == other.always_include_fqdn_) &&
+ (override_no_update_ == other.override_no_update_) &&
+ (override_client_update_ == other.override_client_update_) &&
+ (replace_client_name_ == other.replace_client_name_) &&
+ (generated_prefix_ == other.generated_prefix_) &&
+ (qualifying_suffix_ == other.qualifying_suffix_));
+}
+
+bool
+D2ClientConfig::operator != (const D2ClientConfig& other) const {
+ return (!(*this == other));
+}
+
+std::string
+D2ClientConfig::toText() const {
+ std::ostringstream stream;
+
+ stream << "enable_updates: " << (enable_updates_ ? "yes" : "no");
+ if (enable_updates_) {
+ stream << ", server_ip: " << server_ip_.toText()
+ << ", server_port: " << server_port_
+ << ", ncr_protocol: " << ncr_protocol_
+ << ", ncr_format: " << ncr_format_
+ << ", remove_on_renew: " << (remove_on_renew_ ? "yes" : "no")
+ << ", always_include_fqdn: " << (always_include_fqdn_ ?
+ "yes" : "no")
+ << ", override_no_update: " << (override_no_update_ ?
+ "yes" : "no")
+ << ", override_client_update: " << (override_client_update_ ?
+ "yes" : "no")
+ << ", replace_client_name: " << (replace_client_name_ ?
+ "yes" : "no")
+ << ", generated_prefix: [" << generated_prefix_ << "]"
+ << ", qualifying_suffix: [" << qualifying_suffix_ << "]";
+ }
+
+ return (stream.str());
+}
+
+std::ostream&
+operator<<(std::ostream& os, const D2ClientConfig& config) {
+ os << config.toText();
+ return (os);
+}
+
+D2ClientMgr::D2ClientMgr() : d2_client_config_(new D2ClientConfig()) {
+ // Default contstructor initializes with a disabled config.
+}
+
+D2ClientMgr::~D2ClientMgr(){
+}
+
+void
+D2ClientMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
+ if (!new_config) {
+ isc_throw(D2ClientError,
+ "D2ClientMgr cannot set DHCP-DDNS configuration to NULL.");
+ }
+
+ // @todo When NameChangeSender is integrated, we will need to handle these
+ // scenarios:
+ // 1. D2 was enabled but now it is disabled
+ // - destroy the sender, flush any queued
+ // 2. D2 is still enabled but server params have changed
+ // - preserve any queued, reconnect based on sender params
+ // 3. D2 was was disabled now it is enabled.
+ // - create sender
+ //
+ // For now we just update the configuration.
+ d2_client_config_ = new_config;
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_CFG_DHCP_DDNS)
+ .arg(!ddnsEnabled() ? "DHCP-DDNS updates disabled" :
+ "DHCP_DDNS updates enabled");
+}
+
+bool
+D2ClientMgr::ddnsEnabled() {
+ return (d2_client_config_->getEnableUpdates());
+}
+
+const D2ClientConfigPtr&
+D2ClientMgr::getD2ClientConfig() const {
+ return (d2_client_config_);
+}
+
+}; // namespace dhcp
+}; // namespace isc
diff --git a/src/lib/dhcpsrv/d2_client.h b/src/lib/dhcpsrv/d2_client.h
new file mode 100644
index 0000000..2f84515
--- /dev/null
+++ b/src/lib/dhcpsrv/d2_client.h
@@ -0,0 +1,278 @@
+// Copyright (C) 2013-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 D2_CLIENT_H
+#define D2_CLIENT_H
+
+/// @file d2_client.h Defines the D2ClientConfig and D2ClientMgr classes.
+/// This file defines the classes Kea uses to act as a client of the b10-
+/// dhcp-ddns module (aka D2).
+///
+#include <asiolink/io_address.h>
+#include <dhcp_ddns/ncr_io.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+
+/// An exception that is thrown if an error occurs while configuring
+/// the D2 DHCP DDNS client.
+class D2ClientError : 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
+ D2ClientError(const char* file, size_t line, const char* what)
+ : isc::Exception(file, line, what) {}
+};
+
+/// @brief Acts as a storage vault for D2 client configuration
+///
+/// A simple container class for storing and retrieving the configuration
+/// parameters associated with DHCP-DDNS and acting as a client of D2.
+/// Instances of this class may be constructed through configuration parsing.
+///
+class D2ClientConfig {
+public:
+ /// @brief Constructor
+ ///
+ /// @param enable_updates Enables DHCP-DDNS updates
+ /// @param server_ip IP address of the b10-dhcp-ddns server (IPv4 or IPv6)
+ /// @param server_port IP port of the b10-dhcp-ddns server
+ /// @param ncr_protocol Socket protocol to use with b10-dhcp-ddns
+ /// Currently only UDP is supported.
+ /// @param ncr_format Format of the b10-dhcp-ddns requests.
+ /// Currently only JSON format is supported.
+ /// @param remove_on_renew Enables DNS Removes when renewing a lease
+ /// If true, Kea should request an explicit DNS remove prior to requesting
+ /// a DNS update when renewing a lease.
+ /// (Note: b10-dhcp-ddns is implemented per RFC 4703 and such a remove
+ /// is unnecessary).
+ /// @param always_include_fqdn Enables always including the FQDN option in
+ /// DHCP responses.
+ /// @param override_no_update Enables updates, even if clients request no
+ /// updates.
+ /// @param override_client_update Perform updates, even if client requested
+ /// delegation.
+ /// @param replace_client_name enables replacement of the domain-name
+ /// supplied by the client with a generated name.
+ /// @param generated_prefix Prefix to use when generating domain-names.
+ /// @param qualifying_suffix Suffix to use to qualify partial domain-names.
+ ///
+ /// @throw D2ClientError if given an invalid protocol or format.
+ D2ClientConfig(const bool enable_updates,
+ const isc::asiolink::IOAddress& server_ip,
+ const size_t server_port,
+ const dhcp_ddns::NameChangeProtocol& ncr_protocol,
+ const dhcp_ddns::NameChangeFormat& ncr_format,
+ const bool remove_on_renew,
+ const bool always_include_fqdn,
+ const bool override_no_update,
+ const bool override_client_update,
+ const bool replace_client_name,
+ const std::string& generated_prefix,
+ const std::string& qualifying_suffix);
+
+ /// @brief Default constructor
+ /// The default constructor creates an instance that has updates disabled.
+ D2ClientConfig();
+
+ /// @brief Destructor
+ virtual ~D2ClientConfig();
+
+ /// @brief Return whether or not DHCP-DDNS updating is enabled.
+ bool getEnableUpdates() const {
+ return(enable_updates_);
+ }
+
+ /// @brief Return the IP address of b10-dhcp-ddns (IPv4 or IPv6).
+ const isc::asiolink::IOAddress& getServerIp() const {
+ return(server_ip_);
+ }
+
+ /// @brief Return the IP port of b10-dhcp-ddns.
+ size_t getServerPort() const {
+ return(server_port_);
+ }
+
+ /// @brief Return the socket protocol to use with b10-dhcp-ddns.
+ const dhcp_ddns::NameChangeProtocol& getNcrProtocol() const {
+ return(ncr_protocol_);
+ }
+
+ /// @brief Return the b10-dhcp-ddns request format.
+ const dhcp_ddns::NameChangeFormat& getNcrFormat() const {
+ return(ncr_format_);
+ }
+
+ /// @brief Return whether or not removes should be sent for lease renewals.
+ bool getRemoveOnRenew() const {
+ return(remove_on_renew_);
+ }
+
+ /// @brief Return whether or not FQDN is always included in DHCP responses.
+ bool getAlwaysIncludeFqdn() const {
+ return(always_include_fqdn_);
+ }
+
+ /// @brief Return if updates are done even if clients request no updates.
+ bool getOverrideNoUpdate() const {
+ return(override_no_update_);
+ }
+
+ /// @brief Return if updates are done even when clients request delegation.
+ bool getOverrideClientUpdate() const {
+ return(override_client_update_);
+ }
+
+ /// @brief Return whether or not client's domain-name is always replaced.
+ bool getReplaceClientName() const {
+ return(replace_client_name_);
+ }
+
+ /// @brief Return the prefix to use when generating domain-names.
+ const std::string& getGeneratedPrefix() const {
+ return(generated_prefix_);
+ }
+
+ /// @brief Return the suffix to use to qualify partial domain-names.
+ const std::string& getQualifyingSuffix() const {
+ return(qualifying_suffix_);
+ }
+
+ /// @brief Compares two D2ClientConfigs for equality
+ bool operator == (const D2ClientConfig& other) const;
+
+ /// @brief Compares two D2ClientConfigs for inequality
+ bool operator != (const D2ClientConfig& other) const;
+
+ /// @brief Generates a string representation of the class contents.
+ std::string toText() const;
+
+protected:
+ /// @brief Validates member values.
+ ///
+ /// Method is used by the constructor to validate member contents.
+ ///
+ /// @throw D2ClientError if given an invalid protocol or format.
+ virtual void validateContents();
+
+private:
+ /// @brief Indicates whether or not DHCP DDNS updating is enabled.
+ bool enable_updates_;
+
+ /// @brief IP address of the b10-dhcp-ddns server (IPv4 or IPv6).
+ isc::asiolink::IOAddress server_ip_;
+
+ /// @brief IP port of the b10-dhcp-ddns server.
+ size_t server_port_;
+
+ /// @brief The socket protocol to use with b10-dhcp-ddns.
+ /// Currently only UPD is supported.
+ dhcp_ddns::NameChangeProtocol ncr_protocol_;
+
+ /// @brief Format of the b10-dhcp-ddns requests.
+ /// Currently only JSON format is supported.
+ dhcp_ddns::NameChangeFormat ncr_format_;
+
+ /// @brief Should Kea request a DNS Remove when renewing a lease.
+ /// If true, Kea should request an explicit DNS remove prior to requesting
+ /// a DNS update when renewing a lease.
+ /// (Note: b10-dhcp-ddns is implemented per RFC 4703 and such a remove
+ /// is unnecessary).
+ bool remove_on_renew_;
+
+ /// @brief Should Kea always include the FQDN option in its response.
+ bool always_include_fqdn_;
+
+ /// @brief Should Kea perform updates, even if client requested no updates.
+ /// Overrides the client request for no updates via the N flag.
+ bool override_no_update_;
+
+ /// @brief Should Kea perform updates, even if client requested delegation.
+ bool override_client_update_;
+
+ /// @brief Should Kea replace the domain-name supplied by the client.
+ bool replace_client_name_;
+
+ /// @brief Prefix Kea should use when generating domain-names.
+ std::string generated_prefix_;
+
+ /// @brief Suffix Kea should use when to qualify partial domain-names.
+ std::string qualifying_suffix_;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const D2ClientConfig& config);
+
+/// @brief Defines a pointer for D2ClientConfig instances.
+typedef boost::shared_ptr<D2ClientConfig> D2ClientConfigPtr;
+
+/// @brief D2ClientMgr isolates Kea from the details of being a D2 client.
+///
+/// Provides services for managing the current D2ClientConfig and managing
+/// communications with D2. (@todo The latter will be added once communication
+/// with D2 is implemented through the integration of
+/// dhcp_ddns::NameChangeSender interface(s)).
+///
+class D2ClientMgr {
+public:
+ /// @brief Constructor
+ ///
+ /// Default constructor which constructs an instance which has DHCP-DDNS
+ /// updates disabled.
+ D2ClientMgr();
+
+ /// @brief Destructor.
+ ~D2ClientMgr();
+
+ /// @brief Updates the DHCP-DDNS client configuration to the given value.
+ ///
+ /// @param new_config pointer to the new client configuration.
+ /// @throw D2ClientError if passed an empty pointer.
+ void setD2ClientConfig(D2ClientConfigPtr& new_config);
+
+ /// @brief Convenience method for checking if DHCP-DDNS is enabled.
+ ///
+ /// @return True if the D2 configuration is enabled.
+ bool ddnsEnabled();
+
+ /// @brief Fetches the DHCP-DDNS configuration pointer.
+ ///
+ /// @return a reference to the current configuration pointer.
+ const D2ClientConfigPtr& getD2ClientConfig() const;
+
+private:
+ /// @brief Container class for DHCP-DDNS configuration parameters.
+ D2ClientConfigPtr d2_client_config_;
+};
+
+/// @brief Defines a pointer for D2ClientMgr instances.
+typedef boost::shared_ptr<D2ClientMgr> D2ClientMgrPtr;
+
+
+} // namespace isc
+} // namespace dhcp
+
+#endif
diff --git a/src/lib/dhcpsrv/dhcp_parsers.cc b/src/lib/dhcpsrv/dhcp_parsers.cc
index ffd49d3..c647954 100644
--- a/src/lib/dhcpsrv/dhcp_parsers.cc
+++ b/src/lib/dhcpsrv/dhcp_parsers.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-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
@@ -1163,5 +1163,109 @@ SubnetConfigParser::getParam(const std::string& name) {
return (Triplet<uint32_t>(value));
}
+//**************************** D2ClientConfigParser **********************
+D2ClientConfigParser::D2ClientConfigParser(const std::string& entry_name)
+ : entry_name_(entry_name), boolean_values_(new BooleanStorage()),
+ uint32_values_(new Uint32Storage()), string_values_(new StringStorage()),
+ local_client_config_() {
+}
+
+D2ClientConfigParser::~D2ClientConfigParser() {
+}
+
+void
+D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
+ BOOST_FOREACH(ConfigPair param, client_config->mapValue()) {
+ ParserPtr parser(createConfigParser(param.first));
+ parser->build(param.second);
+ parser->commit();
+ }
+
+ bool enable_updates = boolean_values_->getParam("enable-updates");
+ if (!enable_updates) {
+ // If it's not enabled, don't bother validating the rest. This
+ // allows for an abbreviated config entry that only contains
+ // the flag. The default constructor creates a disabled instance.
+ local_client_config_.reset(new D2ClientConfig());
+ return;
+ }
+
+ // Get all parameters that are needed to create the D2ClientConfig.
+ asiolink::IOAddress server_ip(string_values_->getParam("server-ip"));
+
+ uint32_t server_port = uint32_values_->getParam("server-port");
+
+ dhcp_ddns::NameChangeProtocol
+ ncr_protocol = dhcp_ddns:: stringToNcrProtocol(string_values_->
+ getParam("ncr-protocol"));
+
+ dhcp_ddns::NameChangeFormat
+ ncr_format = dhcp_ddns::stringToNcrFormat(string_values_->
+ getParam("ncr-format"));
+
+ std::string generated_prefix = string_values_->getParam("generated-prefix");
+ std::string qualifying_suffix = string_values_->
+ getParam("qualifying-suffix");
+
+ bool remove_on_renew = boolean_values_->getParam("remove-on-renew");
+ bool always_include_fqdn = boolean_values_->getParam("always-include-fqdn");
+ bool override_no_update = boolean_values_->getParam("override-no-update");
+ bool override_client_update = boolean_values_->
+ getParam("override-client-update");
+ bool replace_client_name = boolean_values_->getParam("replace-client-name");
+
+ // Attempt to create the new client config.
+ local_client_config_.reset(new D2ClientConfig(enable_updates, server_ip,
+ server_port, ncr_protocol,
+ ncr_format, remove_on_renew,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix));
+}
+
+isc::dhcp::ParserPtr
+D2ClientConfigParser::createConfigParser(const std::string& config_id) {
+ DhcpConfigParser* parser = NULL;
+ if (config_id.compare("server-port") == 0) {
+ parser = new Uint32Parser(config_id, uint32_values_);
+ } else if ((config_id.compare("server-ip") == 0) ||
+ (config_id.compare("ncr-protocol") == 0) ||
+ (config_id.compare("ncr-format") == 0) ||
+ (config_id.compare("generated-prefix") == 0) ||
+ (config_id.compare("qualifying-suffix") == 0)) {
+ parser = new StringParser(config_id, string_values_);
+ } else if ((config_id.compare("enable-updates") == 0) ||
+ (config_id.compare("remove-on-renew") == 0) ||
+ (config_id.compare("always-include-fqdn") == 0) ||
+ (config_id.compare("allow-client-update") == 0) ||
+ (config_id.compare("override-no-update") == 0) ||
+ (config_id.compare("override-client-update") == 0) ||
+ (config_id.compare("replace-client-name") == 0)) {
+ parser = new BooleanParser(config_id, boolean_values_);
+ } else {
+ isc_throw(NotImplemented,
+ "parser error: D2ClientConfig parameter not supported: "
+ << config_id);
+ }
+
+ return (isc::dhcp::ParserPtr(parser));
+}
+
+void
+D2ClientConfigParser::commit() {
+ // @todo if local_client_config_ is empty then shutdown the listener...
+ // @todo Should this also attempt to start a listener?
+ // In keeping with Interface, Subnet, and Hooks parsers, then this
+ // should initialize the listener. Failure to init it, should cause
+ // rollback. This gets sticky, because who owns the listener instance?
+ // Does CfgMgr maintain it or does the server class? If the latter
+ // how do we get that value here?
+ // I'm thinkikng D2ClientConfig could contain the listener instance
+ CfgMgr::instance().setD2ClientConfig(local_client_config_);
+}
+
}; // namespace dhcp
}; // namespace isc
diff --git a/src/lib/dhcpsrv/dhcp_parsers.h b/src/lib/dhcpsrv/dhcp_parsers.h
index 28c57b8..00a07a0 100644
--- a/src/lib/dhcpsrv/dhcp_parsers.h
+++ b/src/lib/dhcpsrv/dhcp_parsers.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-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
@@ -18,6 +18,7 @@
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <dhcp/option_definition.h>
+#include <dhcpsrv/d2_client.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/subnet.h>
@@ -243,7 +244,7 @@ public:
// its value. If it doesn't we insert a new element.
storage_->setParam(param_name_, value_);
}
-
+
private:
/// Pointer to the storage where committed value is stored.
boost::shared_ptr<ValueStorage<ValueType> > storage_;
@@ -876,6 +877,77 @@ protected:
ParserContextPtr global_context_;
};
+/// @brief Parser for D2ClientConfig
+///
+/// This class parses the configuration element "dhcp-ddns" common to the
+/// spec files for both dhcp4 and dhcp6. It creates an instance of a
+/// D2ClientConfig.
+class D2ClientConfigParser : public isc::dhcp::DhcpConfigParser {
+public:
+ /// @brief Constructor
+ ///
+ /// @param entry_name is an arbitrary label assigned to this configuration
+ /// definition.
+ D2ClientConfigParser(const std::string& entry_name);
+
+ /// @brief Destructor
+ virtual ~D2ClientConfigParser();
+
+ /// @brief Performs the parsing of the given dhcp-ddns element.
+ ///
+ /// The results of the parsing are retained internally for use during
+ /// commit.
+ ///
+ /// @param client_config is the "dhcp-ddns" configuration to parse
+ virtual void build(isc::data::ConstElementPtr client_config);
+
+ /// @brief Creates a parser for the given "dhcp-ddns" member element id.
+ ///
+ /// The elements currently supported are (see isc::dhcp::D2ClientConfig
+ /// for details on each):
+ /// -# enable-updates
+ /// -# server-ip
+ /// -# server-port
+ /// -# ncr-protocol
+ /// -# ncr-format
+ /// -# remove-on-renew
+ /// -# always-include-fqdn
+ /// -# allow-client-update
+ /// -# override-no-update
+ /// -# override-client-update
+ /// -# replace-client-name
+ /// -# generated-prefix
+ /// -# qualifying-suffix
+ ///
+ /// @param config_id is the "item_name" for a specific member element of
+ /// the "dns_server" specification.
+ ///
+ /// @return returns a pointer to newly created parser.
+ virtual isc::dhcp::ParserPtr createConfigParser(const std::string&
+ config_id);
+
+ /// @brief Instantiates a D2ClientConfig from internal data values
+ /// passes to CfgMgr singleton.
+ virtual void commit();
+
+private:
+ /// @brief Arbitrary label assigned to this parser instance.
+ /// Primarily used for diagnostics.
+ std::string entry_name_;
+
+ /// Storage for subnet-specific boolean values.
+ BooleanStoragePtr boolean_values_;
+
+ /// Storage for subnet-specific integer values.
+ Uint32StoragePtr uint32_values_;
+
+ /// Storage for subnet-specific string values.
+ StringStoragePtr string_values_;
+
+ /// @brief Pointer to temporary local instance created during build.
+ D2ClientConfigPtr local_client_config_ ;
+};
+
// Pointers to various parser objects.
typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
typedef boost::shared_ptr<StringParser> StringParserPtr;
diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes
index 6ee3e87..5c7854e 100644
--- a/src/lib/dhcpsrv/dhcpsrv_messages.mes
+++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes
@@ -70,6 +70,9 @@ specified IPv6 subnet to its database.
A debug message issued when server is being configured to listen on all
interfaces.
+% DHCPSRV_CFGMGR_CFG_DHCP_DDNS Setting DHCP-DDNS configuration to: %1
+A debug message issued when the server's DHCP-DDNS settings are changed.
+
% DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES stop listening on all interfaces
A debug message issued when configuration manager clears the internal list
of active interfaces. This doesn't prevent the server from listening to
diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am
index 643fd63..ff57254 100644
--- a/src/lib/dhcpsrv/tests/Makefile.am
+++ b/src/lib/dhcpsrv/tests/Makefile.am
@@ -52,6 +52,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 += cfgmgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc
libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
@@ -88,6 +89,7 @@ endif
libdhcpsrv_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index fda8d59..8f952b4 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -154,7 +154,7 @@ public:
EXPECT_TRUE(false == lease->fqdn_fwd_);
EXPECT_TRUE(false == lease->fqdn_rev_);
EXPECT_TRUE(*lease->duid_ == *duid_);
- // @todo: check cltt
+ /// @todo: check cltt
}
/// @brief Checks if specified address is increased properly
@@ -408,7 +408,7 @@ public:
EXPECT_TRUE(*lease->client_id_ == *clientid_);
}
EXPECT_TRUE(lease->hwaddr_ == hwaddr_->hwaddr_);
- // @todo: check cltt
+ /// @todo: check cltt
}
virtual ~AllocEngine4Test() {
diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
index 08ce768..8c3d2ea 100644
--- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -538,7 +538,7 @@ TEST_F(CfgMgrTest, optionSpace4) {
cfg_mgr.addOptionSpace4(space3), isc::dhcp::InvalidOptionSpace
);
- // @todo decode if a duplicate vendor space is allowed.
+ /// @todo decode if a duplicate vendor space is allowed.
}
// This test verifies that new DHCPv6 option spaces can be added to
@@ -571,7 +571,7 @@ TEST_F(CfgMgrTest, optionSpace6) {
cfg_mgr.addOptionSpace6(space3), isc::dhcp::InvalidOptionSpace
);
- // @todo decide if a duplicate vendor space is allowed.
+ /// @todo decide if a duplicate vendor space is allowed.
}
// This test verifies that it is possible to specify interfaces that server
@@ -670,6 +670,46 @@ TEST_F(CfgMgrTest, echoClientId) {
EXPECT_TRUE(cfg_mgr.echoClientId());
}
+// This test checks the D2ClientMgr wrapper methods.
+TEST_F(CfgMgrTest, d2ClientConfig) {
+ // After CfgMgr construction, D2 configuration should be disabled.
+ // Fetch it and verify this is the case.
+ D2ClientConfigPtr original_config = CfgMgr::instance().getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+ EXPECT_FALSE(original_config->getEnableUpdates());
+
+ // Make sure convenience method agrees.
+ EXPECT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+ // Verify that we cannot set the configuration to an empty pointer.
+ D2ClientConfigPtr new_cfg;
+ ASSERT_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg), D2ClientError);
+
+ // Create a new, enabled configuration.
+ ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+
+ // Verify that we can assign a new, non-empty configuration.
+ ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg));
+
+ // Verify that we can fetch the newly assigned configuration.
+ D2ClientConfigPtr updated_config = CfgMgr::instance().getD2ClientConfig();
+ ASSERT_TRUE(updated_config);
+ EXPECT_TRUE(updated_config->getEnableUpdates());
+
+ // Make sure convenience method agrees with updated configuration.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+
+ // Make sure the configuration we fetched is the one we assigned,
+ // and not the original configuration.
+ EXPECT_EQ(*new_cfg, *updated_config);
+ EXPECT_NE(*original_config, *updated_config);
+}
+
+
/// @todo Add unit-tests for testing:
/// - addActiveIface() with invalid interface name
/// - addActiveIface() with the same interface twice
diff --git a/src/lib/dhcpsrv/tests/d2_client_unittest.cc b/src/lib/dhcpsrv/tests/d2_client_unittest.cc
new file mode 100644
index 0000000..bd8f061
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/d2_client_unittest.cc
@@ -0,0 +1,294 @@
+// Copyright (C) 2012-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 <dhcpsrv/d2_client.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc;
+
+namespace {
+
+/// @brief Checks constructors and accessors of D2ClientConfig.
+TEST(D2ClientConfigTest, constructorsAndAccessors) {
+ D2ClientConfigPtr d2_client_config;
+
+ // Verify default constructor creates a disabled instance.
+ ASSERT_NO_THROW(d2_client_config.reset(new D2ClientConfig()));
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+ d2_client_config.reset();
+
+ bool enable_updates = true;
+ isc::asiolink::IOAddress server_ip("127.0.0.1");
+ size_t server_port = 477;
+ dhcp_ddns::NameChangeProtocol ncr_protocol = dhcp_ddns::NCR_UDP;
+ dhcp_ddns::NameChangeFormat ncr_format = dhcp_ddns::FMT_JSON;
+ bool remove_on_renew = true;
+ bool always_include_fqdn = true;
+ bool override_no_update = true;
+ bool override_client_update = true;
+ bool replace_client_name = true;
+ std::string generated_prefix = "the_prefix";
+ std::string qualifying_suffix = "the.suffix.";
+
+ // Verify that we can construct a valid, enabled instance.
+ ASSERT_NO_THROW(d2_client_config.reset(new
+ D2ClientConfig(enable_updates,
+ server_ip,
+ server_port,
+ ncr_protocol,
+ ncr_format,
+ remove_on_renew,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix)));
+
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the accessors return the expected values.
+ EXPECT_EQ(d2_client_config->getEnableUpdates(), enable_updates);
+
+ EXPECT_EQ(d2_client_config->getServerIp(), server_ip);
+ EXPECT_EQ(d2_client_config->getServerPort(), server_port);
+ EXPECT_EQ(d2_client_config->getNcrProtocol(), ncr_protocol);
+ EXPECT_EQ(d2_client_config->getNcrFormat(), ncr_format);
+ EXPECT_EQ(d2_client_config->getRemoveOnRenew(), remove_on_renew);
+ EXPECT_EQ(d2_client_config->getAlwaysIncludeFqdn(), always_include_fqdn);
+ EXPECT_EQ(d2_client_config->getOverrideNoUpdate(), override_no_update);
+ EXPECT_EQ(d2_client_config->getOverrideClientUpdate(),
+ override_client_update);
+ EXPECT_EQ(d2_client_config->getReplaceClientName(), replace_client_name);
+ EXPECT_EQ(d2_client_config->getGeneratedPrefix(), generated_prefix);
+ EXPECT_EQ(d2_client_config->getQualifyingSuffix(), qualifying_suffix);
+
+ // Verify that toText called by << operator doesn't bomb.
+ ASSERT_NO_THROW(std::cout << "toText test:" << std::endl <<
+ *d2_client_config << std::endl);
+
+ // Verify that constructor does not allow use of NCR_TCP.
+ /// @todo obviously this becomes invalid once TCP is supported.
+ ASSERT_THROW(d2_client_config.reset(new
+ D2ClientConfig(enable_updates,
+ server_ip,
+ server_port,
+ dhcp_ddns::NCR_TCP,
+ ncr_format,
+ remove_on_renew,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix)),
+ D2ClientError);
+
+ /// @todo if additional validation is added to ctor, this test needs to
+ /// expand accordingly.
+}
+
+/// @brief Tests the equality and inequality operators of D2ClientConfig.
+TEST(D2ClientConfigTest, equalityOperator) {
+ D2ClientConfigPtr ref_config;
+ D2ClientConfigPtr test_config;
+
+ isc::asiolink::IOAddress ref_address("127.0.0.1");
+ isc::asiolink::IOAddress test_address("127.0.0.2");
+
+ // Create an instance to use as a reference.
+ ASSERT_NO_THROW(ref_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(ref_config);
+
+ // Check a configuration that is identical to reference configuration.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_TRUE(*ref_config == *test_config);
+ EXPECT_FALSE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by enable flag.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(false,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by server ip.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ test_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by server port.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 333,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by remove_on_renew.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by always_include_fqdn.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, false, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by override_no_update.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, false, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by override_client_update.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, false, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by replace_client_name.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by generated_prefix.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "bogus", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by qualifying_suffix.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "bogus")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+}
+
+/// @brief Checks the D2ClientMgr constructor.
+TEST(D2ClientMgr, constructor) {
+ D2ClientMgrPtr d2_client_mgr;
+
+ // Verify we can construct with the default constructor.
+ ASSERT_NO_THROW(d2_client_mgr.reset(new D2ClientMgr()));
+
+ // After construction, D2 configuration should be disabled.
+ // Fetch it and verify this is the case.
+ D2ClientConfigPtr original_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+ EXPECT_FALSE(original_config->getEnableUpdates());
+
+ // Make sure convenience method agrees.
+ EXPECT_FALSE(d2_client_mgr->ddnsEnabled());
+}
+
+/// @brief Checks passing the D2ClientMgr a valid D2 client configuration.
+/// @todo Once NameChangeSender is integrated, this test needs to expand, and
+/// additional scenario tests will need to be written.
+TEST(D2ClientMgr, validConfig) {
+ D2ClientMgrPtr d2_client_mgr;
+
+ // Construct the manager and fetch its initial configuration.
+ ASSERT_NO_THROW(d2_client_mgr.reset(new D2ClientMgr()));
+ D2ClientConfigPtr original_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+
+ // Verify that we cannot set the config to an empty pointer.
+ D2ClientConfigPtr new_cfg;
+ ASSERT_THROW(d2_client_mgr->setD2ClientConfig(new_cfg), D2ClientError);
+
+ // Create a new, enabled config.
+ ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true, true,
+ "pre-fix", "suf-fix")));
+
+ // Verify that we can assign a new, non-empty configuration.
+ ASSERT_NO_THROW(d2_client_mgr->setD2ClientConfig(new_cfg));
+
+ // Verify that we can fetch the newly assigned configuration.
+ D2ClientConfigPtr updated_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(updated_config);
+ EXPECT_TRUE(updated_config->getEnableUpdates());
+
+ // Make sure convenience method agrees with the updated configuration.
+ EXPECT_TRUE(d2_client_mgr->ddnsEnabled());
+
+ // Make sure the configuration we fetched is the one we assigned,
+ // and not the original configuration.
+ EXPECT_EQ(*new_cfg, *updated_config);
+ EXPECT_NE(*original_config, *updated_config);
+}
+
+
+} // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
index 928be23..2e6adb9 100644
--- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
+++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -367,8 +367,8 @@ public:
///
/// Note that the method currently it only supports option-defs, option-data
/// and hooks-libraries.
- ///
- /// @param config_id is the name of the configuration element.
+ ///
+ /// @param config_id is the name of the configuration element.
///
/// @return returns a shared pointer to DhcpConfigParser.
///
@@ -376,20 +376,21 @@ public:
ParserPtr createConfigParser(const std::string& config_id) {
ParserPtr parser;
if (config_id.compare("option-data") == 0) {
- parser.reset(new OptionDataListParser(config_id,
- parser_context_->options_,
+ parser.reset(new OptionDataListParser(config_id,
+ parser_context_->options_,
parser_context_,
UtestOptionDataParser::factory));
} else if (config_id.compare("option-def") == 0) {
- parser.reset(new OptionDefListParser(config_id,
+ parser.reset(new OptionDefListParser(config_id,
parser_context_->option_defs_));
} else if (config_id.compare("hooks-libraries") == 0) {
parser.reset(new HooksLibrariesParser(config_id));
hooks_libraries_parser_ =
boost::dynamic_pointer_cast<HooksLibrariesParser>(parser);
-
+ } else if (config_id.compare("dhcp-ddns") == 0) {
+ parser.reset(new D2ClientConfigParser(config_id));
} else {
isc_throw(NotImplemented,
"Parser error: configuration parameter not supported: "
@@ -399,8 +400,8 @@ public:
return (parser);
}
- /// @brief Convenience method for parsing a configuration
- ///
+ /// @brief Convenience method for parsing a configuration
+ ///
/// Given a configuration string, convert it into Elements
/// and parse them.
/// @param config is the configuration string to parse
@@ -491,6 +492,10 @@ public:
// Ensure no hooks libraries are loaded.
HooksManager::unloadLibraries();
+
+ // Set it to minimal, disabled config
+ D2ClientConfigPtr tmp(new D2ClientConfig());
+ CfgMgr::instance().setD2ClientConfig(tmp);
}
/// @brief Parsers used in the parsing of the configuration
@@ -566,7 +571,7 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
" \"name\": \"foo\","
" \"space\": \"isc\","
" \"code\": 100,"
- " \"data\": \"192.168.2.1\","
+ " \"data\": \"192.0.2.0\","
" \"csv-format\": True"
" } ]"
"}";
@@ -581,7 +586,7 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
// Verify that the option definition is correct.
std::string val = "type=100, len=4, data fields:\n "
- " #0 192.168.2.1 ( ipv4-address ) \n";
+ " #0 192.0.2.0 ( ipv4-address ) \n";
EXPECT_EQ(val, opt_ptr->toText());
}
@@ -677,7 +682,7 @@ TEST_F(ParseConfigTest, validHooksLibrariesTest) {
// Check with a set of libraries, some of which are invalid.
TEST_F(ParseConfigTest, invalidHooksLibrariesTest) {
- // @todo Initialize global library context to null
+ /// @todo Initialize global library context to null
// Configuration string. This contains an invalid library which should
// trigger an error in the "build" stage.
@@ -703,6 +708,262 @@ TEST_F(ParseConfigTest, invalidHooksLibrariesTest) {
"Error text returned from parse failure is " << error_text_;
}
+/// @brief Checks that a valid, enabled D2 client configuration works correctly.
+TEST_F(ParseConfigTest, validD2Config) {
+
+ // Configuration string containing valid values.
+ std::string config_str =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 3432, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ int rcode = parseConfiguration(config_str);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is enabled and we can fetch the configuration.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+ D2ClientConfigPtr d2_client_config;
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the configuration values are as expected.
+ EXPECT_TRUE(d2_client_config->getEnableUpdates());
+ EXPECT_EQ("192.0.2.0", d2_client_config->getServerIp().toText());
+ EXPECT_EQ(3432, d2_client_config->getServerPort());
+ EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
+ EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
+ EXPECT_TRUE(d2_client_config->getRemoveOnRenew());
+ EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());
+ EXPECT_TRUE(d2_client_config->getOverrideNoUpdate());
+ EXPECT_TRUE(d2_client_config->getOverrideClientUpdate());
+ EXPECT_TRUE(d2_client_config->getReplaceClientName());
+ EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
+ EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
+
+ // Another valid Configuration string.
+ // This one has IPV6 server ip, control flags false,
+ // empty prefix/suffix
+ std::string config_str2 =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"2001:db8::\", "
+ " \"server-port\" : 43567, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : false, "
+ " \"always-include-fqdn\" : false, "
+ " \"override-no-update\" : false, "
+ " \"override-client-update\" : false, "
+ " \"replace-client-name\" : false, "
+ " \"generated-prefix\" : \"\", "
+ " \"qualifying-suffix\" : \"\" "
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ rcode = parseConfiguration(config_str2);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is enabled and we can fetch the configuration.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the configuration values are as expected.
+ EXPECT_TRUE(d2_client_config->getEnableUpdates());
+ EXPECT_EQ("2001:db8::", d2_client_config->getServerIp().toText());
+ EXPECT_EQ(43567, d2_client_config->getServerPort());
+ EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
+ EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
+ EXPECT_FALSE(d2_client_config->getRemoveOnRenew());
+ EXPECT_FALSE(d2_client_config->getAlwaysIncludeFqdn());
+ EXPECT_FALSE(d2_client_config->getOverrideNoUpdate());
+ EXPECT_FALSE(d2_client_config->getOverrideClientUpdate());
+ EXPECT_FALSE(d2_client_config->getReplaceClientName());
+ EXPECT_EQ("", d2_client_config->getGeneratedPrefix());
+ EXPECT_EQ("", d2_client_config->getQualifyingSuffix());
+}
+
+/// @brief Checks that D2 client can be configured with enable flag of
+/// false only.
+TEST_F(ParseConfigTest, validDisabledD2Config) {
+
+ // Configuration string. This contains a set of valid libraries.
+ std::string config_str =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : false"
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ int rcode = parseConfiguration(config_str);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is disabled.
+ EXPECT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+ // Make sure fetched config agrees.
+ D2ClientConfigPtr d2_client_config;
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ EXPECT_TRUE(d2_client_config);
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+}
+
+/// @brief Check various invalid D2 client configurations.
+TEST_F(ParseConfigTest, invalidD2Config) {
+ std::string invalid_configs[] = {
+ // only the enable flag of true
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true"
+ " }"
+ "}",
+ // Missing server ip value
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ //" \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Invalid server ip value
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"x192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unknown protocol
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"Bogus\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unsupported protocol
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"TCP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unknown format
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"Bogus\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Missig Port
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ // " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"remove-on-renew\" : true, "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // stop
+ ""
+ };
+
+ // Fetch the original config.
+ D2ClientConfigPtr original_config;
+ ASSERT_NO_THROW(original_config = CfgMgr::instance().getD2ClientConfig());
+
+ // Iterate through the invalid configuration strings, attempting to
+ // parse each one. They should fail to parse, but fail gracefully.
+ D2ClientConfigPtr current_config;
+ int i = 0;
+ while (!invalid_configs[i].empty()) {
+ // Verify that the configuration string parses without throwing.
+ int rcode = parseConfiguration(invalid_configs[i]);
+
+ // Verify that parse result indicates a parsing error.
+ ASSERT_TRUE(rcode != 0) << "Invalid config #: " << i
+ << " should not have passed!";
+
+ // Verify that the "official" config still matches the original config.
+ ASSERT_NO_THROW(current_config =
+ CfgMgr::instance().getD2ClientConfig());
+ EXPECT_EQ(*original_config, *current_config);
+ ++i;
+ }
+}
+
/// @brief DHCP Configuration Parser Context test fixture.
class ParserContextTest : public ::testing::Test {
public:
diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
index 85015f6..5712604 100644
--- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -144,7 +144,7 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
EXPECT_EQ(Lease6Ptr(), x);
}
-// @todo Write more memfile tests
+/// @todo Write more memfile tests
// Simple test about lease4 retrieval through client id method
TEST_F(MemfileLeaseMgrTest, getLease4ClientId) {
diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
index d5e00ab..578ef3c 100644
--- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
@@ -549,7 +549,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4Hwaddr) {
}
// Get the leases matching the hardware address of lease 1
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
HWAddr tmp(leases[1]->hwaddr_, HTYPE_ETHER);
Lease4Collection returned = lmptr_->getLease4(tmp);
@@ -568,14 +568,14 @@ TEST_F(MySqlLeaseMgrTest, getLease4Hwaddr) {
EXPECT_EQ(straddress4_[5], addresses[2]);
// Repeat test with just one expected match
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[2]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[2], *returned.begin());
// Check that an empty vector is valid
EXPECT_TRUE(leases[7]->hwaddr_.empty());
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[7]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[7], *returned.begin());
@@ -599,7 +599,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSize) {
for (uint8_t i = 0; i <= HWAddr::MAX_HWADDR_LEN; ++i) {
leases[1]->hwaddr_.resize(i, i);
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Collection returned =
lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, HTYPE_ETHER));
@@ -610,7 +610,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSize) {
// Database should not let us add one that is too big
// (The 42 is a random value put in each byte of the address.)
- // @todo: 2589 will make this test impossible
+ /// @todo: 2589 will make this test impossible
leases[1]->hwaddr_.resize(HWAddr::MAX_HWADDR_LEN + 100, 42);
EXPECT_THROW(lmptr_->addLease(leases[1]), isc::dhcp::DbOperationError);
}
@@ -628,7 +628,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Get the leases matching the hardware address of lease 1 and
// subnet ID of lease 1. Result should be a single lease - lease 1.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER), leases[1]->subnet_id_);
@@ -637,7 +637,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Try for a match to the hardware address of lease 1 and the wrong
// subnet ID.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, HTYPE_ETHER),
leases[1]->subnet_id_ + 1);
EXPECT_FALSE(returned);
@@ -645,14 +645,14 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Try for a match to the subnet ID of lease 1 (and lease 4) but
// the wrong hardware address.
vector<uint8_t> invalid_hwaddr(15, 0x77);
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(invalid_hwaddr, HTYPE_ETHER),
leases[1]->subnet_id_);
EXPECT_FALSE(returned);
// Try for a match to an unknown hardware address and an unknown
// subnet ID.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(invalid_hwaddr, HTYPE_ETHER),
leases[1]->subnet_id_ + 1);
EXPECT_FALSE(returned);
@@ -665,7 +665,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
EXPECT_TRUE(lmptr_->deleteLease(leases[2]->addr_));
leases[1]->addr_ = leases[2]->addr_;
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
EXPECT_THROW(returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER),
leases[1]->subnet_id_),
@@ -687,7 +687,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetIdSize) {
for (uint8_t i = 0; i <= HWAddr::MAX_HWADDR_LEN; ++i) {
leases[1]->hwaddr_.resize(i, i);
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER),
leases[1]->subnet_id_);
More information about the bind10-changes
mailing list