2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 13:07:50 +00:00

[#2819] kea-dhcp4 supports ddns-ttl, min, and max

Added support for ddns-ttl,ddns-ttl-min, and ddsn-ttl-max
to global,shared-network, and subnet for kea-dhcp4

Changes to be committed:
modified:   doc/examples/kea4/all-keys.json
modified:   src/bin/dhcp4/dhcp4_lexer.cc
modified:   src/bin/dhcp4/dhcp4_lexer.ll
modified:   src/bin/dhcp4/dhcp4_parser.cc
modified:   src/bin/dhcp4/dhcp4_parser.h
modified:   src/bin/dhcp4/dhcp4_parser.yy
modified:   src/bin/dhcp4/json_config_parser.cc
modified:   src/bin/dhcp4/tests/config_parser_unittest.cc
modified:   src/bin/dhcp4/tests/fqdn_unittest.cc
modified:   src/bin/dhcp4/tests/get_config_unittest.cc
modified:   src/bin/dhcp6/json_config_parser.cc
modified:   src/lib/dhcpsrv/cb_ctl_dhcp4.cc
modified:   src/lib/dhcpsrv/cb_ctl_dhcp6.cc
modified:   src/lib/dhcpsrv/cfg_globals.cc
modified:   src/lib/dhcpsrv/cfg_globals.h
modified:   src/lib/dhcpsrv/dhcpsrv_messages.cc
modified:   src/lib/dhcpsrv/dhcpsrv_messages.h
modified:   src/lib/dhcpsrv/dhcpsrv_messages.mes
modified:   src/lib/dhcpsrv/ncr_generator.cc
modified:   src/lib/dhcpsrv/ncr_generator.h
modified:   src/lib/dhcpsrv/network.cc
modified:   src/lib/dhcpsrv/network.h
modified:   src/lib/dhcpsrv/parsers/base_network_parser.cc
modified:   src/lib/dhcpsrv/parsers/simple_parser4.cc
modified:   src/lib/dhcpsrv/parsers/simple_parser6.cc
modified:   src/lib/dhcpsrv/srv_config.cc
modified:   src/lib/dhcpsrv/srv_config.h
modified:   src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
modified:   src/lib/dhcpsrv/tests/ncr_generator_unittest.cc
modified:   src/lib/dhcpsrv/tests/network_unittest.cc
modified:   src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc
modified:   src/lib/dhcpsrv/tests/srv_config_unittest.cc
modified:   src/lib/util/str.cc
modified:   src/lib/util/str.h
This commit is contained in:
Thomas Markwalder 2024-11-19 15:23:08 -05:00
parent f4a25f1776
commit f414f9aa2d
34 changed files with 6420 additions and 4510 deletions

View File

@ -344,6 +344,17 @@
// to use for the DNS TTL.
"ddns-ttl-percent": 0.75,
// When greater than 0 it will be used as the DNS TTL. Specified in seconds.
"ddns-ttl": 0,
// When greater than 0 it used as the lower boundary for calculated DNS TTL values.
// Specified in seconds.
"ddns-ttl-min": 24000,
// When greater than 0 it used as the upper boundary for calculated DNS TTL values.
// Specified in seconds.
"ddns-ttl-max": 64000,
// Time in seconds specifying how long a declined lease should be
// excluded from DHCP assignments. The default value is 86400 (24 hours).
"decline-probation-period": 86400,
@ -895,6 +906,15 @@
// Shared-network level value. See description at the global level.
"ddns-ttl-percent": 0.65,
// Shared-network level value. See description at the global level.
"ddns-ttl": 0,
// Shared-network level value. See description at the global level.
"ddns-ttl-min": 10000,
// Shared-network level value. See description at the global level.
"ddns-ttl-max": 20000,
// Shared-network level value. See description at the global level.
"hostname-char-replacement": "x",
@ -1035,6 +1055,15 @@
// Subnet-level value. See description at the global level.
"ddns-ttl-percent": 0.55,
// Subnet-level value. See description at the global level.
"ddns-ttl": 0,
// Subnet-evel value. See description at the global level.
"ddns-ttl-min": 10000,
// Subnet-level value. See description at the global level.
"ddns-ttl-max": 20000,
// Subnet-level value. See description at the global level.
"hostname-char-replacement": "x",

File diff suppressed because it is too large Load Diff

View File

@ -905,6 +905,39 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
}
}
\"ddns-ttl\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_DDNS_TTL(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("ddns-ttl", driver.loc_);
}
}
\"ddns-ttl-min\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_DDNS_TTL_MIN(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("ddns-ttl-min", driver.loc_);
}
}
\"ddns-ttl-max\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
case isc::dhcp::Parser4Context::SHARED_NETWORK:
return isc::dhcp::Dhcp4Parser::make_DDNS_TTL_MAX(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("ddns-ttl-max", driver.loc_);
}
}
\"subnet4\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -137,6 +137,9 @@ using namespace std;
DDNS_UPDATE_ON_RENEW "ddns-update-on-renew"
DDNS_USE_CONFLICT_RESOLUTION "ddns-use-conflict-resolution"
DDNS_TTL_PERCENT "ddns-ttl-percent"
DDNS_TTL "ddns-ttl"
DDNS_TTL_MIN "ddns-ttl-min"
DDNS_TTL_MAX "ddns-ttl-mix"
STORE_EXTENDED_INFO "store-extended-info"
SUBNET4 "subnet4"
SUBNET_4O6_INTERFACE "4o6-interface"
@ -566,6 +569,9 @@ global_param: valid_lifetime
| ddns_use_conflict_resolution
| ddns_conflict_resolution_mode
| ddns_ttl_percent
| ddns_ttl
| ddns_ttl_min
| ddns_ttl_max
| store_extended_info
| statistic_default_sample_count
| statistic_default_sample_age
@ -800,6 +806,24 @@ ddns_ttl_percent: DDNS_TTL_PERCENT COLON FLOAT {
ctx.stack_.back()->set("ddns-ttl-percent", ttl);
};
ddns_ttl: DDNS_TTL COLON INTEGER {
ctx.unique("ddns-ttl", ctx.loc2pos(@1));
ElementPtr ttl(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("ddns-ttl", ttl);
};
ddns_ttl_min: DDNS_TTL_MIN COLON INTEGER {
ctx.unique("ddns-ttl-min", ctx.loc2pos(@1));
ElementPtr ttl(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("ddns-ttl-min", ttl);
};
ddns_ttl_max: DDNS_TTL_MAX COLON INTEGER {
ctx.unique("ddns-ttl-max", ctx.loc2pos(@1));
ElementPtr ttl(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("ddns-ttl-max", ttl);
};
hostname_char_set: HOSTNAME_CHAR_SET {
ctx.unique("hostname-char-set", ctx.loc2pos(@1));
ctx.enter(ctx.NO_KEYWORD);
@ -1636,6 +1660,9 @@ subnet4_param: valid_lifetime
| ddns_use_conflict_resolution
| ddns_conflict_resolution_mode
| ddns_ttl_percent
| ddns_ttl
| ddns_ttl_min
| ddns_ttl_max
| hostname_char_set
| hostname_char_replacement
| store_extended_info
@ -1837,6 +1864,9 @@ shared_network_param: name
| ddns_use_conflict_resolution
| ddns_conflict_resolution_mode
| ddns_ttl_percent
| ddns_ttl
| ddns_ttl_min
| ddns_ttl_max
| hostname_char_set
| hostname_char_replacement
| store_extended_info

View File

@ -195,6 +195,9 @@ public:
/// Global lifetime sanity checks
cfg->sanityChecksLifetime("valid-lifetime");
/// Sanity check global ddns-ttl parameters
cfg->sanityChecksDdnsTtlParameters();
/// Shared network sanity checks
const SharedNetwork4Collection* networks = cfg->getCfgSharedNetworks4()->getAll();
if (networks) {
@ -673,7 +676,10 @@ processDhcp4Config(isc::data::ConstElementPtr config_set) {
(config_pair.first == "parked-packet-limit") ||
(config_pair.first == "allocator") ||
(config_pair.first == "offer-lifetime") ||
(config_pair.first == "stash-agent-options") ) {
(config_pair.first == "ddns-ttl") ||
(config_pair.first == "ddns-ttl-min") ||
(config_pair.first == "ddns-ttl-max") ||
(config_pair.first == "stash-agent-options")) {
CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
config_pair.second);
continue;

View File

@ -8269,4 +8269,180 @@ TEST_F(Dhcp4ParserTest, deprecatedClientClassesCheck) {
" and 'client-classes'. Use only the latter.");
}
TEST_F(Dhcp4ParserTest, ddnsTtlPercent) {
string config = R"(
{
"ddns-ttl-percent": 0.75,
"valid-lifetime": 4000,
"shared-networks": [{
"name": "net",
"ddns-ttl-percent": 0.50,
"subnet4": [{
"id": 1,
"subnet": "10.0.2.0/24",
"ddns-ttl-percent": 0.25
}],
}]
}
)";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
ConstElementPtr status;
EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// Commit it so global inheritance works.
CfgMgr::instance().commit();
ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("10.0.2.0"));
ASSERT_TRUE(subnet);
EXPECT_FALSE(subnet->getDdnsTtlPercent(Network::Inheritance::NONE).unspecified());
EXPECT_EQ(0.25, subnet->getDdnsTtlPercent(Network::Inheritance::NONE).get());
EXPECT_FALSE(subnet->getDdnsTtlPercent(Network::Inheritance::PARENT_NETWORK).unspecified());
EXPECT_EQ(0.50, subnet->getDdnsTtlPercent(Network::Inheritance::PARENT_NETWORK).get());
EXPECT_FALSE(subnet->getDdnsTtlPercent(Network::Inheritance::GLOBAL).unspecified());
EXPECT_EQ(0.75, subnet->getDdnsTtlPercent(Network::Inheritance::GLOBAL).get());
}
TEST_F(Dhcp4ParserTest, ddnsTtl) {
string config = R"(
{
"ddns-ttl": 750,
"valid-lifetime": 4000,
"shared-networks": [{
"name": "net",
"ddns-ttl": 500,
"subnet4": [{
"id": 1,
"subnet": "10.0.2.0/24",
"ddns-ttl": 250
}],
}]
}
)";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
ConstElementPtr status;
EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// Commit it so global inheritance works.
CfgMgr::instance().commit();
ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("10.0.2.0"));
ASSERT_TRUE(subnet);
EXPECT_FALSE(subnet->getDdnsTtl(Network::Inheritance::NONE).unspecified());
EXPECT_EQ(250, subnet->getDdnsTtl(Network::Inheritance::NONE).get());
EXPECT_FALSE(subnet->getDdnsTtl(Network::Inheritance::PARENT_NETWORK).unspecified());
EXPECT_EQ(500, subnet->getDdnsTtl(Network::Inheritance::PARENT_NETWORK).get());
EXPECT_FALSE(subnet->getDdnsTtl(Network::Inheritance::GLOBAL).unspecified());
EXPECT_EQ(750, subnet->getDdnsTtl(Network::Inheritance::GLOBAL).get());
}
TEST_F(Dhcp4ParserTest, ddnsTtlMin) {
string config = R"(
{
"ddns-ttl-min": 750,
"valid-lifetime": 4000,
"shared-networks": [{
"name": "net",
"ddns-ttl-min": 500,
"subnet4": [{
"id": 1,
"subnet": "10.0.2.0/24",
"ddns-ttl-min": 250
}],
}]
}
)";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
ConstElementPtr status;
EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// Commit it so global inheritance works.
CfgMgr::instance().commit();
ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("10.0.2.0"));
ASSERT_TRUE(subnet);
EXPECT_FALSE(subnet->getDdnsTtlMin(Network::Inheritance::NONE).unspecified());
EXPECT_EQ(250, subnet->getDdnsTtlMin(Network::Inheritance::NONE).get());
EXPECT_FALSE(subnet->getDdnsTtlMin(Network::Inheritance::PARENT_NETWORK).unspecified());
EXPECT_EQ(500, subnet->getDdnsTtlMin(Network::Inheritance::PARENT_NETWORK).get());
EXPECT_FALSE(subnet->getDdnsTtlMin(Network::Inheritance::GLOBAL).unspecified());
EXPECT_EQ(750, subnet->getDdnsTtlMin(Network::Inheritance::GLOBAL).get());
}
TEST_F(Dhcp4ParserTest, ddnsTtlMax) {
string config = R"(
{
"ddns-ttl-max": 750,
"valid-lifetime": 4000,
"shared-networks": [{
"name": "net",
"ddns-ttl-max": 500,
"subnet4": [{
"id": 1,
"subnet": "10.0.2.0/24",
"ddns-ttl-max": 250
}],
}]
}
)";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
ConstElementPtr status;
EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json));
// returned value should be 0 (success)
checkResult(status, 0);
// Commit it so global inheritance works.
CfgMgr::instance().commit();
ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("10.0.2.0"));
ASSERT_TRUE(subnet);
EXPECT_FALSE(subnet->getDdnsTtlMax(Network::Inheritance::NONE).unspecified());
EXPECT_EQ(250, subnet->getDdnsTtlMax(Network::Inheritance::NONE).get());
EXPECT_FALSE(subnet->getDdnsTtlMax(Network::Inheritance::PARENT_NETWORK).unspecified());
EXPECT_EQ(500, subnet->getDdnsTtlMax(Network::Inheritance::PARENT_NETWORK).get());
EXPECT_FALSE(subnet->getDdnsTtlMax(Network::Inheritance::GLOBAL).unspecified());
EXPECT_EQ(750, subnet->getDdnsTtlMax(Network::Inheritance::GLOBAL).get());
}
} // namespace

View File

@ -772,6 +772,100 @@ public:
}
/// @brief Verifies that DDNS TTL parameters are used when specified.
///
/// @param valid_flt lease life time
/// @param ddns_ttl_percent expected configured value for ddns-ttl-percent
/// @param ddns_ttl expected configured value for ddns-ttl
/// @param ddns_ttl_min expected configured value for ddns-ttl-min
/// @param ddns_ttl_max expected configured value for ddns-ttl-max
void testDdnsTtlParameters(uint32_t valid_lft,
Optional<double> ddns_ttl_percent = Optional<double>(),
Optional<uint32_t> ddns_ttl = Optional<uint32_t>(),
Optional<uint32_t> ddns_ttl_min = Optional<uint32_t>(),
Optional<uint32_t> ddns_ttl_max = Optional<uint32_t>()) {
std::string config_header = R"(
{
"interfaces-config": { "interfaces": [ "*" ] },
"subnet4": [ {
"subnet": "10.0.0.0/24",
"interface": "eth1",
"id": 1,
"pools": [ { "pool": "10.0.0.10-10.0.0.10" } ]
)";
std::string config_footer = R"(
}],
"ddns-qualifying-suffix": "example.com.",
"dhcp-ddns": { "enable-updates": true }
}
)";
std::stringstream oss;
oss << config_header;
oss << ",\n \"valid-lifetime\":" << valid_lft;
if (!ddns_ttl_percent.unspecified()) {
oss << ",\n, \"ddns-ttl-percent\" :" << util::str::dumpDouble(ddns_ttl_percent.get());
}
if (!ddns_ttl.unspecified()) {
oss << ",\n, \"ddns-ttl\" :" << ddns_ttl.get();
}
if (!ddns_ttl_min.unspecified()) {
oss << ",\n, \"ddns-ttl-min\" :" << ddns_ttl_min.get();
}
if (!ddns_ttl_max.unspecified()) {
oss << ",\n, \"ddns-ttl-max\" :" << ddns_ttl_max.get();
}
oss << "\n" << config_footer;
// Load a configuration with D2 enabled and ddns-ttl* parameters.
ASSERT_NO_FATAL_FAILURE(configure(oss.str(), *srv_));
ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
// Create a client and get a lease.
Dhcp4Client client1(srv_, Dhcp4Client::SELECTING);
client1.setIfaceName("eth1");
client1.setIfaceIndex(ETH1_INDEX);
ASSERT_NO_THROW(client1.includeHostname("client1"));
// Do the DORA.
ASSERT_NO_THROW(client1.doDORA());
Pkt4Ptr resp = client1.getContext().response_;
ASSERT_TRUE(resp);
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
// Obtain the Hostname option sent in the response and make sure that the server
// has used the hostname reserved for this client.
OptionStringPtr hostname;
hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
ASSERT_TRUE(hostname);
EXPECT_EQ("client1.example.com", hostname->getValue());
// Make sure the lease is in the database and hostname is correct.
Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(IOAddress("10.0.0.10"));
ASSERT_TRUE(lease);
EXPECT_EQ("client1.example.com", lease->hostname_);
// Verify that an NCR was generated correctly.
ASSERT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
resp->getYiaddr().toText(),
"client1.example.com.", "",
time(NULL), lease->valid_lft_, true,
CHECK_WITH_DHCID,
ddns_ttl_percent,
ddns_ttl,
ddns_ttl_min,
ddns_ttl_max);
}
///@brief Verify that NameChangeRequest holds valid values.
///
/// Pulls the NCR from the top of the send queue and checks its content
@ -794,6 +888,10 @@ public:
/// lease expiration time is conducted as greater than or equal to rather
/// equal to CLTT plus lease ttl .
/// @param exp_conflict_resolution_mode expected value of conflict resolution mode
/// @param ddns_ttl_percent expected configured value for ddns-ttl-percent
/// @param ddns_ttl expected configured value for ddns-ttl
/// @param ddns_ttl_min expected configured value for ddns-ttl-min
/// @param ddns_ttl_max expected configured value for ddns-ttl-max
void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
const bool reverse, const bool forward,
const std::string& addr,
@ -804,7 +902,10 @@ public:
const bool not_strict_expire_check = false,
const ConflictResolutionMode
exp_conflict_resolution_mode = CHECK_WITH_DHCID,
Optional<double> ttl_percent = Optional<double>()) {
Optional<double> ddns_ttl_percent = Optional<double>(),
Optional<uint32_t> ddns_ttl = Optional<uint32_t>(),
Optional<uint32_t> ddns_ttl_min = Optional<uint32_t>(),
Optional<uint32_t> ddns_ttl_max = Optional<uint32_t>()) {
NameChangeRequestPtr ncr;
ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
ASSERT_TRUE(ncr);
@ -825,7 +926,10 @@ public:
// current time as cltt but the it may not check the lease expiration
// time for equality but rather check that the lease expiration time
// is not greater than the current time + lease lifetime.
uint32_t ttl = calculateDdnsTtl(valid_lft, ttl_percent);
uint32_t ttl = calculateDdnsTtl(valid_lft, ddns_ttl_percent,
ddns_ttl, ddns_ttl_min, ddns_ttl_max);
if (not_strict_expire_check) {
EXPECT_GE(cltt + ttl, ncr->getLeaseExpiresOn());
} else {
@ -2840,7 +2944,7 @@ TEST_F(NameDhcpv4SrvTest, withOfferLifetime) {
}
// Verifies the DNS TTL when ttl percent is specified
// than zero.
// greater than zero.
TEST_F(NameDhcpv4SrvTest, withDdnsTtlPercent) {
// Load a configuration with D2 enabled and ddns-ttl-percent
ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[12], *srv_));
@ -2958,4 +3062,36 @@ TEST_F(NameDhcpv4SrvTest, checkExistsDHCIDConflictResolutionMode) {
lease->cltt_, 100, false, CHECK_EXISTS_WITH_DHCID);
}
// Verify the ddns-ttl-percent is used when specified.
TEST_F(NameDhcpv4SrvTest, ddnsTtlPercentTest) {
testDdnsTtlParameters(2100, 0.5);
}
// Verify the ddns-ttl is used when specified.
TEST_F(NameDhcpv4SrvTest, ddnsTtlTest) {
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
999, // ttl
Optional<uint32_t>(), // min
Optional<uint32_t>()); // max
}
// Verify the ddns-ttl-min is used when specified.
TEST_F(NameDhcpv4SrvTest, ddnsTtlMinTest) {
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
Optional<uint32_t>(), // ttl
800, // ttl-min
Optional<uint32_t>()); // ttl-max
}
// Verify the ddns-ttl-max is used when specified.
TEST_F(NameDhcpv4SrvTest, ddnsTtlMaxTest) {
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
Optional<uint32_t>(), // ttl
Optional<uint32_t>(), // ttl-min
500); // ttl-max
}
} // end of anonymous namespace

View File

@ -68,6 +68,7 @@ namespace {
///@{
/// @brief extracted configurations
const char* EXTRACTED_CONFIGS[] = {
/// put this after const char* EXTRACTED_CONFIGS[] = {
// CONFIGURATION 0
"{\n"
" \"interfaces-config\": {\n"
@ -2651,11 +2652,84 @@ const char* EXTRACTED_CONFIGS[] = {
" }\n"
" ],\n"
" \"valid-lifetime\": 400\n"
" }\n",
// CONFIGURATION 83
"{\n"
" \"ddns-ttl-percent\": 0.75,\n"
" \"shared-networks\": [\n"
" {\n"
" \"ddns-ttl-percent\": 0.5,\n"
" \"name\": \"net\",\n"
" \"subnet4\": [\n"
" {\n"
" \"ddns-ttl-percent\": 0.25,\n"
" \"id\": 1,\n"
" \"subnet\": \"10.0.2.0/24\"\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 84
"{\n"
" \"ddns-ttl\": 750,\n"
" \"shared-networks\": [\n"
" {\n"
" \"ddns-ttl\": 500,\n"
" \"name\": \"net\",\n"
" \"subnet4\": [\n"
" {\n"
" \"ddns-ttl\": 250,\n"
" \"id\": 1,\n"
" \"subnet\": \"10.0.2.0/24\"\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 85
"{\n"
" \"ddns-ttl-min\": 750,\n"
" \"shared-networks\": [\n"
" {\n"
" \"ddns-ttl-min\": 500,\n"
" \"name\": \"net\",\n"
" \"subnet4\": [\n"
" {\n"
" \"ddns-ttl-min\": 250,\n"
" \"id\": 1,\n"
" \"subnet\": \"10.0.2.0/24\"\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 86
"{\n"
" \"ddns-ttl-max\": 750,\n"
" \"shared-networks\": [\n"
" {\n"
" \"ddns-ttl-max\": 500,\n"
" \"name\": \"net\",\n"
" \"subnet4\": [\n"
" {\n"
" \"ddns-ttl-max\": 250,\n"
" \"id\": 1,\n"
" \"subnet\": \"10.0.2.0/24\"\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n"
};
/// @brief unparsed configurations
const char* UNPARSED_CONFIGS[] = {
///put this after const char* UNPARSED_CONFIGS[] = {
// CONFIGURATION 0
"{\n"
" \"allocator\": \"iterative\",\n"
@ -13546,6 +13620,506 @@ const char* UNPARSED_CONFIGS[] = {
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 400\n"
" }\n",
// CONFIGURATION 83
"{\n"
" \"allocator\": \"iterative\",\n"
" \"authoritative\": false,\n"
" \"boot-file-name\": \"\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
" \"ddns-generated-prefix\": \"myhost\",\n"
" \"ddns-override-client-update\": false,\n"
" \"ddns-override-no-update\": false,\n"
" \"ddns-qualifying-suffix\": \"\",\n"
" \"ddns-replace-client-name\": \"never\",\n"
" \"ddns-send-updates\": true,\n"
" \"ddns-ttl-percent\": 0.75,\n"
" \"ddns-update-on-renew\": false,\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp-queue-control\": {\n"
" \"capacity\": 64,\n"
" \"enable-queue\": false,\n"
" \"queue-type\": \"kea-ring4\"\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"early-global-reservations-lookup\": false,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"hostname-char-replacement\": \"\",\n"
" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ ],\n"
" \"re-detect\": false\n"
" },\n"
" \"ip-reservations-unique\": true,\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"match-client-id\": true,\n"
" \"multi-threading\": {\n"
" \"enable-multi-threading\": true,\n"
" \"packet-queue-size\": 64,\n"
" \"thread-pool-size\": 0\n"
" },\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"parked-packet-limit\": 256,\n"
" \"reservations-global\": false,\n"
" \"reservations-in-subnet\": true,\n"
" \"reservations-lookup-first\": false,\n"
" \"reservations-out-of-pool\": false,\n"
" \"sanity-checks\": {\n"
" \"extended-info-checks\": \"fix\",\n"
" \"lease-checks\": \"warn\"\n"
" },\n"
" \"server-hostname\": \"\",\n"
" \"server-tag\": \"\",\n"
" \"shared-networks\": [\n"
" {\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-percent\": 0.5,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"name\": \"net\",\n"
" \"option-data\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-percent\": 0.25,\n"
" \"id\": 1,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"reservations\": [ ],\n"
" \"store-extended-info\": false,\n"
" \"subnet\": \"10.0.2.0/24\",\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"stash-agent-options\": false,\n"
" \"statistic-default-sample-age\": 0,\n"
" \"statistic-default-sample-count\": 20,\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [ ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 84
"{\n"
" \"allocator\": \"iterative\",\n"
" \"authoritative\": false,\n"
" \"boot-file-name\": \"\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
" \"ddns-generated-prefix\": \"myhost\",\n"
" \"ddns-override-client-update\": false,\n"
" \"ddns-override-no-update\": false,\n"
" \"ddns-qualifying-suffix\": \"\",\n"
" \"ddns-replace-client-name\": \"never\",\n"
" \"ddns-send-updates\": true,\n"
" \"ddns-ttl\": 750,\n"
" \"ddns-update-on-renew\": false,\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp-queue-control\": {\n"
" \"capacity\": 64,\n"
" \"enable-queue\": false,\n"
" \"queue-type\": \"kea-ring4\"\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"early-global-reservations-lookup\": false,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"hostname-char-replacement\": \"\",\n"
" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ ],\n"
" \"re-detect\": false\n"
" },\n"
" \"ip-reservations-unique\": true,\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"match-client-id\": true,\n"
" \"multi-threading\": {\n"
" \"enable-multi-threading\": true,\n"
" \"packet-queue-size\": 64,\n"
" \"thread-pool-size\": 0\n"
" },\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"parked-packet-limit\": 256,\n"
" \"reservations-global\": false,\n"
" \"reservations-in-subnet\": true,\n"
" \"reservations-lookup-first\": false,\n"
" \"reservations-out-of-pool\": false,\n"
" \"sanity-checks\": {\n"
" \"extended-info-checks\": \"fix\",\n"
" \"lease-checks\": \"warn\"\n"
" },\n"
" \"server-hostname\": \"\",\n"
" \"server-tag\": \"\",\n"
" \"shared-networks\": [\n"
" {\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl\": 500,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"name\": \"net\",\n"
" \"option-data\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl\": 250,\n"
" \"id\": 1,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"reservations\": [ ],\n"
" \"store-extended-info\": false,\n"
" \"subnet\": \"10.0.2.0/24\",\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"stash-agent-options\": false,\n"
" \"statistic-default-sample-age\": 0,\n"
" \"statistic-default-sample-count\": 20,\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [ ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 85
"{\n"
" \"allocator\": \"iterative\",\n"
" \"authoritative\": false,\n"
" \"boot-file-name\": \"\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
" \"ddns-generated-prefix\": \"myhost\",\n"
" \"ddns-override-client-update\": false,\n"
" \"ddns-override-no-update\": false,\n"
" \"ddns-qualifying-suffix\": \"\",\n"
" \"ddns-replace-client-name\": \"never\",\n"
" \"ddns-send-updates\": true,\n"
" \"ddns-ttl-min\": 750,\n"
" \"ddns-update-on-renew\": false,\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp-queue-control\": {\n"
" \"capacity\": 64,\n"
" \"enable-queue\": false,\n"
" \"queue-type\": \"kea-ring4\"\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"early-global-reservations-lookup\": false,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"hostname-char-replacement\": \"\",\n"
" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ ],\n"
" \"re-detect\": false\n"
" },\n"
" \"ip-reservations-unique\": true,\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"match-client-id\": true,\n"
" \"multi-threading\": {\n"
" \"enable-multi-threading\": true,\n"
" \"packet-queue-size\": 64,\n"
" \"thread-pool-size\": 0\n"
" },\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"parked-packet-limit\": 256,\n"
" \"reservations-global\": false,\n"
" \"reservations-in-subnet\": true,\n"
" \"reservations-lookup-first\": false,\n"
" \"reservations-out-of-pool\": false,\n"
" \"sanity-checks\": {\n"
" \"extended-info-checks\": \"fix\",\n"
" \"lease-checks\": \"warn\"\n"
" },\n"
" \"server-hostname\": \"\",\n"
" \"server-tag\": \"\",\n"
" \"shared-networks\": [\n"
" {\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-min\": 500,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"name\": \"net\",\n"
" \"option-data\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-min\": 250,\n"
" \"id\": 1,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"reservations\": [ ],\n"
" \"store-extended-info\": false,\n"
" \"subnet\": \"10.0.2.0/24\",\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"stash-agent-options\": false,\n"
" \"statistic-default-sample-age\": 0,\n"
" \"statistic-default-sample-count\": 20,\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [ ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 86
"{\n"
" \"allocator\": \"iterative\",\n"
" \"authoritative\": false,\n"
" \"boot-file-name\": \"\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
" \"ddns-generated-prefix\": \"myhost\",\n"
" \"ddns-override-client-update\": false,\n"
" \"ddns-override-no-update\": false,\n"
" \"ddns-qualifying-suffix\": \"\",\n"
" \"ddns-replace-client-name\": \"never\",\n"
" \"ddns-send-updates\": true,\n"
" \"ddns-ttl-max\": 750,\n"
" \"ddns-update-on-renew\": false,\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp-queue-control\": {\n"
" \"capacity\": 64,\n"
" \"enable-queue\": false,\n"
" \"queue-type\": \"kea-ring4\"\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"early-global-reservations-lookup\": false,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"hostname-char-replacement\": \"\",\n"
" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ ],\n"
" \"re-detect\": false\n"
" },\n"
" \"ip-reservations-unique\": true,\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"match-client-id\": true,\n"
" \"multi-threading\": {\n"
" \"enable-multi-threading\": true,\n"
" \"packet-queue-size\": 64,\n"
" \"thread-pool-size\": 0\n"
" },\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"parked-packet-limit\": 256,\n"
" \"reservations-global\": false,\n"
" \"reservations-in-subnet\": true,\n"
" \"reservations-lookup-first\": false,\n"
" \"reservations-out-of-pool\": false,\n"
" \"sanity-checks\": {\n"
" \"extended-info-checks\": \"fix\",\n"
" \"lease-checks\": \"warn\"\n"
" },\n"
" \"server-hostname\": \"\",\n"
" \"server-tag\": \"\",\n"
" \"shared-networks\": [\n"
" {\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-max\": 500,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"name\": \"net\",\n"
" \"option-data\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"allocator\": \"iterative\",\n"
" \"calculate-tee-times\": false,\n"
" \"ddns-ttl-max\": 250,\n"
" \"id\": 1,\n"
" \"max-valid-lifetime\": 4000,\n"
" \"min-valid-lifetime\": 4000,\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"reservations\": [ ],\n"
" \"store-extended-info\": false,\n"
" \"subnet\": \"10.0.2.0/24\",\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"stash-agent-options\": false,\n"
" \"statistic-default-sample-age\": 0,\n"
" \"statistic-default-sample-count\": 20,\n"
" \"store-extended-info\": false,\n"
" \"subnet4\": [ ],\n"
" \"t1-percent\": 0.5,\n"
" \"t2-percent\": 0.875,\n"
" \"valid-lifetime\": 4000\n"
" }\n"
};

View File

@ -284,6 +284,9 @@ public:
cfg->sanityChecksLifetime("preferred-lifetime");
cfg->sanityChecksLifetime("valid-lifetime");
/// Sanity check global ddns-ttl parameters
cfg->sanityChecksDdnsTtlParameters();
/// Shared network sanity checks
const SharedNetwork6Collection* networks = cfg->getCfgSharedNetworks6()->getAll();
if (networks) {

View File

@ -86,6 +86,7 @@ CBControlDHCPv4::databaseConfigApply(const BackendSelector& backend_selector,
// Sanity check it.
external_cfg->sanityChecksLifetime("valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
// Now that we successfully fetched the new global parameters, let's
// remove existing ones and merge them into the current configuration.
@ -310,6 +311,7 @@ CBControlDHCPv4::databaseConfigApply(const BackendSelector& backend_selector,
// ip-reservations-unique setting here. It will be applied when the
// configuration is committed.
external_cfg->sanityChecksLifetime(*staging_cfg, "valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
CfgMgr::instance().mergeIntoStagingCfg(external_cfg->getSequence());
} else {
@ -331,6 +333,7 @@ CBControlDHCPv4::databaseConfigApply(const BackendSelector& backend_selector,
}
}
external_cfg->sanityChecksLifetime(*current_cfg, "valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
CfgMgr::instance().mergeIntoCurrentCfg(external_cfg->getSequence());
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure();
}

View File

@ -85,6 +85,7 @@ CBControlDHCPv6::databaseConfigApply(const db::BackendSelector& backend_selector
// Sanity check it.
external_cfg->sanityChecksLifetime("preferred-lifetime");
external_cfg->sanityChecksLifetime("valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
// Now that we successfully fetched the new global parameters, let's
// remove existing ones and merge them into the current configuration.
@ -325,6 +326,7 @@ CBControlDHCPv6::databaseConfigApply(const db::BackendSelector& backend_selector
auto const& cfg = CfgMgr::instance().getStagingCfg();
external_cfg->sanityChecksLifetime(*cfg, "preferred-lifetime");
external_cfg->sanityChecksLifetime(*cfg, "valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
CfgMgr::instance().mergeIntoStagingCfg(external_cfg->getSequence());
} else {
@ -348,6 +350,7 @@ CBControlDHCPv6::databaseConfigApply(const db::BackendSelector& backend_selector
auto const& cfg = CfgMgr::instance().getCurrentCfg();
external_cfg->sanityChecksLifetime(*cfg, "preferred-lifetime");
external_cfg->sanityChecksLifetime(*cfg, "valid-lifetime");
external_cfg->sanityChecksDdnsTtlParameters();
CfgMgr::instance().mergeIntoCurrentCfg(external_cfg->getSequence());
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->initAllocatorsAfterConfigure();
}

View File

@ -57,6 +57,9 @@ CfgGlobals::nameToIndex = {
{ "multi-threading", MULTI_THREADING },
{ "sanity-checks", SANITY_CHECKS },
{ "dhcp-queue-control", DHCP_QUEUE_CONTROL },
{ "ddns-ttl", DDNS_TTL },
{ "ddns-ttl-min", DDNS_TTL_MIN },
{ "ddns-ttl-max", DDNS_TTL_MAX },
// DHCPv4 specific parameters.
{ "echo-client-id", ECHO_CLIENT_ID },

View File

@ -80,6 +80,9 @@ public:
MULTI_THREADING,
SANITY_CHECKS,
DHCP_QUEUE_CONTROL,
DDNS_TTL,
DDNS_TTL_MIN,
DDNS_TTL_MAX,
// DHCPv4 specific parameters.
ECHO_CLIENT_ID,

View File

@ -49,7 +49,8 @@ extern const isc::log::MessageID DHCPSRV_CFGMGR_USE_UNICAST = "DHCPSRV_CFGMGR_US
extern const isc::log::MessageID DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES = "DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES";
extern const isc::log::MessageID DHCPSRV_CLIENT_CLASS_DEPRECATED = "DHCPSRV_CLIENT_CLASS_DEPRECATED";
extern const isc::log::MessageID DHCPSRV_CLOSE_DB = "DHCPSRV_CLOSE_DB";
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL = "DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL";
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_TOO_LARGE = "DHCPSRV_DDNS_TTL_TOO_LARGE";
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_TOO_SMALL = "DHCPSRV_DDNS_TTL_TOO_SMALL";
extern const isc::log::MessageID DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET = "DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET";
extern const isc::log::MessageID DHCPSRV_DHCP_DDNS_ERROR_EXCEPTION = "DHCPSRV_DHCP_DDNS_ERROR_EXCEPTION";
extern const isc::log::MessageID DHCPSRV_DHCP_DDNS_HANDLER_NULL = "DHCPSRV_DHCP_DDNS_HANDLER_NULL";
@ -220,7 +221,8 @@ const char* values[] = {
"DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES", "class: %1 has 'only-in-additional-list' true while specifying one or more lease life time values. Life time values will be ignored.",
"DHCPSRV_CLIENT_CLASS_DEPRECATED", "The parameter 'client-class' is deprecated. Use 'client-classes' list parameter instead",
"DHCPSRV_CLOSE_DB", "closing currently open %1 database",
"DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL", "ddns-ttl-percent %1 of lease lifetime %2 is too small, ignoring it",
"DHCPSRV_DDNS_TTL_TOO_LARGE", "%1 of lease life time %2 is %3, using maximum of %4 instead.",
"DHCPSRV_DDNS_TTL_TOO_SMALL", "%1 of lease life time %2 is %3, using minimum of %4 instead.",
"DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET", "received bad DHCPv4o6 packet: %1",
"DHCPSRV_DHCP_DDNS_ERROR_EXCEPTION", "error handler for DHCP_DDNS IO generated an expected exception: %1",
"DHCPSRV_DHCP_DDNS_HANDLER_NULL", "error handler for DHCP_DDNS IO is not set.",

View File

@ -50,7 +50,8 @@ extern const isc::log::MessageID DHCPSRV_CFGMGR_USE_UNICAST;
extern const isc::log::MessageID DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES;
extern const isc::log::MessageID DHCPSRV_CLIENT_CLASS_DEPRECATED;
extern const isc::log::MessageID DHCPSRV_CLOSE_DB;
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL;
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_TOO_LARGE;
extern const isc::log::MessageID DHCPSRV_DDNS_TTL_TOO_SMALL;
extern const isc::log::MessageID DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET;
extern const isc::log::MessageID DHCPSRV_DHCP_DDNS_ERROR_EXCEPTION;
extern const isc::log::MessageID DHCPSRV_DHCP_DDNS_HANDLER_NULL;

View File

@ -267,14 +267,6 @@ the database access parameters are changed: in the latter case, the
server closes the currently open database, and opens a database using
the new parameters.
% DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL ddns-ttl-percent %1 of lease lifetime %2 is too small, ignoring it
Logged at debug log level 55.
A debug message issued when the DDNS TTL value calculated using the
ddns-ttl-percent is zero. Kea will ignore the value and calculate
the DDNS TTL as though ddsn-ttl-percent were not specified. The
value of ddns-ttl-percent and the lease lifetime are shown in
the message details.
% DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET received bad DHCPv4o6 packet: %1
A bad DHCPv4o6 packet was received.
@ -971,3 +963,20 @@ included in the message.
% DHCPSRV_UNKNOWN_DB unknown database type: %1
The database access string specified a database type (given in the
message) that is unknown to the software. This is a configuration error.
% DHCPSRV_DDNS_TTL_TOO_SMALL %1 of lease life time %2 is %3, using minimum of %4 instead.
Logged at debug log level 55.
A debug message issued when the DDNS TTL value calculated using the
ddns-ttl-percent if specfieed or (0.33 if not) is too small. Kea will
ignore the value and is the minimum (ddns-ttl-min is specifed or 600
seconds if not). The message details include the percentage, the lease
life time, the calculated TTL, and the value actually used.
% DHCPSRV_DDNS_TTL_TOO_LARGE %1 of lease life time %2 is %3, using maximum of %4 instead.
Logged at debug log level 55.
A debug message issued when the DDNS TTL value calculated using the
ddns-ttl-percent if specfieed or (0.33 if not) is larger than the
the specified value of ddns-ttl-max. Kea will ignore the value and
use is the specified maxinimum instead. The message details include
the percentage, the lease life time, the calculated TTL, and the value
actually used.

View File

@ -13,6 +13,7 @@
#include <dhcpsrv/ncr_generator.h>
#include <stdint.h>
#include <vector>
#include <util/str.h>
using namespace isc;
using namespace isc::dhcp;
@ -52,6 +53,9 @@ void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
ConflictResolutionMode conflict_resolution_mode = CHECK_WITH_DHCID;
util::Optional<double> ddns_ttl_percent;
util::Optional<uint32_t> ddns_ttl;
util::Optional<uint32_t> ddns_ttl_min;
util::Optional<uint32_t> ddns_ttl_max;
if (subnet) {
auto mode = subnet->getDdnsConflictResolutionMode();
if (!mode.empty()) {
@ -59,6 +63,9 @@ void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
}
ddns_ttl_percent = subnet->getDdnsTtlPercent();
ddns_ttl = subnet->getDdnsTtl();
ddns_ttl_min = subnet->getDdnsTtlMin();
ddns_ttl_max = subnet->getDdnsTtlMax();
}
try {
@ -68,7 +75,9 @@ void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
D2Dhcid dhcid = D2Dhcid(identifier, hostname_wire);
// Calculate the TTL based on lease life time.
uint32_t ttl = calculateDdnsTtl(lease->valid_lft_, ddns_ttl_percent);
uint32_t ttl = calculateDdnsTtl(lease->valid_lft_,
ddns_ttl_percent, ddns_ttl,
ddns_ttl_min, ddns_ttl_max);
// Create name change request.
NameChangeRequestPtr ncr
@ -131,27 +140,50 @@ void queueNCR(const NameChangeType& chg_type, const Lease6Ptr& lease) {
}
}
uint32_t calculateDdnsTtl(uint32_t lease_lft, const util::Optional<double>& ddns_ttl_percent) {
// If we have a configured percentage use it to calculate TTL.
if (!ddns_ttl_percent.unspecified() && (ddns_ttl_percent.get() > 0.0)) {
uint32_t new_lft = static_cast<uint32_t>(round(ddns_ttl_percent.get() * lease_lft));
if (new_lft > 0) {
return (new_lft);
} else {
uint32_t calculateDdnsTtl(uint32_t lease_lft,
const util::Optional<double>& ddns_ttl_percent,
const util::Optional<uint32_t>& ddns_ttl,
const util::Optional<uint32_t>& ddns_ttl_min,
const util::Optional<uint32_t>& ddns_ttl_max) {
// If we have an explicit value use it.
if (!ddns_ttl.unspecified() && ddns_ttl.get() > 0) {
return (ddns_ttl.get());
}
// Use specified percentage (if one) or 1/3 as called for in RFC 4702.
double ttl_percent = (ddns_ttl_percent.get() > 0.0 ?
ddns_ttl_percent.get() : 0.33333);
// Calculate the ttl.
uint32_t ttl = static_cast<uint32_t>(round(ttl_percent * lease_lft));
// Adjust for minimum and maximum.
// If we have a custom mininum enforce it, otherwise per RFC 4702 it
// should not less than 600.
uint32_t ttl_min = (ddns_ttl_min.get() > 0) ? ddns_ttl_min.get() : 600;
if (ttl < ttl_min) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA,
DHCPSRV_DDNS_TTL_TOO_SMALL)
.arg(util::str::dumpDouble(ttl_percent))
.arg(lease_lft)
.arg(ttl)
.arg(ttl_min);
return (ttl_min);
}
// If we have a maximum enforce it.
uint32_t ttl_max = ddns_ttl_max.get();
if (ttl_max && ttl > ttl_max) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA,
DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL)
.arg(ddns_ttl_percent.get())
.arg(lease_lft);
}
DHCPSRV_DDNS_TTL_TOO_LARGE)
.arg(util::str::dumpDouble(ttl_percent))
.arg(lease_lft)
.arg(ttl)
.arg(ttl_max);
return (ttl_max);
}
// Per RFC 4702 DDNS RR TTL should be given by:
// ((lease life time / 3) < 10 minutes) ? 10 minutes : (lease life time / 3)
if (lease_lft < 1800) {
return (600);
}
return (lease_lft / 3);
return (ttl);
}
}

View File

@ -44,22 +44,38 @@ void queueNCR(const dhcp_ddns::NameChangeType& chg_type, const Lease6Ptr& lease)
/// @brief Calculates TTL for a DNS resource record based on lease life time.
///
/// If the parameter, ddns_ttl_percent is greater than zero, it is used to calculate
/// the TTL directly:
/// The logic for calculating TTL is as follow:
///
/// TTL = (lease life time * ddns-ttl-percent)
/// If ddns-ttl is specified use it unconditionally.
///
/// Otherwise it is calculated as per RFC 4702 Section 5:
/// If ddns-ttl-percnet is specified use it otherwise use 1/3 as
/// called for by RFC 4702.
///
/// TTL = ((lease life time / 3) < 10 minutes) ? 10 minutes : (lease life time / 3)
/// Calculate the candidate TTL based on the deteremined percentage.
///
/// If ddsn-ttl-min is specified used it otherwise use a minimum of
/// 600 per RFC 4702. If the TTL is less than the mininum return
/// the minimum.
///
/// If ddsn-ttl-max is specified limit the ttl to that value otherwse
/// return the ttl.
///
/// @param lease_life_time valid life time of the lease
/// @param ddns_ttl_percent optional percentage to use in calculation
/// @param ddns_ttl optional percentage to use in calculation
/// @param ddns_ttl_min optional minium TTL to allow
/// @param ddns_ttl_max optional maximum TTL to allow
///
/// @return the calculated TTL.
uint32_t calculateDdnsTtl(uint32_t lease_life_time,
const util::Optional<double>& ddns_ttl_percent
= util::Optional<double>());
= util::Optional<double>(),
const util::Optional<uint32_t>& ddns_ttl
= util::Optional<uint32_t>(),
const util::Optional<uint32_t>& ddns_ttl_min
= util::Optional<uint32_t>(),
const util::Optional<uint32_t>& ddns_ttl_max
= util::Optional<uint32_t>());
} // end of isc::dhcp namespace
} // end of isc namespace

View File

@ -231,6 +231,18 @@ Network::toElement() const {
map->set("ddns-ttl-percent", Element::create(ddns_ttl_percent_));
}
if (!ddns_ttl_.unspecified()) {
map->set("ddns-ttl", Element::create(ddns_ttl_));
}
if (!ddns_ttl_min_.unspecified()) {
map->set("ddns-ttl-min", Element::create(ddns_ttl_min_));
}
if (!ddns_ttl_max_.unspecified()) {
map->set("ddns-ttl-max", Element::create(ddns_ttl_max_));
}
if (!hostname_char_set_.unspecified()) {
map->set("hostname-char-set", Element::create(hostname_char_set_));
}

View File

@ -219,8 +219,9 @@ public:
ddns_replace_client_name_mode_(), ddns_generated_prefix_(), ddns_qualifying_suffix_(),
hostname_char_set_(), hostname_char_replacement_(), store_extended_info_(),
cache_threshold_(), cache_max_age_(), ddns_update_on_renew_(),
ddns_conflict_resolution_mode_(), ddns_ttl_percent_(), allocator_type_(),
default_allocator_type_() {
ddns_conflict_resolution_mode_(), ddns_ttl_percent_(),
ddns_ttl_(), ddns_ttl_min_(), ddns_ttl_max_(),
allocator_type_(), default_allocator_type_() {
}
/// @brief Virtual destructor.
@ -682,6 +683,59 @@ public:
ddns_ttl_percent_ = ddns_ttl_percent;
}
/// @brief Returns ddns-ttl
///
/// @param inheritance inheritance mode to be used.
util::Optional<uint32_t>
getDdnsTtl(const Inheritance& inheritance = Inheritance::ALL) const {
return (getProperty<Network>(&Network::getDdnsTtl,
ddns_ttl_, inheritance,
CfgGlobals::DDNS_TTL));
}
/// @brief Sets new ddns-ttl
///
/// @param ddns_ttl New value to use.
void setDdnsTtl(const util::Optional<uint32_t>& ddns_ttl) {
ddns_ttl_ = ddns_ttl;
}
/// @brief Returns ddns-ttl-min
///
/// @param inheritance inheritance mode to be used.
util::Optional<uint32_t>
getDdnsTtlMin(const Inheritance& inheritance = Inheritance::ALL) const {
return (getProperty<Network>(&Network::getDdnsTtlMin,
ddns_ttl_min_, inheritance,
CfgGlobals::DDNS_TTL_MIN));
}
/// @brief Sets new ddns-ttl-min
///
/// @param ddns_ttl_min New value to use.
void setDdnsTtlMin(const util::Optional<uint32_t>& ddns_ttl_min) {
ddns_ttl_min_ = ddns_ttl_min;
}
/// @brief Returns ddns-ttl-max
///
/// @param inheritance inheritance mode to be used.
util::Optional<uint32_t>
getDdnsTtlMax(const Inheritance& inheritance = Inheritance::ALL) const {
return (getProperty<Network>(&Network::getDdnsTtlMax,
ddns_ttl_max_, inheritance,
CfgGlobals::DDNS_TTL_MAX));
}
/// @brief Sets new ddns-ttl-max
///
/// @param ddns_ttl_max New value to use.
void setDdnsTtlMax(const util::Optional<uint32_t>& ddns_ttl_max) {
ddns_ttl_max_ = ddns_ttl_max;
}
/// @brief Return the char set regexp used to sanitize client hostnames.
util::Optional<std::string>
getHostnameCharSet(const Inheritance& inheritance = Inheritance::ALL) const {
@ -1237,6 +1291,15 @@ protected:
/// @brief Percentage of the lease lifetime to use for DNS TTL.
util::Optional<double> ddns_ttl_percent_;
/// @brief Explicit value to use for DNS TTL.
util::Optional<uint32_t> ddns_ttl_;
/// @brief Minimum value to use for DNS TTL.
util::Optional<uint32_t> ddns_ttl_min_;
/// @brief Maximum value to use for DNS TTL.
util::Optional<uint32_t> ddns_ttl_max_;
/// @brief Allocator used for IP address allocations.
util::Optional<std::string> allocator_type_;

View File

@ -197,10 +197,46 @@ BaseNetworkParser::parseDdnsParams(const data::ConstElementPtr& network_data,
network->setDdnsUpdateOnRenew(getBoolean(network_data, "ddns-update-on-renew"));
}
bool has_ddns_ttl = false;
uint32_t ddns_ttl = 0;
if (network_data->contains("ddns-ttl")) {
ddns_ttl = getInteger(network_data, "ddns-ttl");
network->setDdnsTtl(ddns_ttl);
has_ddns_ttl = true;
}
if (network_data->contains("ddns-ttl-percent")) {
if (has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-percent and ddns-ttl");
}
network->setDdnsTtlPercent(getDouble(network_data, "ddns-ttl-percent"));
}
uint32_t ddns_ttl_min = 0;
if (network_data->contains("ddns-ttl-min")) {
if (has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-min and ddns-ttl");
}
ddns_ttl_min = getInteger(network_data, "ddns-ttl-min");
network->setDdnsTtlMin(ddns_ttl_min);
}
if (network_data->contains("ddns-ttl-max")) {
if (has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-max and ddns-ttl");
}
uint32_t ddns_ttl_max = getInteger(network_data, "ddns-ttl-max");
if (ddns_ttl_max < ddns_ttl_min) {
isc_throw(BadValue, "ddns-ttl-max: " << ddns_ttl_max
<< " must be greater than ddns-ttl-min: " << ddns_ttl_min);
}
network->setDdnsTtlMax(ddns_ttl_max);
}
// For backward compatibility, ddns-conflict-resolution-mode is optional.
if (network_data->contains("ddns-conflict-resolution-mode")) {
network->setDdnsConflictResolutionMode(getString(network_data,

View File

@ -101,6 +101,9 @@ const SimpleKeywords SimpleParser4::GLOBAL4_PARAMETERS = {
{ "ddns-ttl-percent", Element::real },
{ "ddns-conflict-resolution-mode", Element::string },
{ "stash-agent-options", Element::boolean },
{ "ddns-ttl", Element::integer },
{ "ddns-ttl-min", Element::integer },
{ "ddns-ttl-max", Element::integer },
};
/// @brief This table defines default global values for DHCPv4
@ -261,6 +264,9 @@ const SimpleKeywords SimpleParser4::SUBNET4_PARAMETERS = {
{ "offer-lifetime", Element::integer },
{ "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 },
};
/// @brief This table defines default values for each IPv4 subnet.
@ -388,6 +394,9 @@ const SimpleKeywords SimpleParser4::SHARED_NETWORK4_PARAMETERS = {
{ "offer-lifetime", Element::integer },
{ "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 },
};
/// @brief This table defines default values for interfaces for DHCPv4.

View File

@ -100,6 +100,9 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = {
{ "pd-allocator", Element::string },
{ "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 },
};
/// @brief This table defines default global values for DHCPv6
@ -253,6 +256,9 @@ const SimpleKeywords SimpleParser6::SUBNET6_PARAMETERS = {
{ "pd-allocator", Element::string },
{ "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 },
};
/// @brief This table defines default values for each IPv6 subnet.
@ -401,6 +407,9 @@ const SimpleKeywords SimpleParser6::SHARED_NETWORK6_PARAMETERS = {
{ "pd-allocator", Element::string },
{ "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 },
};
/// @brief This table defines default values for interfaces for DHCPv6.

View File

@ -1057,6 +1057,42 @@ DdnsParams::getHostnameSanitizer() const {
return (sanitizer);
}
void
SrvConfig::sanityChecksDdnsTtlParameters() const {
// Need to check that global DDNS TTL values make sense
// Get ddns-ttl first. If ddns-ttl is specified none of the others should be.
ConstElementPtr has_ddns_ttl = getConfiguredGlobal("ddns-ttl");
if (getConfiguredGlobal("ddns-ttl-percent")) {
if (has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-percent and ddns-ttl");
}
}
ConstElementPtr has_ddns_ttl_min = getConfiguredGlobal("ddns-ttl-min");
if (has_ddns_ttl_min && has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-min and ddns-ttl");
}
ConstElementPtr has_ddns_ttl_max = getConfiguredGlobal("ddns-ttl-max");
if (has_ddns_ttl_max) {
if (has_ddns_ttl) {
isc_throw(BadValue, "cannot specify both ddns-ttl-max and ddns-ttl");
}
if (has_ddns_ttl_min) {
// Have min and max, make sure the range is sane.
uint32_t ddns_ttl_min = has_ddns_ttl_min->intValue();
uint32_t ddns_ttl_max = has_ddns_ttl_max->intValue();
if (ddns_ttl_max < ddns_ttl_min) {
isc_throw(BadValue, "ddns-ttl-max: " << ddns_ttl_max
<< " must be greater than ddns-ttl-min: " << ddns_ttl_min);
}
}
}
}
bool
DdnsParams::getUpdateOnRenew() const {
if (!subnet_) {
@ -1075,6 +1111,33 @@ DdnsParams::getTtlPercent() const {
return (subnet_->getDdnsTtlPercent());
}
util::Optional<uint32_t>
DdnsParams::getTtl() const {
if (!subnet_) {
return (util::Optional<uint32_t>());
}
return (subnet_->getDdnsTtl());
}
util::Optional<uint32_t>
DdnsParams::getTtlMin() const {
if (!subnet_) {
return (util::Optional<uint32_t>());
}
return (subnet_->getDdnsTtlMin());
}
util::Optional<uint32_t>
DdnsParams::getTtlMax() const {
if (!subnet_) {
return (util::Optional<uint32_t>());
}
return (subnet_->getDdnsTtlMax());
}
std::string
DdnsParams::getConflictResolutionMode() const {
if (!subnet_) {

View File

@ -150,6 +150,30 @@ public:
/// @return TTL percent as an Optional.
util::Optional<double> getTtlPercent() const;
/// @brief Returns explicit TTL to use
///
/// This value, if greater than zero, is used as the lifetime
/// passed to D2 in the NCR.
///
/// @return TTL as an Optional.
util::Optional<uint32_t> getTtl() const;
/// @brief Returns the minimum TTL to use
///
/// This value, if greater than zero, is used as the lower boundary
/// for calculated TTLs.
///
/// @return TTL minimum as an Optional.
util::Optional<uint32_t> getTtlMin() const;
/// @brief Returns the maximum TTL to use
///
/// This value, if greater than zero, is used as the upper boundary
/// for calculated TTLs.
///
/// @return TTL maximum as an Optional.
util::Optional<uint32_t> getTtlMax() const;
/// @brief Returns the DDNS config resolution mode for kea-dhcp-ddns
///
/// This value is communicated to D2 via the NCR.
@ -951,6 +975,16 @@ public:
void sanityChecksLifetime(const SrvConfig& target_config,
const std::string& name) const;
/// @brief Conducts sanity checks on global DDNS ttl parameters:
/// ddsn-ttl, ddsn-ttl-percent, ddns-ttl-min, ddns-ttl-max
///
/// If ddns-ttl is specified none of the others can be
/// If ddns-ttl-min and ddsn-ttl-max are specified max cannot
/// be less than min.
///
/// @throw Throws BadValue if any of the rules are violated.
void sanityChecksDdnsTtlParameters() const;
/// @brief Configures the server to allow or disallow specifying multiple
/// hosts with the same IP address/subnet.
///

View File

@ -72,6 +72,161 @@ public:
void resetIfaceCfg() {
CfgMgr::instance().clear();
}
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
template<typename ParserType, typename NetworkPtrType>
void validDdnsTtlParmatersSubnet(int family) {
struct Scenario {
size_t line_no_;
std::string json_;
double ddns_ttl_percent_;
uint32_t ddns_ttl_;
uint32_t ddns_ttl_min_;
uint32_t ddns_ttl_max_;
};
std::list<Scenario> scenarios = {
{
__LINE__,
R"^({
"id": 1,
"ddns-ttl": 100
})^",
0.0, 100, 0, 0
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-percent": 5.0
})^",
5.0, 0, 0, 0
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-min": 25
})^",
0.0, 0, 25, 0
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-max": 150
})^",
0.0, 0, 0, 150
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-min": 25,
"ddns-ttl-max": 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
})^",
5.0, 0, 25, 150
}};
ElementPtr subnet_elem = Element::create(family == AF_INET ?
"192.0.2.0/24" : "2001:db8::/64");
for (const auto& scenario : scenarios) {
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_));
config_element->set("subnet", subnet_elem);
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_);
}
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
template<typename ParserType>
void invalidDdnsTtlParmatersSubnet(int family) {
struct Scenario {
size_t line_no_;
std::string json_;
std::string exp_message_;
};
std::list<Scenario> scenarios = {
{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-percent": 5.0,
"ddns-ttl": 100
})^",
"subnet configuration failed: cannot specify both ddns-ttl-percent and ddns-ttl"
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl": 100,
"ddns-ttl-min": 25
})^",
"subnet configuration failed: cannot specify both ddns-ttl-min and ddns-ttl"
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl": 100,
"ddns-ttl-max": 150
})^",
"subnet configuration failed: cannot specify both ddns-ttl-max and ddns-ttl"
},{
__LINE__,
R"^({
"id": 1,
"ddns-ttl-min": 150,
"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");
for (const auto& scenario : scenarios) {
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_));
config_element->set("subnet", subnet_elem);
ParserType parser(family);
ASSERT_THROW_MSG(parser.parse(config_element), DhcpConfigError, scenario.exp_message_);
}
}
};
/// Verifies the code that parses mac sources and adds them to CfgMgr
@ -4115,4 +4270,28 @@ TEST_F(DhcpParserTest, deprecatedClientClassPool6) {
" 'client-classes'. Use only the latter.");
}
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet4.
TEST_F(DhcpParserTest, validDdnsTtlParmatersSubnet4) {
validDdnsTtlParmatersSubnet<Subnet4ConfigParser, Subnet4Ptr>(AF_INET);
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet4.
TEST_F(DhcpParserTest, invalidDdnsTtlParmatersSubnet4) {
invalidDdnsTtlParmatersSubnet<Subnet4ConfigParser>(AF_INET);
}
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet6.
TEST_F(DhcpParserTest, validDdnsTtlParmatersSubnet6) {
validDdnsTtlParmatersSubnet<Subnet6ConfigParser, Subnet6Ptr>(AF_INET6);
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet6.
TEST_F(DhcpParserTest, invalidDdnsTtlParmatersSubnet6) {
invalidDdnsTtlParmatersSubnet<Subnet6ConfigParser>(AF_INET6);
}
} // Anonymous namespace

View File

@ -234,14 +234,18 @@ public:
void testNCR(const NameChangeType chg_type, const bool fwd, const bool rev,
const std::string& fqdn, const std::string exp_dhcid,
const ConflictResolutionMode exp_cr_mode = CHECK_WITH_DHCID,
const Optional<double> ttl_percent = Optional<double>()) {
const Optional<double> ddns_ttl_percent = Optional<double>(),
const Optional<uint32_t> ddns_ttl = Optional<uint32_t>(),
const Optional<uint32_t> ddns_ttl_min = Optional<uint32_t>(),
const Optional<uint32_t> ddns_ttl_max = Optional<uint32_t>()) {
// Queue NCR.
ASSERT_NO_FATAL_FAILURE(sendNCR(chg_type, fwd, rev, fqdn));
// Expecting one NCR be generated.
ASSERT_EQ(1, d2_mgr_.getQueueSize());
// Calculate expected ttl.
uint32_t ttl = calculateDdnsTtl(lease_->valid_lft_, ttl_percent);
uint32_t ttl = calculateDdnsTtl(lease_->valid_lft_, ddns_ttl_percent,
ddns_ttl, ddns_ttl_min, ddns_ttl_max);
// Check the details of the NCR.
verifyNameChangeRequest(chg_type, rev, fwd, lease_->addr_.toText(), exp_dhcid,
@ -719,55 +723,83 @@ TEST_F(NCRGenerator4Test, conflictResolutionMode) {
}
}
// Verify that calculateDdnsTtl() produces the expected values.
TEST_F(NCRGenerator4Test, calculateDdnsTtl) {
// Verify that calculateDdnsTtl(), called by queueNcr()
// produces the expected values. Note there is no v6
// version of this test as v4 and v6 use the same code.
TEST_F(NCRGenerator4Test, calculateDdnsTtlThroughQueueNcr) {
struct Scenario {
size_t line_no_;
uint32_t lease_lft_;
Optional<double> ddns_ttl_percent_;
Optional<uint32_t> ddns_ttl_;
Optional<uint32_t> ddns_ttl_min_;
Optional<uint32_t> ddns_ttl_max_;
uint32_t exp_ttl_;
};
// A life time less than or equal to 1800 should yield a TTL of 600 seconds.
EXPECT_EQ(600, calculateDdnsTtl(100));
Optional<double> no_percent;
Optional<uint32_t> no_ttl;
Optional<uint32_t> no_min;
Optional<uint32_t> no_max;
// A life time > 1800 should be 1/3 of the value.
EXPECT_EQ(601, calculateDdnsTtl(1803));
std::list<Scenario> scenarios = {
// No modifiers, should be RFC % (i.e lft / 3)
{ __LINE__, 2100, no_percent, no_ttl, no_min, no_max, 700 },
// Now check permutations of values for ddns-ttl-percent.
util::Optional<double> ddns_ttl_percent;
// No modifiers, RFC % < RFC minium 600
{ __LINE__, 1500, no_percent, no_ttl, no_min, no_max, 600 },
// Unspecified percent should result in normal per RFC calculation.
EXPECT_EQ(601, calculateDdnsTtl(1803, ddns_ttl_percent));
// RFC % < specified minimum
{ __LINE__, 2100, no_percent, no_ttl, 800, no_max, 800 },
// A percentage of zero should be ignored.
ddns_ttl_percent = 0.0;
EXPECT_EQ(601, calculateDdnsTtl(1803, ddns_ttl_percent));
// RFC % > specified maximum
{ __LINE__, 2100, no_percent, no_ttl, no_min, 500, 500 },
// A percentage that results in near zero should be ignored.
ddns_ttl_percent = 0.000005;
EXPECT_EQ(601, calculateDdnsTtl(1803, ddns_ttl_percent));
// Explicit ttl
{ __LINE__, 2100, no_percent, 900, no_min, no_max, 900 },
// A large enough percentage should be used.
ddns_ttl_percent = 0.01;
EXPECT_EQ(18, calculateDdnsTtl(1803, ddns_ttl_percent));
// Explicit ttl wins over specified percent
{ __LINE__, 2100, 0.25, 900, no_min, no_max, 900 },
// A large enough percentage should be used.
ddns_ttl_percent = 1.50;
EXPECT_EQ(2705, calculateDdnsTtl(1803, ddns_ttl_percent));
}
// Explicit ttl wins over specified minumum
{ __LINE__, 2100, no_percent, 900, 1000, no_max, 900 },
// Verify that ddns-ttl-percent is used correctly by v4 queueNCR()
TEST_F(NCRGenerator4Test, withTtlPercent) {
{
SCOPED_TRACE("Ttl percent of 0");
Optional<double> ttl_percent(0);
subnet_->setDdnsTtlPercent(ttl_percent);
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
// Explicit ttl wins over specified maxiumum
{ __LINE__, 2100, no_percent, 900, no_min, 800, 900 },
// Specified percent > RFC minumum
{ __LINE__, 2100, 0.5, no_ttl, no_min, no_max, 1050 },
// Specified percent < RFC minumum
{ __LINE__, 2100, 0.25, no_ttl, no_min, no_max, 600 },
// Specified percent < specified minimum < RFC minimum
{ __LINE__, 2100, 0.10, no_ttl, 300 , no_max, 300 },
// Specified percent > specified maximum
{ __LINE__, 2100, 0.50, no_ttl, no_min, 800, 800 },
// Specified percent > lft
{ __LINE__, 2100, 1.50, no_ttl, no_min, no_max, 3150 },
};
for (const auto& scenario : scenarios) {
lease_->valid_lft_ = scenario.lease_lft_;
subnet_->setDdnsTtlPercent(scenario.ddns_ttl_percent_);
subnet_->setDdnsTtl(scenario.ddns_ttl_);
subnet_->setDdnsTtlMin(scenario.ddns_ttl_min_);
subnet_->setDdnsTtlMax(scenario.ddns_ttl_max_);
std::stringstream oss;
oss << "scenario at: " << scenario.line_no_;
SCOPED_TRACE(oss.str());
testNCR(CHG_ADD, true, true, "MYHOST.example.com.",
"000001E356D43E5F0A496D65BCA24D982D646140813E3"
"B03AB370BFF46BFA309AE7BFD", CHECK_WITH_DHCID, ttl_percent);
}
{
SCOPED_TRACE("Ttl percent of 1.5");
Optional<double> ttl_percent(1.5);
subnet_->setDdnsTtlPercent(ttl_percent);
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
"000001E356D43E5F0A496D65BCA24D982D646140813E3"
"B03AB370BFF46BFA309AE7BFD", CHECK_WITH_DHCID, ttl_percent);
"B03AB370BFF46BFA309AE7BFD", CHECK_WITH_DHCID,
scenario.ddns_ttl_percent_,
scenario.ddns_ttl_,
scenario.ddns_ttl_min_,
scenario.ddns_ttl_max_);
}
}

View File

@ -183,6 +183,9 @@ TEST_F(NetworkTest, inheritanceSupport4) {
globals_->set("allocator", Element::create("random"));
globals_->set("offer-lifetime", Element::create(45));
globals_->set("ddns-ttl-percent", Element::create(0.75));
globals_->set("ddns-ttl", Element::create(400));
globals_->set("ddns-ttl-min", Element::create(200));
globals_->set("ddns-ttl-max", Element::create(600));
// For each parameter for which inheritance is supported run
// the test that checks if the values are inherited properly.
@ -372,6 +375,24 @@ TEST_F(NetworkTest, inheritanceSupport4) {
&Network::setDdnsTtlPercent,
.33, .75);
}
{
SCOPED_TRACE("ddns-ttl");
testNetworkInheritance<TestNetwork4>(&Network::getDdnsTtl,
&Network::setDdnsTtl,
300, 400);
}
{
SCOPED_TRACE("ddns-ttl-min");
testNetworkInheritance<TestNetwork4>(&Network::getDdnsTtlMin,
&Network::setDdnsTtlMin,
100, 200);
}
{
SCOPED_TRACE("ddns-ttl-max");
testNetworkInheritance<TestNetwork4>(&Network::getDdnsTtlMax,
&Network::setDdnsTtlMax,
500, 600);
}
}
// This test verifies that the inheritance is supported for DHCPv6
@ -394,6 +415,9 @@ TEST_F(NetworkTest, inheritanceSupport6) {
globals_->set("pd-allocator", Element::create("random"));
globals_->set("ddns-ttl-percent", Element::create(0.55));
globals_->set("ddns-conflict-resolution-mode", Element::create("check-with-dhcid"));
globals_->set("ddns-ttl", Element::create(400));
globals_->set("ddns-ttl-min", Element::create(200));
globals_->set("ddns-ttl-max", Element::create(600));
// For each parameter for which inheritance is supported run
// the test that checks if the values are inherited properly.
@ -502,6 +526,24 @@ TEST_F(NetworkTest, inheritanceSupport6) {
&Network::setDdnsTtlPercent,
.22, .55);
}
{
SCOPED_TRACE("ddns-ttl");
testNetworkInheritance<TestNetwork6>(&Network::getDdnsTtl,
&Network::setDdnsTtl,
300, 400);
}
{
SCOPED_TRACE("ddns-ttl-min");
testNetworkInheritance<TestNetwork6>(&Network::getDdnsTtlMin,
&Network::setDdnsTtlMin,
100, 200);
}
{
SCOPED_TRACE("ddns-ttl-max");
testNetworkInheritance<TestNetwork6>(&Network::getDdnsTtlMax,
&Network::setDdnsTtlMax,
500, 600);
}
// Interface-id requires special type of test.
boost::shared_ptr<TestNetwork6> net_child(new TestNetwork6());

View File

@ -106,8 +106,155 @@ public:
/// @param test_config JSON configuration text to parse
/// @return A reference to the Network created if parsing is successful
virtual Network& parseIntoNetwork(ConstElementPtr test_config) = 0;
};
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SharedNetwork4.
template<typename NetworkTypePtr, typename ParserType>
void validDdnsTtlParmatersTest() {
struct Scenario {
size_t line_no_;
std::string json_;
double ddns_ttl_percent_;
uint32_t ddns_ttl_;
uint32_t ddns_ttl_min_;
uint32_t ddns_ttl_max_;
};
std::list<Scenario> scenarios = {
{
__LINE__,
R"^({
"name": "one",
"ddns-ttl": 100
})^",
0.0, 100, 0, 0
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-percent": 5.0
})^",
5.0, 0, 0, 0
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-min": 25
})^",
0.0, 0, 25, 0
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-max": 150
})^",
0.0, 0, 0, 150
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-min": 25,
"ddns-ttl-max": 150
})^",
0.0, 0, 25, 150
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-percent": 5.0,
"ddns-ttl-min": 25,
"ddns-ttl-max": 150
})^",
5.0, 0, 25, 150
}};
for (const auto& scenario : scenarios) {
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_));
ParserType parser;
NetworkTypePtr network;
ASSERT_NO_THROW_LOG(network = parser.parse(config_element));
ASSERT_TRUE(network);
EXPECT_EQ(network->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
EXPECT_EQ(network->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
EXPECT_EQ(network->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
EXPECT_EQ(network->getDdnsTtl(), scenario.ddns_ttl_);
EXPECT_EQ(network->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
EXPECT_EQ(network->getDdnsTtlMin(), scenario.ddns_ttl_min_);
EXPECT_EQ(network->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
EXPECT_EQ(network->getDdnsTtlMax(), scenario.ddns_ttl_max_);
}
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SharedNetwork.
template<typename ParserType>
void invalidDdnsTtlParmatersTest() {
struct Scenario {
size_t line_no_;
std::string json_;
std::string exp_message_;
};
std::list<Scenario> scenarios = {
{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-percent": 5.0,
"ddns-ttl": 100
})^",
"cannot specify both ddns-ttl-percent and ddns-ttl (<string>:1:2)"
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl": 100,
"ddns-ttl-min": 25
})^",
"cannot specify both ddns-ttl-min and ddns-ttl (<string>:1:2)"
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl": 100,
"ddns-ttl-max": 150
})^",
"cannot specify both ddns-ttl-max and ddns-ttl (<string>:1:2)"
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-min": 150,
"ddns-ttl-max": 25
})^",
"ddns-ttl-max: 25 must be greater than ddns-ttl-min: 150 (<string>:1:2)"
}};
for (const auto& scenario : scenarios) {
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_));
ParserType parser;
ASSERT_THROW_MSG(parser.parse(config_element), DhcpConfigError, scenario.exp_message_);
}
}
};
/// @brief Test fixture class for SharedNetwork4Parser class.
class SharedNetwork4ParserTest : public SharedNetworkParserTest {
@ -1215,5 +1362,28 @@ TEST_F(SharedNetwork6ParserTest, deprecatedClientClass) {
" (<string>:1:2)");
}
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SharedNetwork4.
TEST_F(SharedNetwork4ParserTest, validDdnsTtlParmaters4) {
validDdnsTtlParmatersTest<SharedNetwork4Ptr, SharedNetwork4Parser>();
}
// Verifies valid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for SharedNetwork6.
TEST_F(SharedNetwork6ParserTest, validDdnsTtlParmaters6) {
validDdnsTtlParmatersTest<SharedNetwork6Ptr, SharedNetwork6Parser>();
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet4.
TEST_F(SharedNetwork4ParserTest, invalidDdnsTtlParmaters4) {
invalidDdnsTtlParmatersTest<SharedNetwork4Parser>();
}
// Verifies invalid permuatations of ddns-ttl-percent, ddns-ttl,
// ddns-ttl-min, and ddns-ttl-max values for Subnet6.
TEST_F(SharedNetwork6ParserTest, invalidDdnsTtlParmaters6) {
invalidDdnsTtlParmatersTest<SharedNetwork6Parser>();
}
} // end of anonymous namespace

View File

@ -2214,4 +2214,73 @@ TEST_F(SrvConfigTest, sanityChecksLifetime) {
}
}
// Verifies that sanityChecksDdnsTtlParams works as expected.
TEST_F(SrvConfigTest, sanityChecksDdnsTtlParameters) {
{
SCOPED_TRACE("none");
SrvConfig conf(32);
EXPECT_NO_THROW(conf.sanityChecksDdnsTtlParameters());
}
{
SCOPED_TRACE("ddns-ttl only");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl", Element::create(200));
EXPECT_NO_THROW(conf.sanityChecksDdnsTtlParameters());
}
{
SCOPED_TRACE("ddns-ttl and ddns-ttl-percent");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl", Element::create(200));
conf.addConfiguredGlobal("ddns-ttl-percent", Element::create(50.0));
EXPECT_THROW_MSG(conf.sanityChecksDdnsTtlParameters(), isc::BadValue,
"cannot specify both ddns-ttl-percent and ddns-ttl");
}
{
SCOPED_TRACE("ddns-ttl and ddns-ttl-min");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl", Element::create(200));
conf.addConfiguredGlobal("ddns-ttl-min", Element::create(100));
EXPECT_THROW_MSG(conf.sanityChecksDdnsTtlParameters(), isc::BadValue,
"cannot specify both ddns-ttl-min and ddns-ttl");
}
{
SCOPED_TRACE("ddns-ttl and ddns-ttl-max");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl", Element::create(200));
conf.addConfiguredGlobal("ddns-ttl-max", Element::create(100));
EXPECT_THROW_MSG(conf.sanityChecksDdnsTtlParameters(), isc::BadValue,
"cannot specify both ddns-ttl-max and ddns-ttl");
}
{
SCOPED_TRACE("ddns-ttl-min < ddns-ttl-max");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl-min", Element::create(25));
conf.addConfiguredGlobal("ddns-ttl-max", Element::create(100));
EXPECT_NO_THROW(conf.sanityChecksDdnsTtlParameters());
}
{
SCOPED_TRACE("ddns-ttl-min > ddns-ttl-max");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl-min", Element::create(100));
conf.addConfiguredGlobal("ddns-ttl-max", Element::create(25));
EXPECT_THROW_MSG(conf.sanityChecksDdnsTtlParameters(), isc::BadValue,
"ddns-ttl-max: 25 must be greater than ddns-ttl-min: 100");
}
{
SCOPED_TRACE("ddsn-ttl-percent and ddns-ttl-min < ddns-ttl-max");
SrvConfig conf(32);
conf.addConfiguredGlobal("ddns-ttl-percent", Element::create(50.0));
conf.addConfiguredGlobal("ddns-ttl-min", Element::create(25));
conf.addConfiguredGlobal("ddns-ttl-max", Element::create(100));
EXPECT_NO_THROW(conf.sanityChecksDdnsTtlParameters());
}
}
} // end of anonymous namespace

View File

@ -340,6 +340,13 @@ dumpAsHex(const uint8_t* data, size_t length) {
return (output.str());
}
string
dumpDouble(double val, size_t precision) {
std::stringstream oss;
oss << setprecision(precision) << val;
return (oss.str());
}
} // namespace str
} // namespace util
} // namespace isc

View File

@ -286,6 +286,13 @@ isPrintable(const std::vector<uint8_t>& content);
std::string
dumpAsHex(const uint8_t* data, size_t length);
/// @brief Converts a double to a string with given precision
///
/// @param val double to convert
/// @param precision number of maxium number decimal places to output
/// @return string representaion of val
std::string dumpDouble(double val, size_t precision = 5);
} // namespace str
} // namespace util
} // namespace isc