Commit c13c824d authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[master] Merge branch 'trac3689'

parents ee47aff0 52b6493c
......@@ -2071,11 +2071,64 @@ should include options from the isc option space:
<section id="reservation6-hostname">
<title>Reserving a hostname</title>
<!-- @todo: replace this with the actual text once #3689 is implemented -->
<para>Reserving a hostname is currently not supported. It is possible
to specify that information in the configuration file, but that data
is not used by the server engine yet.</para>
</section>
<para>When the reservation for the client includes the <command>hostname
</command>, the server will assign this hostname to the client and send
it back in the Client FQDN, if the client sent the FQDN option to the
the server. The reserved hostname always takes precedence over the hostname
supplied by the client (via the FQDN option) or the autogenerated
(from the IPv6 address) hostname.</para>
<para>The server qualifies the reserved hostname with the value
of the <command>qualifying-suffix</command> parameter. For example, the
following subnet configuration:
<screen>
"subnet6": [
{
"subnet": "2001:db8:1::/48",
"pools": [ { "pool": "2001:db8:1::/80" } ],
"reservations": [
{
"duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
"ip-addresses": [ "2001:db8:1::100" ]
"hostname": "alice-laptop"
}
]
}
],
"dhcp-ddns": {
"enable-updates": true,
"qualifying-suffix": "example.isc.org."
}
</screen>
will result in assigning the "alice-laptop.example.isc.org." hostname to the
client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the <command>qualifying-suffix
</command> is not specified, the default (empty) value will be used, and
in this case the value specified as a <command>hostname</command> will
be treated as fully qualified name. Thus, by leaving the
<command>qualifying-suffix</command> empty it is possible to qualify
hostnames for the different clients with different domain names:
<screen>
"subnet6": [
{
"subnet": "2001:db8:1::/48",
"pools": [ { "pool": "2001:db8:1::/80" } ],
"reservations": [
{
"duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
"ip-addresses": [ "2001:db8:1::100" ]
"hostname": "mark-desktop.example.org."
}
]
}
],
"dhcp-ddns": {
"enable-updates": true,
}
</screen>
will result in assigning the "mark-desktop.example.org." hostname to the
client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E".
</para>
</section>
<section id="reservation6-options">
<title>Reserving specific options</title>
......
This diff is collapsed.
......@@ -166,25 +166,25 @@ protected:
void sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
RequirementLevel serverid);
/// @brief Processes incoming SOLICIT and returns response.
/// @brief Processes incoming Solicit and returns response.
///
/// Processes received SOLICIT message and verifies that its sender
/// Processes received Solicit message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with to-be assigned addresses, temporary addresses and delegated
/// prefixes, respectively. In the usual 4 message exchange, server is
/// expected to respond with ADVERTISE message. However, if client
/// requests rapid-commit and server supports it, REPLY will be sent
/// instead of ADVERTISE and requested leases will be assigned
/// expected to respond with Advertise message. However, if client
/// requests rapid-commit and server supports it, Reply will be sent
/// instead of Advertise and requested leases will be assigned
/// immediately.
///
/// @param solicit SOLICIT message received from client
/// @param solicit Solicit message received from client
///
/// @return ADVERTISE, REPLY message or NULL
/// @return Advertise, Reply message or NULL.
Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
/// @brief Processes incoming REQUEST and returns REPLY response.
/// @brief Processes incoming Request and returns Reply response.
///
/// Processes incoming REQUEST message and verifies that its sender
/// Processes incoming Request message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with assigned addresses, temporary addresses and delegated
/// prefixes, respectively. Uses LeaseMgr to allocate or update existing
......@@ -195,14 +195,22 @@ protected:
/// @return REPLY message or NULL
Pkt6Ptr processRequest(const Pkt6Ptr& request);
/// @brief Stub function that will handle incoming RENEW messages.
/// @brief Processes incoming Renew message.
///
/// @param renew message received from client
/// @param renew message received from the client
/// @return Reply message to be sent to the client.
Pkt6Ptr processRenew(const Pkt6Ptr& renew);
/// @brief Stub function that will handle incoming REBIND messages.
/// @brief Processes incoming Rebind message.
///
/// @param rebind message received from client
/// @todo There are cases when the Rebind message should be discarded
/// by the DHCP server. One of those is when the server doesn't have a
/// record of the client and it is unable to determine whether the
/// client is on the appropriate link or not. We don't seem to do it
/// now.
///
/// @param rebind message received from the client.
/// @return Reply message to be sent to the client.
Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
/// @brief Processes incoming Confirm message and returns Reply.
......@@ -226,24 +234,26 @@ protected:
///
/// @param confirm Confirm message sent by a client.
///
/// @return Reply message from the server al NULL pointer if Confirm
/// @return Reply message from the server or NULL pointer if Confirm
/// message should be discarded by the server.
Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
/// @brief Stub function that will handle incoming RELEASE messages.
/// @brief Process incoming Release message.
///
/// @param release message received from client
/// @return Reply message to be sent to the client.
Pkt6Ptr processRelease(const Pkt6Ptr& release);
/// @brief Stub function that will handle incoming DECLINE messages.
/// @brief Stub function that will handle incoming Decline.
///
/// @param decline message received from client
Pkt6Ptr processDecline(const Pkt6Ptr& decline);
/// @brief Stub function that will handle incoming INF-REQUEST messages.
/// @brief Processes incoming Information-request message.
///
/// @param infRequest message received from client
Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
/// @param inf_request message received from client
/// @return Reply message to be sent to the client.
Pkt6Ptr processInfRequest(const Pkt6Ptr& inf_request);
/// @brief Creates status-code option.
///
......@@ -266,19 +276,17 @@ protected:
/// status code option with non-zero status, denoting cause of the
/// allocation failure.
///
/// @param subnet subnet the client is connected to
/// @param duid client's duid
/// @param query client's message (typically SOLICIT or REQUEST)
/// @param answer server's response to the client's message. This
/// message should contain Client FQDN option being sent by the server
/// to the client (if the client sent this option to the server).
/// @param orig_ctx client context (contains subnet, duid and other parameters)
/// @param ia pointer to client's IA_NA option (client's request)
///
/// @return IA_NA option (server's response)
OptionPtr assignIA_NA(const isc::dhcp::Subnet6Ptr& subnet,
const isc::dhcp::DuidPtr& duid,
const isc::dhcp::Pkt6Ptr& query,
OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query,
const isc::dhcp::Pkt6Ptr& answer,
AllocEngine::ClientContext6& orig_ctx,
Option6IAPtr ia);
/// @brief Processes IA_PD option (and assigns prefixes if necessary).
......@@ -289,13 +297,12 @@ protected:
/// status code option with non-zero status denoting the cause of the
/// allocation failure.
///
/// @param subnet subnet the client is connected to
/// @param duid client's duid
/// @param query client's message (typically SOLICIT or REQUEST)
/// @param orig_ctx client context (contains subnet, duid and other parameters)
/// @param ia pointer to client's IA_PD option (client's request)
/// @return IA_PD option (server's response)
OptionPtr assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
const Pkt6Ptr& query,
OptionPtr assignIA_PD(const Pkt6Ptr& query,
AllocEngine::ClientContext6& orig_ctx,
boost::shared_ptr<Option6IA> ia);
/// @brief Extends lifetime of the specific IA_NA option.
......@@ -323,11 +330,12 @@ protected:
/// @param answer server's response to the client's message. This
/// message should contain Client FQDN option being sent by the server
/// to the client (if the client sent this option to the server).
/// @param orig_ctx client context (contains subnet, duid and other parameters)
/// @param ia IA_NA option which carries adress for which lease lifetime
/// will be extended.
/// @return IA_NA option (server's response)
OptionPtr extendIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
const Pkt6Ptr& query, const Pkt6Ptr& answer,
OptionPtr extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
AllocEngine::ClientContext6& orig_ctx,
Option6IAPtr ia);
/// @brief Extends lifetime of the prefix.
......@@ -341,16 +349,16 @@ protected:
/// is thrown when there is no binding and the Rebind message is processed
/// (see RFC3633, section 12.2. for details).
///
/// @param subnet subnet the sender belongs to
/// @param duid client's duid
/// @param query client's message
/// @param orig_ctx client context (contains subnet, duid and other parameters)
/// @param ia IA_PD option that is being renewed
/// @return IA_PD option (server's response)
/// @throw DHCPv6DiscardMessageError when the message being processed should
/// be discarded by the server, i.e. there is no binding for the client doing
/// Rebind.
OptionPtr extendIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
const Pkt6Ptr& query, Option6IAPtr ia);
OptionPtr extendIA_PD(const Pkt6Ptr& query,
AllocEngine::ClientContext6& orig_ctx,
Option6IAPtr ia);
/// @brief Releases specific IA_NA option
///
......@@ -416,7 +424,9 @@ protected:
///
/// @param question client's message
/// @param answer server's message (options will be added here)
void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @param ctx client context (contains subnet, duid and other parameters)
void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @brief Appends requested vendor options to server's answer.
///
......@@ -425,19 +435,22 @@ protected:
///
/// @param question client's message
/// @param answer server's message (vendor options will be added here)
void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @param ctx client context (contains subnet, duid and other parameters)
void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @brief Assigns leases.
///
/// It supports addresses (IA_NA) only. It does NOT support temporary
/// addresses (IA_TA) nor prefixes (IA_PD).
/// @todo: Extend this method once TA and PD becomes supported
/// It supports non-temporary addresses (IA_NA) and prefixes (IA_PD). It
/// does NOT support temporary addresses (IA_TA).
///
/// @param question client's message (with requested IA_NA)
/// @param answer server's message (IA_NA options will be added here).
/// This message should contain Client FQDN option being sent by the server
/// to the client (if the client sent this option to the server).
void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @param question client's message (with requested IA options)
/// @param answer server's message (IA options will be added here).
/// This message should contain Client FQDN option being sent by the server
/// to the client (if the client sent this option to the server).
/// @param ctx client context (contains subnet, duid and other parameters)
void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @brief Processes Client FQDN Option.
///
......@@ -453,6 +466,28 @@ protected:
/// domain-name, i.e. if the provided domain-name is partial it should
/// generate the fully qualified domain-name.
///
/// This function takes into account the host reservation if one is matched
/// to this client when forming the FQDN to be used with DNS as well as the
/// lease name to be stored with the lease. In the following the term
/// "reserved hostname" means a host reservation which includes a
/// non-blank hostname.
///
/// - If there is no Client FQDN and no reserved hostname then there
/// will no be DNS updates and the lease hostname will be empty.
///
/// - If there is no Client FQDN but there is reserverd hostname then
/// there will be no DNS updates and the lease hostname will be equal
/// to reserved hostname.
///
/// - If there is a Client FQDN and a reserved hostname, then both the
/// FQDN and lease hostname will be equal to reserved hostname with
/// the qualifying suffix appended.
///
/// - If there is a Client FQDN but no reserverd hostname then both the
/// FQDN and lease hostname will be equal to the name provided in the
/// client FQDN adjusted according the the DhcpDdns configuration
/// parameters (e.g.replace-client-name, qualifying suffix...).
///
/// All the logic required to form appropriate answer to the client is
/// held in this function.
///
......@@ -460,7 +495,9 @@ protected:
/// @param answer Server's response to a client. If server generated
/// Client FQDN option for the client, this option is stored in this
/// object.
void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer);
/// @param ctx client context (includes subnet, client-id, hw-addr etc.)
void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @brief Creates a number of @c isc::dhcp_ddns::NameChangeRequest objects
/// based on the DHCPv6 Client FQDN %Option.
......@@ -507,7 +544,9 @@ protected:
///
/// @param query client's Renew or Rebind message
/// @param reply server's response
void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply);
/// @param ctx client context (contains subnet, duid and other parameters)
void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply,
AllocEngine::ClientContext6& ctx);
/// @brief Attempts to release received addresses
///
......@@ -518,7 +557,9 @@ protected:
/// to REPLY packet, just its IA_NA containers.
/// @param release client's message asking to release
/// @param reply server's response
void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply);
/// @param ctx client context (includes subnet, client-id, hw-addr etc.)
void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply,
AllocEngine::ClientContext6& ctx);
/// @brief Sets server-identifier.
///
......@@ -616,6 +657,19 @@ protected:
/// - there is no such option provided by the server)
void processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp);
/// @brief Creates client context for specified packet
///
/// Instantiates the ClientContext6 and then:
/// - Performs the subnet selection and stores the result in context
/// - Extracts the duid from the packet and saves it to the context
/// - Extracts the hardware address from the packet and saves it to
/// the context
/// - Performs host reservation lookup and stores the result in the
/// context
///
/// @return client context
AllocEngine::ClientContext6 createContext(const Pkt6Ptr& pkt);
/// @brief this is a prefix added to the contend of vendor-class option
///
/// If incoming packet has a vendor class option, its content is
......@@ -683,6 +737,12 @@ private:
const std::string& hostname,
bool do_fwd, bool do_rev);
/// @brief Utility method that extracts DUID from client-id option
///
/// @param pkt the message that contains client-id option
/// @return extracted DUID (or NULL if client-id is missing)
DuidPtr extractClientId(const Pkt6Ptr& pkt);
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
/// It must be a pointer, because we will support changing engines
......
......@@ -75,6 +75,7 @@ dhcp6_unittests_SOURCES = dhcp6_unittests.cc
dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
dhcp6_unittests_SOURCES += fqdn_unittest.cc
dhcp6_unittests_SOURCES += hooks_unittest.cc
dhcp6_unittests_SOURCES += host_unittest.cc
dhcp6_unittests_SOURCES += dhcp6_test_utils.cc dhcp6_test_utils.h
dhcp6_unittests_SOURCES += d2_unittest.cc d2_unittest.h
dhcp6_unittests_SOURCES += marker_file.cc
......
......@@ -340,6 +340,20 @@ Dhcp6Client::doInfRequest() {
context_.response_ = receiveOneMsg();
}
void
Dhcp6Client::doRenew() {
Pkt6Ptr query = createMsg(DHCPV6_RENEW);
query->addOption(context_.response_->getOption(D6O_SERVERID));
copyIAsFromLeases(query);
context_.query_ = query;
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
// Apply configuration only if the server has responded.
if (context_.response_) {
applyRcvdConfiguration(context_.response_);
}
}
void
Dhcp6Client::doRebind() {
Pkt6Ptr query = createMsg(DHCPV6_REBIND);
......@@ -427,6 +441,12 @@ Dhcp6Client::getLeasesByIAID(const uint32_t iaid) const {
return (leases);
}
void
Dhcp6Client::setDUID(const std::string& str) {
DUID d = DUID::fromText(str);
duid_.reset(new DUID(d));
}
void
Dhcp6Client::modifyDUID() {
if (!duid_) {
......
......@@ -204,6 +204,21 @@ public:
/// @todo Perform sanity checks on returned messages.
void doSolicit();
/// @brief Sends a Renew to the server and receives the Reply.
///
/// This function simulates sending the Renew message to the server and
/// receiving server's response (if any). The client uses existing leases
/// (either address or prefixes) and places them in the Renew message.
/// If the server responds to the Renew (and extends the lease lifetimes)
/// the current lease configuration is updated.
///
/// @throw This function doesn't throw exceptions on its own, but it calls
/// functions that are not exception safe, so it may throw exceptions if
/// error occurs.
///
/// @todo Perform sanity checks on returned messages.
void doRenew();
/// @brief Sends a Rebind to the server and receives the Reply.
///
/// This function simulates sending the Rebind message to the server and
......@@ -324,6 +339,18 @@ public:
return (srv_);
}
/// @brief Sets the client's DUID from a string value
///
/// Replaces the client's DUID with one constructed from the given
/// string. The string is expected to contain hexadecimal digits with or
/// without ":" separators.
///
/// @param str The string of digits from which to create the DUID
///
/// The DUID modification affects the value returned by the
/// @c Dhcp6Client::getClientId
void setDUID(const std::string& duid_str);
/// @brief Modifies the client's DUID (adds one to it).
///
/// The DUID should be modified to test negative scenarios when the client
......
......@@ -2354,4 +2354,5 @@ TEST_F(Dhcpv6SrvTest, rsooOverride) {
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
} // end of anonymous namespace
......@@ -113,6 +113,7 @@ public:
using Dhcpv6Srv::shutdown_;
using Dhcpv6Srv::name_change_reqs_;
using Dhcpv6Srv::VENDOR_CLASS_PREFIX;
using Dhcpv6Srv::createContext;
/// @brief packets we pretend to receive
///
......
......@@ -24,6 +24,7 @@
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option_int_array.h>
#include <dhcpsrv/lease.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <boost/pointer_cast.hpp>
......@@ -329,7 +330,8 @@ public:
// Create three IAs, each having different address.
addIA(1234, IOAddress("2001:db8:1::1"), answer);
ASSERT_NO_THROW(srv_->processClientFqdn(question, answer));
AllocEngine::ClientContext6 ctx;
ASSERT_NO_THROW(srv_->processClientFqdn(question, answer, ctx));
Option6ClientFqdnPtr answ_fqdn = boost::dynamic_pointer_cast<
Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
ASSERT_TRUE(answ_fqdn);
......@@ -393,6 +395,7 @@ public:
const std::string& exp_hostname,
const uint8_t client_flags =
Option6ClientFqdn::FLAG_S,
const IOAddress expected_address = IOAddress("2001:db8:1:1::dead:beef"),
const bool include_oro = true) {
// Create a message of a specified type, add server id and
// FQDN option.
......@@ -440,7 +443,7 @@ public:
ASSERT_TRUE(addr);
// Check that we have got the address we requested.
checkIAAddr(addr, IOAddress("2001:db8:1:1::dead:beef"),
checkIAAddr(addr, expected_address,
Lease::TYPE_NA);
if (msg_type != DHCPV6_SOLICIT) {
......@@ -482,12 +485,15 @@ public:
/// NameChangeRequest expires.
/// @param len A valid lifetime of the lease associated with the
/// NameChangeRequest.
/// @param fqdn The expected string value of the FQDN, if blank the
/// check is skipped
void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
const bool reverse, const bool forward,
const std::string& addr,
const std::string& dhcid,
const uint16_t expires,
const uint16_t len) {
const uint16_t len,
const std::string& fqdn="") {
NameChangeRequestPtr ncr;
ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
ASSERT_TRUE(ncr);
......@@ -501,10 +507,40 @@ public:
EXPECT_EQ(len, ncr->getLeaseLength());
EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());
if (! fqdn.empty()) {
EXPECT_EQ(fqdn, ncr->getFqdn());
}
// Process the message off the queue
ASSERT_NO_THROW(d2_mgr_.runReadyIO());
}
/// @brief Updates inherited subnet and pool members
///
/// Hack added to set subnet_ and pool_ members that are buried into lower
/// level tests such as checkLease(), so one can use "configure" functionality
/// rather than hand-building configured objects
/// @param subnet_idx Element index of the desired subnet
/// @param pool_idx Element index of the desired pool within the desired subnet
/// @param type lease type of desired pool
///
void setSubnetAndPool(int subnet_idx, int pool_idx, Lease::Type type) {
ConstCfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
ASSERT_TRUE(subnets);
const Subnet6Collection* subnet_col = subnets->getAll();
ASSERT_EQ(subnet_idx + 1, subnet_col->size());
subnet_ = subnet_col->at(subnet_idx);
ASSERT_TRUE(subnet_);
const PoolCollection& pool_col = subnet_->getPools(type);
ASSERT_EQ(pool_idx + 1, pool_col.size());
PoolPtr pool = (subnet_->getPools(type)).at(pool_idx);
ASSERT_TRUE(pool);
pool_ = boost::dynamic_pointer_cast<Pool6>(pool);
ASSERT_TRUE(pool);
}
// Holds a lease used by a test.
Lease6Ptr lease_;
......@@ -943,7 +979,8 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
// In this case, we expect that the FQDN option will not be included
// in the server's response. The testProcessMessage will check that.
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
"myhost.example.com.", Option6ClientFqdn::FLAG_S, false);
"myhost.example.com.", Option6ClientFqdn::FLAG_S,
IOAddress("2001:db8:1:1::dead:beef"), false);
ASSERT_EQ(1, d2_mgr_.getQueueSize());
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
"2001:db8:1:1::dead:beef",
......@@ -957,7 +994,8 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
TEST_F(FqdnDhcpv6SrvTest, processRequestEmptyFqdn) {
testProcessMessage(DHCPV6_REQUEST, "",
"myhost-2001-db8-1-1--dead-beef.example.com.",
Option6ClientFqdn::FLAG_S, false);
Option6ClientFqdn::FLAG_S,
IOAddress("2001:db8:1:1::dead:beef"), false);
ASSERT_EQ(1, d2_mgr_.getQueueSize());
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
"2001:db8:1:1::dead:beef",
......@@ -1050,5 +1088,151 @@ TEST_F(FqdnDhcpv6SrvTest, processClientDelegation) {
0, 4000);
}
// Verify that the host reservation is found and used. Lease host name and
// FQDN should be the reservation hostname suffixed by the qualifying suffix.
TEST_F(FqdnDhcpv6SrvTest, hostnameReservationSuffix) {
isc::dhcp::test::IfaceMgrTestConfig test_config(true);
string config_str = "{ "
"\"interfaces-config\": {"
" \"interfaces\": [ \"*\" ]"
"},"
"\"valid-lifetime\": 4000, "
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ "
" { "
" \"subnet\": \"2001:db8:1::/48\", "
" \"pools\": [ { \"pool\": \"2001:db8:1:1::/64\" } ],"
" \"interface\" : \"eth0\" , "
" \"reservations\": ["
" {"
" \"duid\": \"" + duid_->toText() + "\","
" \"ip-addresses\": [ \"2001:db8:1:1::babe\" ],"
" \"hostname\": \"alice\""
" }"
" ]"
" } ],"
" \"dhcp-ddns\" : {"
" \"enable-updates\" : true, "
" \"qualifying-suffix\" : \"example.com\" }"
"}";
configure(config_str);
// Update subnet_ and pool_ members after config
setSubnetAndPool(0, 0, Lease::TYPE_NA);