2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +00:00

[#3049] Initial v6 changes

Pool6 UT and added keywords,
first cut of logic to Dhcpv6Srv

/src/bin/dhcp6/dhcp6_srv.*
    replaced Dhcpv6Srv::checkDynamicSubnetChange()
    with Dhcpv6Srv::checkPostAssignmentChanges()

/src/lib/dhcpsrv/parsers/simple_parser6.cc
    Added parameter to POOL6_PARAMETERS

/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
    TEST_F(DhcpParserTest, validDdnsParmatersPool4) - use function template
    TEST_F(DhcpParserTest, validDdnsParmatersPool6) - new test
This commit is contained in:
Thomas Markwalder
2025-01-08 13:09:53 -05:00
parent 18cde6f9e2
commit 0f20a2374e
6 changed files with 265 additions and 208 deletions

View File

@@ -2249,9 +2249,10 @@ Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
}
}
// Subnet may be modified by the allocation engine, there are things
// we need to do when that happens.
checkDynamicSubnetChange(question, answer, ctx, orig_subnet);
// Need to check for pool-level DDNS parameters and if the
// subnet was modified by the allocation engine, there are things
// we need to do either case.
checkPostAssignmentChanges(question, answer, ctx, orig_subnet);
}
void
@@ -2440,6 +2441,8 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
// Iterate over the IAContexts (there should be one per client IA processed).
// For the first address in each IA_NA, create the appropriate NCR(s).
/// @todo TKM - we should really consider only doing this for the first
/// IA_NA.
for (auto& ia_ctx : ctx.getIAContexts()) {
if ((ia_ctx.type_ != Lease::TYPE_NA) || !ia_ctx.ia_rsp_) {
continue;
@@ -3267,9 +3270,10 @@ Dhcpv6Srv::extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply,
}
}
// Subnet may be modified by the allocation engine, there are things
// we need to do when that happens.
checkDynamicSubnetChange(query, reply, ctx, orig_subnet);
// Need to check for pool-level DDNS parameters and if the
// subnet was modified by the allocation engine, there are things
// we need to do either case.
checkPostAssignmentChanges(query, reply, ctx, orig_subnet);
}
void
@@ -5069,52 +5073,71 @@ Dhcpv6Srv::setTeeTimes(uint32_t preferred_lft,
}
void
Dhcpv6Srv::checkDynamicSubnetChange(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const ConstSubnet6Ptr orig_subnet) {
// If the subnet's are the same there's nothing to do.
if ((!ctx.subnet_) || (!orig_subnet) || (orig_subnet->getID() == ctx.subnet_->getID())) {
return;
Dhcpv6Srv::checkPostAssignmentChanges(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const ConstSubnet6Ptr orig_subnet) {
bool reprocess_client_name = false;
// Find the pool to which the first active lease address belongs and use it
// to update DDNS parameters to include those from the pool.
OptionPtr ia = answer->getOption(D6O_IA_NA);
if (ia) {
Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
if (iaaddr && (iaaddr->getValid() > 0)) {
auto ddns_params = ctx.getDdnsParams();
auto pool = ddns_params->setPoolFromAddress(iaaddr->getAddress());
if (pool) {
// If the pool has any DDNS parameters we need to recalculate the FQDN.
reprocess_client_name = pool->hasDdnsParameters();
}
}
}
// We get the network for logging only. It should always be set as this a dynamic
// change should only happen within shared-networks. Not having one might not be
// an error if a hook changed the subnet?
SharedNetwork6Ptr network;
orig_subnet->getSharedNetwork(network);
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_SUBNET_DYNAMICALLY_CHANGED)
.arg(question->getLabel())
.arg(orig_subnet->toText())
.arg(ctx.subnet_->toText())
.arg(network ? network->getName() : "<no network?>");
// Check if the subnet was dynamnically changed by the allocation engine.
if (ctx.subnet_ && orig_subnet && (orig_subnet->getID() != ctx.subnet_->getID())) {
// We get the network for logging only. It should always be set as this a dynamic
// change should only happen within shared-networks. Not having one might not be
// an error if a hook changed the subnet?
SharedNetwork6Ptr network;
orig_subnet->getSharedNetwork(network);
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_SUBNET_DYNAMICALLY_CHANGED)
.arg(question->getLabel())
.arg(orig_subnet->toText())
.arg(ctx.subnet_->toText())
.arg(network ? network->getName() : "<no network?>");
// The DDNS parameters may have changed with the subnet, so we need to
// recalculate the client name.
// The subnet changed so we need to recalculate the FQDN.
reprocess_client_name = true;
}
// Save the current DNS values on the context.
std::string prev_hostname = ctx.hostname_;
bool prev_fwd_dns_update = ctx.fwd_dns_update_;
bool prev_rev_dns_update = ctx.rev_dns_update_;
// Recalulate the FQDN if either the pool has DDNS parameters or the
// selected subnet was changed.
if (reprocess_client_name) {
// Save the current DNS values on the context.
std::string prev_hostname = ctx.hostname_;
bool prev_fwd_dns_update = ctx.fwd_dns_update_;
bool prev_rev_dns_update = ctx.rev_dns_update_;
// Remove the current FQDN option from the answer.
answer->delOption(D6O_CLIENT_FQDN);
// Remove the current FQDN option from the answer.
answer->delOption(D6O_CLIENT_FQDN);
// Recalculate the client's FQDN. This will replace the FQDN option and
// update the context values for hostname_ and DNS directions.
processClientFqdn(question, answer, ctx);
// Recalculate the client's FQDN. This will replace the FQDN option and
// update the context values for hostname_ and DNS directions.
processClientFqdn(question, answer, ctx);
// If this is a real allocation and the DNS values changed we need to
// update the leases.
if (!ctx.fake_allocation_ &&
((prev_hostname != ctx.hostname_) ||
(prev_fwd_dns_update != ctx.fwd_dns_update_) ||
(prev_rev_dns_update != ctx.rev_dns_update_))) {
for (auto const& l : ctx.new_leases_) {
l->hostname_ = ctx.hostname_;
l->fqdn_fwd_ = ctx.fwd_dns_update_;
l->fqdn_rev_ = ctx.rev_dns_update_;
l->reuseable_valid_lft_ = 0;
LeaseMgrFactory::instance().updateLease6(l);
// If this is a real allocation and the DNS values changed we need to
// update the leases.
if (!ctx.fake_allocation_ &&
((prev_hostname != ctx.hostname_) ||
(prev_fwd_dns_update != ctx.fwd_dns_update_) ||
(prev_rev_dns_update != ctx.rev_dns_update_))) {
for (auto const& l : ctx.new_leases_) {
l->hostname_ = ctx.hostname_;
l->fqdn_fwd_ = ctx.fwd_dns_update_;
l->fqdn_rev_ = ctx.rev_dns_update_;
l->reuseable_valid_lft_ = 0;
LeaseMgrFactory::instance().updateLease6(l);
}
}
}
}

View File

@@ -1030,18 +1030,18 @@ protected:
/// @brief Iterates over new leases, update stale DNS entries
///
/// Checks the context's current subnet (most recently selected) against
/// an original selected subnet. If they are the same the function
/// simply returns.
/// Updates the context DDNS parameters to include those from the pool
/// associated with the first active NA lease address and then checks
/// to see if the subnet has been dynamicaly changed. If either the
/// pool has DDNS parameters or the subnet has changed the FQDN and
/// DDNS flags are recalculated in the event the pool or subnet change
/// introduced different parameter values otherwise the function returns.
///
/// If they differ, we treat this as a dynamic subnet change made by the
/// allocation engine. It is possible that DDNS subnet parameters for
/// the new subnet are different and this needs to handled. We first
/// save the current DNS-related values from the context and then
/// re-run processClientFqdn(). This will rebuild the FQDN option
/// to send back to the client based on the new subnet as well as
/// update the context. If the new values are different from the
/// previous values, we iterate over the leases and update the
/// When recalculating we first save the current DNS-related values
/// from the context and then re-run processClientFqdn(). This will
/// rebuild the FQDN option to send back to the client based on the new
/// subnet as well as update the context. If the new values are different
/// from the previous values, we iterate over the leases and update the
/// DNS values.
///
/// @param question Client's message.
@@ -1063,9 +1063,9 @@ protected:
/// class guards etc)
/// 3. subnets have differing options or DDNS parameters
//
void checkDynamicSubnetChange(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const ConstSubnet6Ptr orig_subnet);
void checkPostAssignmentChanges(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const ConstSubnet6Ptr orig_subnet);
/// @brief Return the PD exclude option to include.
///

View File

@@ -341,7 +341,6 @@ const SimpleKeywords SimpleParser4::POOL4_PARAMETERS = {
{ "evaluate-additional-classes", Element::list },
{ "user-context", Element::map },
{ "comment", Element::string },
{ "metadata", Element::map },
{ "ddns-send-updates", Element::boolean },
{ "ddns-override-no-update", Element::boolean },
{ "ddns-override-client-update", Element::boolean },
@@ -355,7 +354,8 @@ const SimpleKeywords SimpleParser4::POOL4_PARAMETERS = {
{ "ddns-conflict-resolution-mode", Element::string },
{ "ddns-ttl", Element::integer },
{ "ddns-ttl-min", Element::integer },
{ "ddns-ttl-max", Element::integer }
{ "ddns-ttl-max", Element::integer },
{ "metadata", Element::map }
};
/// @brief This table defines all shared network parameters for DHCPv4.

View File

@@ -323,16 +323,30 @@ const ParamsList SimpleParser6::INHERIT_TO_SUBNET6 = {
/// list and map types for entries.
/// Order follows pool_param rules in bison grammar.
const SimpleKeywords SimpleParser6::POOL6_PARAMETERS = {
{ "pool", Element::string },
{ "pool-id", Element::integer },
{ "option-data", Element::list },
{ "client-class", Element::string },
{ "client-classes", Element::list },
{ "require-client-classes", Element::list },
{ "evaluate-additional-classes", Element::list },
{ "user-context", Element::map },
{ "comment", Element::string },
{ "metadata", Element::map }
{ "pool", Element::string },
{ "pool-id", Element::integer },
{ "option-data", Element::list },
{ "client-class", Element::string },
{ "client-classes", Element::list },
{ "require-client-classes", Element::list },
{ "evaluate-additional-classes", Element::list },
{ "user-context", Element::map },
{ "comment", Element::string },
{ "ddns-send-updates", Element::boolean },
{ "ddns-override-no-update", Element::boolean },
{ "ddns-override-client-update", Element::boolean },
{ "ddns-replace-client-name", Element::string },
{ "ddns-generated-prefix", Element::string },
{ "ddns-qualifying-suffix", Element::string },
{ "hostname-char-set", Element::string },
{ "hostname-char-replacement", Element::string },
{ "ddns-update-on-renew", Element::boolean },
{ "ddns-ttl-percent", Element::real },
{ "ddns-conflict-resolution-mode", Element::string },
{ "ddns-ttl", Element::integer },
{ "ddns-ttl-min", Element::integer },
{ "ddns-ttl-max", Element::integer },
{ "metadata", Element::map }
};
/// @brief This table defines all prefix delegation pool parameters.

View File

@@ -1244,7 +1244,8 @@ DdnsParams::setPoolFromAddress(const asiolink::IOAddress& address) {
"DdnsParams::setPoolFromAddress called without a subnet");
}
pool_ = subnet_->getPool((address.isV4() ? Lease::TYPE_V4 : Lease::TYPE_NA), address, false);
pool_ = subnet_->getPool((address.isV4() ? Lease::TYPE_V4 : Lease::TYPE_NA),
address, false);
return (pool_);
}

View File

@@ -100,49 +100,49 @@ public:
__LINE__,
R"^({
"id": 1,
"ddns-ttl-percent": 5.0
"ddns-ttl-percent": 5.0
})^",
5.0, 0, 0, 0
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-min": 25
"ddns-ttl-min": 25
})^",
0.0, 0, 25, 0
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-max": 150
"id": 1,
"ddns-ttl-max": 150
})^",
0.0, 0, 0, 150
0.0, 0, 0, 150
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-min": 25,
"ddns-ttl-max": 150
"ddns-ttl-max": 150
})^",
0.0, 0, 25, 150
0.0, 0, 25, 150
},{
__LINE__,
R"^({
"id": 1, "subnet": "192.0.2.0/24",
"ddns-ttl-percent": 5.0,
"ddns-ttl-min": 25,
"ddns-ttl-max": 150
"ddns-ttl-max": 150
})^",
5.0, 0, 25, 150
5.0, 0, 25, 150
}};
ElementPtr subnet_elem = Element::create(family == AF_INET ?
"192.0.2.0/24" : "2001:db8::/64");
"192.0.2.0/24" : "2001:db8::/64");
for (const auto& scenario : scenarios) {
std::stringstream oss;
std::stringstream oss;
oss << "scenario at " << scenario.line_no_;
SCOPED_TRACE(oss.str());
// Parse configuration specified above.
ElementPtr config_element;
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
@@ -151,24 +151,24 @@ public:
ParserType parser(family);
NetworkPtrType subnet;
ASSERT_NO_THROW_LOG(subnet = parser.parse(config_element));
ASSERT_TRUE(subnet);
EXPECT_EQ(subnet->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
EXPECT_EQ(subnet->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
EXPECT_EQ(subnet->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
EXPECT_EQ(subnet->getDdnsTtl(), scenario.ddns_ttl_);
EXPECT_EQ(subnet->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
EXPECT_EQ(subnet->getDdnsTtlMin(), scenario.ddns_ttl_min_);
EXPECT_EQ(subnet->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
EXPECT_EQ(subnet->getDdnsTtlMax(), scenario.ddns_ttl_max_);
EXPECT_EQ(subnet->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
EXPECT_EQ(subnet->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
EXPECT_EQ(subnet->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
EXPECT_EQ(subnet->getDdnsTtl(), scenario.ddns_ttl_);
EXPECT_EQ(subnet->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
EXPECT_EQ(subnet->getDdnsTtlMin(), scenario.ddns_ttl_min_);
EXPECT_EQ(subnet->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
EXPECT_EQ(subnet->getDdnsTtlMax(), scenario.ddns_ttl_max_);
}
}
// Verifies invalid permutations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
template<typename ParserType>
@@ -178,7 +178,7 @@ public:
std::string json_;
std::string exp_message_;
};
std::list<Scenario> scenarios = {
{
__LINE__,
@@ -201,7 +201,7 @@ public:
R"^({
"id": 1,
"ddns-ttl": 100,
"ddns-ttl-max": 150
"ddns-ttl-max": 150
})^",
"subnet configuration failed: cannot specify both ddns-ttl-max and ddns-ttl"
},{
@@ -209,18 +209,18 @@ public:
R"^({
"id": 1,
"ddns-ttl-min": 150,
"ddns-ttl-max": 25
"ddns-ttl-max": 25
})^",
"subnet configuration failed: ddns-ttl-max: 25 must be greater than ddns-ttl-min: 150"
}};
ElementPtr subnet_elem = Element::create(family == AF_INET ?
"192.0.2.0/24" : "2001:db8::/64");
"192.0.2.0/24" : "2001:db8::/64");
for (const auto& scenario : scenarios) {
std::stringstream oss;
std::stringstream oss;
oss << "scenario at " << scenario.line_no_;
SCOPED_TRACE(oss.str());
// Parse configuration specified above.
ElementPtr config_element;
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
@@ -229,6 +229,121 @@ public:
ASSERT_THROW_MSG(parser.parse(config_element), DhcpConfigError, scenario.exp_message_);
}
}
/// @brief Tests valid DDNS parameters in v4 or v6 pools.
///
/// As this uses the
/// same parser as Network derivatives we skip retesting all the
/// invalid permuations. This test ensures all supported
/// parameters can be set.
/// @tparam PoolListParserType type of pool list parser to use, Pools4ListParser
/// or Pools6ListParser.
/// @param pool1 string pool specification for the first pool
/// @param pool2 string pool specification for the first pool
template<typename PoolListParserType>
void validPoolDdnsParmaters(const std::string& pool1, const std::string& pool2) {
std::stringstream ss;
ss <<
R"^([{ "pool": ")^" << pool1 << "\"," <<
R"^(
"ddns-send-updates": true,
"ddns-override-no-update": true,
"ddns-override-client-update": true,
"ddns-replace-client-name": "always",
"ddns-generated-prefix": "prefix",
"ddns-qualifying-suffix": "suffix",
"hostname-char-set": "[a-z]",
"hostname-char-replacement": "X",
"ddns-update-on-renew": true,
"ddns-ttl-percent": 0.5,
"ddns-conflict-resolution-mode": "check-with-dhcid",
"ddns-ttl-min": 200,
"ddns-ttl-max": 500
},
{
"pool": ")^" << pool2 << "\"," <<
R"^(
"ddns-ttl": 300
}])^";
ElementPtr config_element = Element::fromJSON(ss.str());
PoolStoragePtr pools(new PoolStorage());
PoolListParserType parser;
ASSERT_NO_THROW_LOG(parser.parse(pools, config_element));
// Should have two pools.
ASSERT_EQ(pools->size(), 2);
// First pool specifies all but ddns-ttl.
PoolPtr pool = (*pools)[0];
ASSERT_TRUE(pool);
ASSERT_FALSE(pool->getDdnsSendUpdates().unspecified());
EXPECT_TRUE(pool->getDdnsSendUpdates().get());
ASSERT_FALSE(pool->getDdnsOverrideNoUpdate().unspecified());
EXPECT_TRUE(pool->getDdnsOverrideNoUpdate().get());
ASSERT_FALSE(pool->getDdnsOverrideClientUpdate().unspecified());
EXPECT_TRUE(pool->getDdnsOverrideClientUpdate().get());
ASSERT_FALSE(pool->getDdnsReplaceClientNameMode().unspecified());
EXPECT_EQ(pool->getDdnsReplaceClientNameMode().get(),
D2ClientConfig::RCM_ALWAYS);
ASSERT_FALSE(pool->getDdnsGeneratedPrefix().unspecified());
EXPECT_EQ(pool->getDdnsGeneratedPrefix().get(), "prefix");
ASSERT_FALSE(pool->getDdnsQualifyingSuffix().unspecified());
EXPECT_EQ(pool->getDdnsQualifyingSuffix().get(), "suffix");
ASSERT_FALSE(pool->getHostnameCharSet().unspecified());
EXPECT_EQ(pool->getHostnameCharSet().get(), "[a-z]");
ASSERT_FALSE(pool->getHostnameCharReplacement().unspecified());
EXPECT_EQ(pool->getHostnameCharReplacement().get(), "X");
ASSERT_FALSE(pool->getDdnsUpdateOnRenew().unspecified());
EXPECT_TRUE(pool->getDdnsUpdateOnRenew().get());
ASSERT_FALSE(pool->getDdnsTtlPercent().unspecified());
EXPECT_EQ(pool->getDdnsTtlPercent().get(), 0.5);
ASSERT_FALSE(pool->getDdnsConflictResolutionMode().unspecified());
EXPECT_EQ(pool->getDdnsConflictResolutionMode().get(), "check-with-dhcid");
ASSERT_TRUE(pool->getDdnsTtl().unspecified());
ASSERT_FALSE(pool->getDdnsTtlMin().unspecified());
EXPECT_EQ(pool->getDdnsTtlMin().get(), 200);
ASSERT_FALSE(pool->getDdnsTtlMax().unspecified());
EXPECT_EQ(pool->getDdnsTtlMax().get(), 500);
// Second pool only specifies ddns-ttl.
pool = (*pools)[1];
ASSERT_TRUE(pool);
ASSERT_TRUE(pool->getDdnsSendUpdates().unspecified());
ASSERT_TRUE(pool->getDdnsOverrideNoUpdate().unspecified());
ASSERT_TRUE(pool->getDdnsOverrideClientUpdate().unspecified());
ASSERT_TRUE(pool->getDdnsReplaceClientNameMode().unspecified());
ASSERT_TRUE(pool->getDdnsGeneratedPrefix().unspecified());
ASSERT_TRUE(pool->getDdnsQualifyingSuffix().unspecified());
ASSERT_TRUE(pool->getHostnameCharSet().unspecified());
ASSERT_TRUE(pool->getHostnameCharReplacement().unspecified());
ASSERT_TRUE(pool->getDdnsUpdateOnRenew().unspecified());
ASSERT_TRUE(pool->getDdnsTtlPercent().unspecified());
ASSERT_TRUE(pool->getDdnsConflictResolutionMode().unspecified());
ASSERT_TRUE(pool->getDdnsTtlMin().unspecified());
ASSERT_FALSE(pool->getDdnsTtl().unspecified());
EXPECT_EQ(pool->getDdnsTtl().get(), 300);
ASSERT_TRUE(pool->getDdnsTtlMax().unspecified());
}
};
/// Verifies the code that parses mac sources and adds them to CfgMgr
@@ -4231,7 +4346,7 @@ TEST_F(DhcpParserTest, deprecatedClientClassSubnet6) {
}
// Verify that deprecated client-class is handled properly
// by Pool4 parser.
// by Pool4 parser.
TEST_F(DhcpParserTest, deprecatedClientClassPool4) {
// Valid entry.
std::string config =
@@ -4337,110 +4452,14 @@ TEST_F(DhcpParserTest, invalidDdnsTtlParmatersSubnet6) {
invalidDdnsTtlParmatersSubnet<Subnet6ConfigParser>(AF_INET6);
}
// Verifies valid DDNS parameters in v4 pools. As this uses the
// same parser as Network derivatives we skip retesting all the
// invalid permuations. This test ensures all supported
// parameters can be set.
// Verifies valid DDNS parameters in v4 pools.
TEST_F(DhcpParserTest, validDdnsParmatersPool4) {
validPoolDdnsParmaters<Pools4ListParser>("192.0.1.0/24", "192.0.2.0/24");
}
std::string config =
R"^([{
"pool": "192.0.1.0/24",
"ddns-send-updates": true,
"ddns-override-no-update": true,
"ddns-override-client-update": true,
"ddns-replace-client-name": "always",
"ddns-generated-prefix": "prefix",
"ddns-qualifying-suffix": "suffix",
"hostname-char-set": "[a-z]",
"hostname-char-replacement": "X",
"ddns-update-on-renew": true,
"ddns-ttl-percent": 0.5,
"ddns-conflict-resolution-mode": "check-with-dhcid",
"ddns-ttl-min": 200,
"ddns-ttl-max": 500
},
{
"pool": "192.0.2.0/24",
"ddns-ttl": 300
}])^";
ElementPtr config_element = Element::fromJSON(config);
PoolStoragePtr pools(new PoolStorage());
Pools4ListParser parser;
ASSERT_NO_THROW_LOG(parser.parse(pools, config_element));
// Should have two pools.
ASSERT_EQ(pools->size(), 2);
// First pool specifies all but ddns-ttl.
PoolPtr pool = (*pools)[0];
ASSERT_TRUE(pool);
ASSERT_FALSE(pool->getDdnsSendUpdates().unspecified());
EXPECT_TRUE(pool->getDdnsSendUpdates().get());
ASSERT_FALSE(pool->getDdnsOverrideNoUpdate().unspecified());
EXPECT_TRUE(pool->getDdnsOverrideNoUpdate().get());
ASSERT_FALSE(pool->getDdnsOverrideClientUpdate().unspecified());
EXPECT_TRUE(pool->getDdnsOverrideClientUpdate().get());
ASSERT_FALSE(pool->getDdnsReplaceClientNameMode().unspecified());
EXPECT_EQ(pool->getDdnsReplaceClientNameMode().get(),
D2ClientConfig::RCM_ALWAYS);
ASSERT_FALSE(pool->getDdnsGeneratedPrefix().unspecified());
EXPECT_EQ(pool->getDdnsGeneratedPrefix().get(), "prefix");
ASSERT_FALSE(pool->getDdnsQualifyingSuffix().unspecified());
EXPECT_EQ(pool->getDdnsQualifyingSuffix().get(), "suffix");
ASSERT_FALSE(pool->getHostnameCharSet().unspecified());
EXPECT_EQ(pool->getHostnameCharSet().get(), "[a-z]");
ASSERT_FALSE(pool->getHostnameCharReplacement().unspecified());
EXPECT_EQ(pool->getHostnameCharReplacement().get(), "X");
ASSERT_FALSE(pool->getDdnsUpdateOnRenew().unspecified());
EXPECT_TRUE(pool->getDdnsUpdateOnRenew().get());
ASSERT_FALSE(pool->getDdnsTtlPercent().unspecified());
EXPECT_EQ(pool->getDdnsTtlPercent().get(), 0.5);
ASSERT_FALSE(pool->getDdnsConflictResolutionMode().unspecified());
EXPECT_EQ(pool->getDdnsConflictResolutionMode().get(), "check-with-dhcid");
ASSERT_TRUE(pool->getDdnsTtl().unspecified());
ASSERT_FALSE(pool->getDdnsTtlMin().unspecified());
EXPECT_EQ(pool->getDdnsTtlMin().get(), 200);
ASSERT_FALSE(pool->getDdnsTtlMax().unspecified());
EXPECT_EQ(pool->getDdnsTtlMax().get(), 500);
// Second pool only specifies ddns-ttl.
pool = (*pools)[1];
ASSERT_TRUE(pool);
ASSERT_TRUE(pool->getDdnsSendUpdates().unspecified());
ASSERT_TRUE(pool->getDdnsOverrideNoUpdate().unspecified());
ASSERT_TRUE(pool->getDdnsOverrideClientUpdate().unspecified());
ASSERT_TRUE(pool->getDdnsReplaceClientNameMode().unspecified());
ASSERT_TRUE(pool->getDdnsGeneratedPrefix().unspecified());
ASSERT_TRUE(pool->getDdnsQualifyingSuffix().unspecified());
ASSERT_TRUE(pool->getHostnameCharSet().unspecified());
ASSERT_TRUE(pool->getHostnameCharReplacement().unspecified());
ASSERT_TRUE(pool->getDdnsUpdateOnRenew().unspecified());
ASSERT_TRUE(pool->getDdnsTtlPercent().unspecified());
ASSERT_TRUE(pool->getDdnsConflictResolutionMode().unspecified());
ASSERT_TRUE(pool->getDdnsTtlMin().unspecified());
ASSERT_FALSE(pool->getDdnsTtl().unspecified());
EXPECT_EQ(pool->getDdnsTtl().get(), 300);
ASSERT_TRUE(pool->getDdnsTtlMax().unspecified());
// Verifies valid DDNS parameters in v6 pools.
TEST_F(DhcpParserTest, validDdnsParmatersPool6) {
validPoolDdnsParmaters<Pools6ListParser>("2001:db8:1::/64", "2001:db8:2::/64");
}
} // Anonymous namespace