From a40b586fe8654cfcd9a9439bfae29fe3fb7361c7 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Tue, 4 Mar 2025 23:10:56 +0200 Subject: [PATCH] [#3755] backport #3578 to 2.6.2 --- src/bin/agent/parser_context.cc | 5 +- src/bin/d2/parser_context.cc | 5 +- src/bin/dhcp4/parser_context.cc | 5 +- src/bin/dhcp4/tests/config_parser_unittest.cc | 1552 ++++---- src/bin/dhcp4/tests/get_config_unittest.cc | 1212 ++++-- .../dhcp4/tests/get_config_unittest.cc.skel | 19 +- .../dhcp4/tests/kea_controller_unittest.cc | 6 +- src/bin/dhcp6/parser_context.cc | 5 +- src/bin/dhcp6/tests/config_parser_unittest.cc | 2059 ++++++---- src/bin/dhcp6/tests/get_config_unittest.cc | 3391 +++++++++++++---- .../dhcp6/tests/get_config_unittest.cc.skel | 19 +- .../dhcp6/tests/kea_controller_unittest.cc | 12 +- src/bin/netconf/parser_context.cc | 5 +- src/lib/database/database_connection.cc | 4 +- .../tests/database_connection_unittest.cc | 1 + 15 files changed, 5775 insertions(+), 2525 deletions(-) diff --git a/src/bin/agent/parser_context.cc b/src/bin/agent/parser_context.cc index 7c18e034e3..675fda3db6 100644 --- a/src/bin/agent/parser_context.cc +++ b/src/bin/agent/parser_context.cc @@ -57,15 +57,14 @@ ParserContext::parseCommon() { isc_throw(ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/d2/parser_context.cc b/src/bin/d2/parser_context.cc index 26ee144e23..83724e820c 100644 --- a/src/bin/d2/parser_context.cc +++ b/src/bin/d2/parser_context.cc @@ -57,15 +57,14 @@ D2ParserContext::parseCommon() { isc_throw(D2ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(D2ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(D2ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp4/parser_context.cc b/src/bin/dhcp4/parser_context.cc index c13d264133..126f2eee2e 100644 --- a/src/bin/dhcp4/parser_context.cc +++ b/src/bin/dhcp4/parser_context.cc @@ -55,15 +55,14 @@ Parser4Context::parseCommon() { isc_throw(Dhcp4ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(Dhcp4ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(Dhcp4ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index 16db37949d..8f0d8467ab 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -6,48 +6,52 @@ #include -#include -#include - +#include #include -#include -#include -#include +#include +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include +#include +#include #include #include #include +#include #include +#include +#include #include #include -#include #include +#include #include -#include #include +#include #include #include #include -#include "marker_file.h" -#include "test_libraries.h" -#include "test_data_files_config.h" -#include "dhcp4_test_utils.h" -#include "get_config_unittest.h" - #include #include -#include #include -#include +#include +#include + +#include +#include +#include + +#include "dhcp4_test_utils.h" +#include "get_config_unittest.h" +#include "marker_file.h" +#include "test_libraries.h" using namespace isc; using namespace isc::asiolink; @@ -62,7 +66,7 @@ using namespace std; namespace { const char* PARSER_CONFIGS[] = { - // CONFIGURATION 0: one subnet with one pool, no user contexts + // Configuration 0: one subnet with one pool, no user contexts "{" " \"interfaces-config\": {" " \"interfaces\": [\"*\" ]" @@ -162,12 +166,39 @@ const char* PARSER_CONFIGS[] = { " \"type\": \"mysql\"," " \"name\": \"keatest2\"," " \"user\": \"keatest\"," + " \"retry-on-startup\": true," " \"password\": \"keatest\"" " }" " ]" "}", - // Configuration 5 for comments + // Configuration 5: config databases + "{ \n" + " \"interfaces-config\": { \n" + " \"interfaces\": [\"*\" ] \n" + " }, \n" + " \"valid-lifetime\": 4000, \n" + " \"rebind-timer\": 2000, \n" + " \"renew-timer\": 1000, \n" + " \"config-control\": { \n" + " \"config-fetch-wait-time\": 10, \n" + " \"config-databases\": [ { \n" + " \"type\": \"mysql\", \n" + " \"name\": \"keatest1\", \n" + " \"user\": \"keatest\", \n" + " \"password\": \"keatest\" \n" + " },{ \n" + " \"type\": \"mysql\", \n" + " \"name\": \"keatest2\", \n" + " \"user\": \"keatest\", \n" + " \"retry-on-startup\": true, \n" + " \"password\": \"keatest\" \n" + " } \n" + " ] \n" + " } \n" + "} \n", + + // Configuration 6 for comments "{" " \"comment\": \"A DHCPv4 server\"," " \"interfaces-config\": {" @@ -241,32 +272,7 @@ const char* PARSER_CONFIGS[] = { " \"comment\": \"No dynamic DNS\"," " \"enable-updates\": false" " }" - "}", - - // Configuration 6: config databases - "{ \n" - " \"interfaces-config\": { \n" - " \"interfaces\": [\"*\" ] \n" - " }, \n" - " \"valid-lifetime\": 4000, \n" - " \"rebind-timer\": 2000, \n" - " \"renew-timer\": 1000, \n" - " \"config-control\": { \n" - " \"config-fetch-wait-time\": 10, \n" - " \"config-databases\": [ { \n" - " \"type\": \"mysql\", \n" - " \"name\": \"keatest1\", \n" - " \"user\": \"keatest\", \n" - " \"password\": \"keatest\" \n" - " },{ \n" - " \"type\": \"mysql\", \n" - " \"name\": \"keatest2\", \n" - " \"user\": \"keatest\", \n" - " \"password\": \"keatest\" \n" - " } \n" - " ] \n" - " } \n" - "} \n" + "}" }; class Dhcp4ParserTest : public LogContentTest { @@ -281,17 +287,40 @@ protected: } public: - Dhcp4ParserTest() - : rcode_(-1) { - // Open port 0 means to not do anything at all. We don't want to + Dhcp4ParserTest() : rcode_(-1) { + // Open port 0 means to not open any sockets. We don't want to // deal with sockets here, just check if configuration handling // is sane. srv_.reset(new ControlledDhcpv4Srv(0)); - // Create fresh context. + + const IfaceCollection& ifaces = IfaceMgr::instance().getIfaces(); + + // There must be some interface detected + if (ifaces.empty()) { + // We can't use ASSERT in constructor + ADD_FAILURE() << "No interfaces detected."; + } + + valid_iface_ = (*ifaces.begin())->getName(); + bogus_iface_ = "nonexisting0"; + + if (IfaceMgr::instance().getIface(bogus_iface_)) { + ADD_FAILURE() << "The '" << bogus_iface_ << "' exists on this system" + << " while the test assumes that it doesn't, to execute" + << " some negative scenarios. Can't continue this test."; + } + // Reset configuration for each test. resetConfiguration(); } -public: + ~Dhcp4ParserTest() { + // Reset configuration database after each test. + resetConfiguration(); + + // ... and delete the hooks library marker files if present + static_cast(remove(LOAD_MARKER_FILE)); + static_cast(remove(UNLOAD_MARKER_FILE)); + }; // Checks if the result of DHCP server configuration has // expected code (0 for success, other for failures). @@ -308,7 +337,7 @@ public: void checkResult(ConstElementPtr status, int expected_code, string expected_txt) { ASSERT_TRUE(status); - comment_ = parseAnswer(rcode_, status); + comment_ = parseAnswerText(rcode_, status); EXPECT_EQ(expected_code, rcode_) << "error text:" << comment_->stringValue(); ASSERT_TRUE(comment_); ASSERT_EQ(Element::string, comment_->getType()); @@ -325,11 +354,7 @@ public: void configure(std::string config, int expected_code, std::string exp_error = "") { ConstElementPtr json; - try { - json = parseDHCP4(config, true); - } catch(const std::exception& ex) { - ADD_FAILURE() << "parseDHCP4 failed: " << ex.what(); - } + ASSERT_NO_THROW_LOG(json = parseDHCP4(config, true)); ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); @@ -354,14 +379,6 @@ public: } } - ~Dhcp4ParserTest() { - resetConfiguration(); - - // ... and delete the hooks library marker files if present - static_cast(remove(LOAD_MARKER_FILE)); - static_cast(remove(UNLOAD_MARKER_FILE)); - }; - /// @brief Returns an interface configuration used by the most of the /// unit tests. std::string genIfaceConfig() const { @@ -427,7 +444,8 @@ public: /// @params params map holding parameters and their values. /// @return configuration string containing custom values of parameters /// describing an option. - std::string createConfigWithOption(const std::map& params) { + std::string createConfigWithOption(const std::map& params) { std::ostringstream stream; stream << "{ " << genIfaceConfig() << "," << "\"rebind-timer\": 2000, " @@ -450,7 +468,7 @@ public: } else if (param.first == "space") { stream << "\"space\": \"" << param.second << "\""; } else if (param.first == "code") { - stream << "\"code\": " << param.second << ""; + stream << "\"code\": " << param.second; } else if (param.first == "data") { stream << "\"data\": \"" << param.second << "\""; } else if (param.first == "csv-format") { @@ -486,10 +504,10 @@ public: Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()-> getCfgSubnets4()->selectSubnet(subnet_address); if (!subnet) { - /// @todo replace toText() with the use of operator <<. ADD_FAILURE() << "A subnet for the specified address " - << subnet_address.toText() - << "does not exist in Config Manager"; + << subnet_address + << " does not exist in Config Manager"; + return (OptionDescriptor(false, false)); } OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP4_OPTION_SPACE); @@ -539,6 +557,7 @@ public: EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 1); EXPECT_TRUE(errorContainsPosition(x, "")); + CfgMgr::instance().clear(); } /// @brief Test invalid option parameter value. @@ -556,6 +575,7 @@ public: EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 1); EXPECT_TRUE(errorContainsPosition(x, "")); + CfgMgr::instance().clear(); } /// @brief Test option against given code and data. @@ -595,7 +615,8 @@ public: } // Verify that the data is correct. Do not verify suboptions and a header. const uint8_t* data = buf.getData(); - EXPECT_EQ(0, memcmp(expected_data, data + option_desc.option_->getHeaderLen(), + EXPECT_EQ(0, memcmp(expected_data, + data + option_desc.option_->getHeaderLen(), expected_data_len)); } @@ -623,13 +644,17 @@ public: const uint16_t option_code, const uint8_t* expected_data, const size_t expected_data_len) { + CfgMgr::instance().clear(); + std::string config = createConfigWithOption(params); ASSERT_TRUE(executeConfiguration(config, "parse option configuration")); + // The subnet should now hold one option with the specified option code. OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"), option_code); ASSERT_TRUE(desc.option_); testOption(desc, option_code, expected_data, expected_data_len); + CfgMgr::instance().clear(); } /// @brief Parse and Execute configuration @@ -687,19 +712,22 @@ public: /// @brief Reset configuration database. /// - /// This function resets configuration data base by - /// removing all subnets and option-data. Reset must - /// be performed after each test to make sure that - /// contents of the database do not affect result of - /// subsequent tests. + /// This function resets configuration data base by removing all subnets + /// option-data, and hooks libraries. The reset must be performed after each + /// test to make sure that contents of the database do not affect the + /// results of subsequent tests. void resetConfiguration() { // The default setting is to listen on all interfaces. In order to // properly test interface configuration we disable listening on // all interfaces before each test and later check that this setting // has been overridden by the configuration used in the test. CfgMgr::instance().clear(); - string config = "{ " + genIfaceConfig() + "," + - "\"hooks-libraries\": [ ], " + string config = "{ \"interfaces-config\": {" + " \"interfaces\": [ ]" + "}," + "\"hooks-libraries\": [ ]," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " "\"valid-lifetime\": 4000, " "\"subnet4\": [ ], " "\"dhcp-ddns\": { \"enable-updates\" : false }, " @@ -836,9 +864,11 @@ public: << isc::data::prettyPrint(exp_value); } - boost::scoped_ptr srv_; ///< DHCP4 server under test int rcode_; ///< Return code from element parsing - ConstElementPtr comment_; ///< Reason for parse fail + boost::scoped_ptr srv_; ///< Instance of the Dhcpv4Srv used during tests + ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer) + string valid_iface_; ///< Valid network interface name (present in system) + string bogus_iface_; ///< invalid network interface name (not in system) isc::dhcp::ClientClasses classify_; ///< used in client classification }; @@ -862,7 +892,8 @@ TEST_F(Dhcp4ParserTest, bogusCommand) { TEST_F(Dhcp4ParserTest, emptyInterfaceConfig) { ConstElementPtr json; - EXPECT_NO_THROW(json = parseDHCP4("{ \"rebind-timer\": 2000, " + EXPECT_NO_THROW(json = parseDHCP4("{ " + "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"valid-lifetime\": 4000 }")); @@ -873,34 +904,12 @@ TEST_F(Dhcp4ParserTest, emptyInterfaceConfig) { checkResult(status, 0); } -/// The goal of this test is to verify if wrongly defined subnet will -/// be rejected. Properly defined subnet must include at least one -/// pool definition. -TEST_F(Dhcp4ParserTest, emptySubnet) { - - std::string config = "{ " + genIfaceConfig() + "," + - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"subnet4\": [ ], " - "\"valid-lifetime\": 4000 }"; - - ConstElementPtr json; - EXPECT_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); -} - /// Check that valid-lifetime must be between min-valid-lifetime and /// max-valid-lifetime when a bound is specified, *AND* a subnet is /// specified (boundary check is done when lifetimes are applied). TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"subnet4\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," @@ -918,7 +927,7 @@ TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"subnet4\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," @@ -933,7 +942,7 @@ TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"subnet4\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," @@ -949,7 +958,7 @@ TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"subnet4\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," @@ -965,7 +974,7 @@ TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"subnet4\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," @@ -986,7 +995,7 @@ TEST_F(Dhcp4ParserTest, outBoundValidLifetime) { /// parameters only. TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1000, \"min-valid-lifetime\": 2000 }"; ConstElementPtr json; @@ -1000,7 +1009,7 @@ TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 2000, \"max-valid-lifetime\": 1000 }"; ASSERT_NO_THROW(json = parseDHCP4(too_large)); @@ -1011,7 +1020,7 @@ TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1000, \"min-valid-lifetime\": 2000, " "\"max-valid-lifetime\": 4000 }"; @@ -1023,7 +1032,7 @@ TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 5000, \"min-valid-lifetime\": 1000, " "\"max-valid-lifetime\": 4000 }"; @@ -1035,7 +1044,7 @@ TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1500, \"min-valid-lifetime\": 2000, " "\"max-valid-lifetime\": 1000 }"; @@ -1051,7 +1060,7 @@ TEST_F(Dhcp4ParserTest, outBoundGlobalValidLifetime) { /// it is marked unspecified in the Subnet. TEST_F(Dhcp4ParserTest, unspecifiedRenewTimer) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"subnet4\": [ { " " \"id\": 1," @@ -1086,7 +1095,7 @@ TEST_F(Dhcp4ParserTest, unspecifiedRenewTimer) { /// it is marked unspecified in the Subnet. TEST_F(Dhcp4ParserTest, unspecifiedRebindTimer) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"id\": 1," @@ -1116,11 +1125,32 @@ TEST_F(Dhcp4ParserTest, unspecifiedRebindTimer) { EXPECT_EQ(1, subnet->getID()); } +/// The goal of this test is to verify if configuration without any +/// subnets defined can be accepted. +TEST_F(Dhcp4ParserTest, emptySubnet) { + + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ ], " + "\"valid-lifetime\": 4000 }"; + + 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); +} + /// The goal of this test is to verify if defined subnet uses global /// parameter timer definitions. TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1160,36 +1190,37 @@ TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) { TEST_F(Dhcp4ParserTest, multipleSubnetsExplicitIDs) { ConstElementPtr x; // Four subnets with arbitrary subnet ids. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"id\": 1024 " + " \"id\": 1024" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," " \"subnet\": \"192.0.3.0/24\", " - " \"id\": 100 " + " \"id\": 100" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"id\": 1 " + " \"id\": 1" " }," " {" " \"pools\": [ { \"pool\": \"192.0.5.101 - 192.0.5.150\" } ]," " \"subnet\": \"192.0.5.0/24\", " - " \"id\": 34 " + " \"id\": 34" " } ]," "\"valid-lifetime\": 4000 }"; + int cnt = 0; // Number of reconfigurations + ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); - int cnt = 0; // Number of reconfigurations do { EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 0); @@ -1214,32 +1245,32 @@ TEST_F(Dhcp4ParserTest, multipleSubnetsExplicitIDs) { } while (++cnt < 3); } -// Check that the configuration with two subnets having the same id is rejected. +// Check that the configuration with two subnets having the same ID is rejected. TEST_F(Dhcp4ParserTest, multipleSubnetsOverlappingIDs) { ConstElementPtr x; - // Four subnets, two of them having the same id. - string config = "{ " + genIfaceConfig() + "," + + // Four subnets, two of them have the same id. + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"id\": 1024 " + " \"id\": 1024" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," " \"subnet\": \"192.0.3.0/24\", " - " \"id\": 100 " + " \"id\": 100" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"id\": 1024 " + " \"id\": 1024" " }," " {" " \"pools\": [ { \"pool\": \"192.0.5.101 - 192.0.5.150\" } ]," " \"subnet\": \"192.0.5.0/24\", " - " \"id\": 34 " + " \"id\": 34" " } ]," "\"valid-lifetime\": 4000 }"; @@ -1257,70 +1288,70 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { ConstElementPtr x; // All four subnets - string config4 = "{ " + genIfaceConfig() + "," + + string config4 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"id\": 1 " + " \"id\": 1" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," " \"subnet\": \"192.0.3.0/24\", " - " \"id\": 2 " + " \"id\": 2" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"id\": 3 " + " \"id\": 3" " }," " {" " \"pools\": [ { \"pool\": \"192.0.5.101 - 192.0.5.150\" } ]," " \"subnet\": \"192.0.5.0/24\", " - " \"id\": 4 " + " \"id\": 4" " } ]," "\"valid-lifetime\": 4000 }"; // Three subnets (the last one removed) - string config_first3 = "{ " + genIfaceConfig() + "," + + string config_first3 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"id\": 1 " + " \"id\": 1" " }," " {" " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," " \"subnet\": \"192.0.3.0/24\", " - " \"id\": 2 " + " \"id\": 2" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"id\": 3 " + " \"id\": 3" " } ]," "\"valid-lifetime\": 4000 }"; // Second subnet removed - string config_second_removed = "{ " + genIfaceConfig() + "," + + string config_second_removed = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\", " - " \"id\": 1 " + " \"id\": 1" " }," " {" " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," " \"subnet\": \"192.0.4.0/24\", " - " \"id\": 3 " + " \"id\": 3" " }," " {" " \"pools\": [ { \"pool\": \"192.0.5.101 - 192.0.5.150\" } ]," " \"subnet\": \"192.0.5.0/24\", " - " \"id\": 4 " + " \"id\": 4" " } ]," "\"valid-lifetime\": 4000 }"; @@ -1329,11 +1360,14 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config4)); + extractConfig(config4); EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 0); + CfgMgr::instance().commit(); + const Subnet4Collection* subnets = - CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll(); + CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll(); ASSERT_TRUE(subnets); ASSERT_EQ(4, subnets->size()); // We expect 4 subnets @@ -1344,7 +1378,9 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 0); - subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll(); + CfgMgr::instance().commit(); + + subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll(); ASSERT_TRUE(subnets); ASSERT_EQ(3, subnets->size()); // We expect 3 subnets now (4th is removed) @@ -1362,22 +1398,24 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 0); - CfgMgr::instance().clear(); + CfgMgr::instance().commit(); // Do reconfiguration ASSERT_NO_THROW(json = parseDHCP4(config_second_removed)); EXPECT_NO_THROW(x = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(x, 0); - subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll(); + CfgMgr::instance().commit(); + + subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll(); ASSERT_TRUE(subnets); ASSERT_EQ(3, subnets->size()); // We expect 4 subnets - auto subnet_it = subnets->begin(); - EXPECT_EQ(1, (*subnet_it)->getID()); + subnet = subnets->begin(); + EXPECT_EQ(1, (*subnet)->getID()); // The second subnet (with subnet-id = 2) is no longer there - EXPECT_EQ(3, (*++subnet_it)->getID()); - EXPECT_EQ(4, (*++subnet_it)->getID()); + EXPECT_EQ(3, (*++subnet)->getID()); + EXPECT_EQ(4, (*++subnet)->getID()); } /// @todo: implement subnet removal test as part of #3281. @@ -1386,7 +1424,7 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { // global parameter are taken into consideration. TEST_F(Dhcp4ParserTest, nextServerGlobal) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"next-server\": \"1.2.3.4\", " @@ -1426,7 +1464,7 @@ TEST_F(Dhcp4ParserTest, nextServerGlobal) { // subnet parameter are taken into consideration. TEST_F(Dhcp4ParserTest, nextServerSubnet) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1464,7 +1502,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { IfaceMgrTestConfig test_config(true); // Config with junk instead of next-server address - string config_bogus1 = "{ " + genIfaceConfig() + "," + + string config_bogus1 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1477,7 +1515,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { "\"valid-lifetime\": 4000 }"; // Config with IPv6 next server address - string config_bogus2 = "{ " + genIfaceConfig() + "," + + string config_bogus2 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1490,7 +1528,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { "\"valid-lifetime\": 4000 }"; // Config with empty next server address - string config_bogus3 = "{ " + genIfaceConfig() + "," + + string config_bogus3 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1504,7 +1542,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { // Config with too large server-hostname string bigsname(Pkt4::MAX_SNAME_LEN + 1, ' '); - string config_bogus4 = "{ " + genIfaceConfig() + "," + + string config_bogus4 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1518,7 +1556,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { // Config with too large boot-file-hostname string bigfilename(Pkt4::MAX_FILE_LEN + 1, ' '); - string config_bogus5 = "{ " + genIfaceConfig() + "," + + string config_bogus5 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1576,7 +1614,7 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { // specific value. TEST_F(Dhcp4ParserTest, nextServerOverride) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"next-server\": \"192.0.0.1\", " @@ -1614,7 +1652,7 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) { // Check whether it is possible to configure echo-client-id TEST_F(Dhcp4ParserTest, echoClientId) { - string config_false = "{ " + genIfaceConfig() + "," + + string config_false = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"echo-client-id\": false," @@ -1624,7 +1662,7 @@ TEST_F(Dhcp4ParserTest, echoClientId) { " \"subnet\": \"192.0.2.0/24\" } ]," "\"valid-lifetime\": 4000 }"; - string config_true = "{ " + genIfaceConfig() + "," + + string config_true = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"echo-client-id\": true," @@ -1663,7 +1701,7 @@ TEST_F(Dhcp4ParserTest, echoClientId) { // Check whether it is possible to configure compatibility flags. TEST_F(Dhcp4ParserTest, compatibility) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"compatibility\": { " @@ -1701,7 +1739,7 @@ TEST_F(Dhcp4ParserTest, compatibility) { // Check that unknown compatibility flag raises error. TEST_F(Dhcp4ParserTest, compatibilityUnknown) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"compatibility\": { " @@ -1728,7 +1766,7 @@ TEST_F(Dhcp4ParserTest, compatibilityUnknown) { // Check that not boolean compatibility flag value raises error. TEST_F(Dhcp4ParserTest, compatibilityNotBool) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"compatibility\": { " @@ -1756,7 +1794,7 @@ TEST_F(Dhcp4ParserTest, compatibilityNotBool) { // This test checks that the global match-client-id parameter is optional // and that values under the subnet are used. TEST_F(Dhcp4ParserTest, matchClientIdNoGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -1804,7 +1842,7 @@ TEST_F(Dhcp4ParserTest, matchClientIdNoGlobal) { // when there is no such parameter under subnet and that the parameter // specified for a subnet overrides the global setting. TEST_F(Dhcp4ParserTest, matchClientIdGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"match-client-id\": true," @@ -1851,7 +1889,7 @@ TEST_F(Dhcp4ParserTest, matchClientIdGlobal) { // This test checks that the global authoritative parameter is optional // and that values under the subnet are used. TEST_F(Dhcp4ParserTest, authoritativeNoGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -1899,7 +1937,7 @@ TEST_F(Dhcp4ParserTest, authoritativeNoGlobal) { // when there is no such parameter under subnet and that the parameter // specified for a subnet overrides the global setting. TEST_F(Dhcp4ParserTest, authoritativeGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"authoritative\": true," @@ -1947,7 +1985,7 @@ TEST_F(Dhcp4ParserTest, authoritativeGlobal) { // on a per subnet basis. TEST_F(Dhcp4ParserTest, subnetLocal) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -1983,81 +2021,57 @@ TEST_F(Dhcp4ParserTest, subnetLocal) { EXPECT_EQ(5, subnet->getValid().getMax()); } -// This test checks that multiple pools can be defined and handled properly. -// The test defines 2 subnets, each with 2 pools. -TEST_F(Dhcp4ParserTest, multiplePools) { +// This test checks if it is possible to define a subnet with an +// interface defined. +TEST_F(Dhcp4ParserTest, subnetInterface) { + + // There should be at least one interface + // As far as I can tell, this is the first lambda in Kea code. Cool. + auto config = [this](string iface) { + return ("{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ { " + " \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"interface\": \"" + iface + "\"," + " \"subnet\": \"192.0.2.0/24\" } ]," + "\"valid-lifetime\": 4000 }"); }; + cout << config(valid_iface_) << endl; - // Collection with two subnets, each with 2 pools. - string config = "{ " + genIfaceConfig() + "," + - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"subnet4\": [ { " - " \"id\": 1," - " \"pools\": [ " - " { \"pool\": \"192.0.2.0/28\" }," - " { \"pool\": \"192.0.2.200-192.0.2.255\" }" - " ]," - " \"subnet\": \"192.0.2.0/24\" " - " }," - " {" - " \"id\": 2," - " \"pools\": [ " - " { \"pool\": \"192.0.3.0/25\" }," - " { \"pool\": \"192.0.3.128/25\" }" - " ]," - " \"subnet\": \"192.0.3.0/24\"" - " } ]," - "\"valid-lifetime\": 4000 }"; ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP4(config)); - extractConfig(config); + ASSERT_NO_THROW(json = parseDHCP4(config(valid_iface_))); + extractConfig(config("eth0")); ConstElementPtr status; - ASSERT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); - checkResult(status, 0); - - const Subnet4Collection* subnets = - CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll(); - ASSERT_TRUE(subnets); - ASSERT_EQ(2, subnets->size()); // We expect 2 subnets + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); - // Check the first subnet - auto subnet = subnets->begin(); - const PoolCollection& pools1 = (*subnet)->getPools(Lease::TYPE_V4); - ASSERT_EQ(2, pools1.size()); - EXPECT_EQ("type=V4, 192.0.2.0-192.0.2.15", - pools1[0]->toText()); - EXPECT_EQ("type=V4, 192.0.2.200-192.0.2.255", - pools1[1]->toText()); - // There shouldn't be any TA or PD pools - EXPECT_THROW((*subnet)->getPools(Lease::TYPE_TA), BadValue); - EXPECT_THROW((*subnet)->getPools(Lease::TYPE_PD), BadValue); + // returned value should be 0 (configuration success) + checkResult(status, 0); - // Check the second subnet - ++subnet; - const PoolCollection& pools2 = (*subnet)->getPools(Lease::TYPE_V4); - ASSERT_EQ(2, pools2.size()); - EXPECT_EQ("type=V4, 192.0.3.0-192.0.3.127", - pools2[0]->toText()); - EXPECT_EQ("type=V4, 192.0.3.128-192.0.3.255", - pools2[1]->toText()); - // There shouldn't be any TA or PD pools - EXPECT_THROW((*subnet)->getPools(Lease::TYPE_TA), BadValue); - EXPECT_THROW((*subnet)->getPools(Lease::TYPE_PD), BadValue); + Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()-> + selectSubnet(IOAddress("192.0.2.200"), classify_); + ASSERT_TRUE(subnet); + EXPECT_EQ(valid_iface_, subnet->getIface().get()); } -// Test verifies that a subnet with pool values that do not belong to that -// pool are rejected. -TEST_F(Dhcp4ParserTest, poolOutOfSubnet) { +// This test checks if invalid interface name will be rejected in +// Subnet4 definition. +TEST_F(Dhcp4ParserTest, subnetInterfaceBogus) { - string config = "{ " + genIfaceConfig() + "," + + // There should be at least one interface + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " " \"id\": 1," - " \"pools\": [ { \"pool\": \"192.0.4.0/28\" } ]," + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"interface\": \"" + bogus_iface_ + "\"," " \"subnet\": \"192.0.2.0/24\" } ]," "\"valid-lifetime\": 4000 }"; + cout << config << endl; ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); @@ -2065,27 +2079,212 @@ TEST_F(Dhcp4ParserTest, poolOutOfSubnet) { ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); - // returned value must be 1 (values error) - // as the pool does not belong to that subnet + // returned value should be 1 (configuration error) checkResult(status, 1); EXPECT_TRUE(errorContainsPosition(status, "")); + + Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()-> + selectSubnet(IOAddress("192.0.2.200"), classify_); + EXPECT_FALSE(subnet); } -// Goal of this test is to verify if pools can be defined -// using prefix/length notation. There is no separate test for min-max -// notation as it was tested in several previous tests. -TEST_F(Dhcp4ParserTest, poolPrefixLen) { +// This test checks if it is not allowed to define global interface +// parameter. +TEST_F(Dhcp4ParserTest, interfaceGlobal) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " + "\"interface\": \"" + valid_iface_ + "\"," // Not valid. Can be defined in subnet only "\"subnet4\": [ { " " \"id\": 1," - " \"pools\": [ { \"pool\": \"192.0.2.128/28\" } ]," + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"subnet\": \"192.0.2.0/24\" } ]," "\"valid-lifetime\": 4000 }"; + cout << config << endl; - ConstElementPtr json; + ConstElementPtr json = parseJSON(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); + + // returned value should be 1 (parse error) + checkResult(status, 1); + EXPECT_TRUE(errorContainsPosition(status, "")); + + EXPECT_THROW(parseDHCP4(config), Dhcp4ParseError); +} + +// Goal of this test is to verify that invalid subnet fails to be parsed. +TEST_F(Dhcp4ParserTest, badSubnetValues) { + + // Contains parts needed for a single test scenario. + struct Scenario { + std::string description_; + std::string config_json_; + std::string exp_error_msg_; + }; + + // Vector of scenarios. + std::vector scenarios = { + { + "IP is not an address", + "{ \"subnet4\": [ { " + " \"subnet\": \"not an address/24\" } ]," + "\"valid-lifetime\": 4000 }", + "subnet configuration failed: " + "Failed to convert string to address 'notanaddress': Invalid argument" + }, + { + "IP is Invalid", + "{ \"subnet4\": [ { " + " \"subnet\": \"256.16.1.0/24\" } ]," + "\"valid-lifetime\": 4000 }", + "subnet configuration failed: " + "Failed to convert string to address '256.16.1.0': Invalid argument" + }, + { + "Missing prefix", + "{ \"subnet4\": [ { " + " \"subnet\": \"192.0.2.0\" } ]," + "\"valid-lifetime\": 4000 }", + "subnet configuration failed: " + "Invalid subnet syntax (prefix/len expected):192.0.2.0 (:1:32)" + }, + { + "Prefix not an integer (2 slashes)", + "{ \"subnet4\": [ { " + " \"subnet\": \"192.0.2.0//24\" } ]," + "\"valid-lifetime\": 4000 }", + "subnet configuration failed: " + "prefix length: '/24' is not an integer (:1:32)" + }, + { + "Prefix value is insane", + "{ \"subnet4\": [ { " + " \"subnet\": \"192.0.2.0/45938\" } ]," + "\"valid-lifetime\": 4000 }", + "subnet configuration failed: " + "Invalid prefix length specified for subnet: 45938 (:1:32)" + } + }; + + // Iterate over the list of scenarios. Each should fail to parse with + // a specific error message. + for (auto const& scenario : scenarios) { + SCOPED_TRACE(scenario.description_); + ConstElementPtr config; + ASSERT_NO_THROW(config = parseDHCP4(scenario.config_json_)) + << "invalid json, broken test"; + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); + checkResult(status, 1); + ASSERT_TRUE(comment_); + EXPECT_EQ(comment_->stringValue(), scenario.exp_error_msg_); + } +} + +// This test checks that multiple pools can be defined and handled properly. +// The test defines 2 subnets, each with 2 pools. +TEST_F(Dhcp4ParserTest, multiplePools) { + // Collection with two subnets, each with 2 pools. + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ " + " { \"pool\": \"192.0.2.0/28\" }," + " { \"pool\": \"192.0.2.200-192.0.2.255\" }" + " ]," + " \"subnet\": \"192.0.2.0/24\" " + " }," + " {" + " \"id\": 2," + " \"pools\": [ " + " { \"pool\": \"192.0.3.0/25\" }," + " { \"pool\": \"192.0.3.128/25\" }" + " ]," + " \"subnet\": \"192.0.3.0/24\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP4(config)); + extractConfig(config); + + ConstElementPtr status; + ASSERT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); + checkResult(status, 0); + + const Subnet4Collection* subnets = + CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll(); + ASSERT_TRUE(subnets); + ASSERT_EQ(2, subnets->size()); // We expect 2 subnets + + // Check the first subnet + auto subnet = subnets->begin(); + const PoolCollection& pools1 = (*subnet)->getPools(Lease::TYPE_V4); + ASSERT_EQ(2, pools1.size()); + EXPECT_EQ("type=V4, 192.0.2.0-192.0.2.15", + pools1[0]->toText()); + EXPECT_EQ("type=V4, 192.0.2.200-192.0.2.255", + pools1[1]->toText()); + // There shouldn't be any TA or PD pools + EXPECT_THROW((*subnet)->getPools(Lease::TYPE_TA), BadValue); + EXPECT_THROW((*subnet)->getPools(Lease::TYPE_PD), BadValue); + + // Check the second subnet + ++subnet; + const PoolCollection& pools2 = (*subnet)->getPools(Lease::TYPE_V4); + ASSERT_EQ(2, pools2.size()); + EXPECT_EQ("type=V4, 192.0.3.0-192.0.3.127", + pools2[0]->toText()); + EXPECT_EQ("type=V4, 192.0.3.128-192.0.3.255", + pools2[1]->toText()); + // There shouldn't be any TA or PD pools + EXPECT_THROW((*subnet)->getPools(Lease::TYPE_TA), BadValue); + EXPECT_THROW((*subnet)->getPools(Lease::TYPE_PD), BadValue); +} + +// Test verifies that a subnet with pool values that do not belong to that +// pool are rejected. +TEST_F(Dhcp4ParserTest, poolOutOfSubnet) { + + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"192.0.4.0/28\" } ]," + " \"subnet\": \"192.0.2.0/24\" } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP4(config)); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); + + // returned value must be 1 (values error) + // as the pool does not belong to that subnet + checkResult(status, 1); + EXPECT_TRUE(errorContainsPosition(status, "")); +} + +// Goal of this test is to verify if pools can be defined +// using prefix/length notation. There is no separate test for min-max +// notation as it was tested in several previous tests. +TEST_F(Dhcp4ParserTest, poolPrefixLen) { + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"192.0.2.128/28\" } ]," + " \"subnet\": \"192.0.2.0/24\" } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); @@ -2108,7 +2307,7 @@ TEST_F(Dhcp4ParserTest, poolPrefixLen) { TEST_F(Dhcp4ParserTest, badPools) { // not a prefix - string config_bogus1 = "{ " + genIfaceConfig() + "," + + string config_bogus1 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2118,7 +2317,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // not a length - string config_bogus2 = "{ " + genIfaceConfig() + "," + + string config_bogus2 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2128,7 +2327,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // invalid prefix length - string config_bogus3 = "{ " + genIfaceConfig() + "," + + string config_bogus3 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2138,7 +2337,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // not a prefix nor a min-max - string config_bogus4 = "{ " + genIfaceConfig() + "," + + string config_bogus4 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2148,7 +2347,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // not an address - string config_bogus5 = "{ " + genIfaceConfig() + "," + + string config_bogus5 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2158,7 +2357,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // min > max - string config_bogus6 = "{ " + genIfaceConfig() + "," + + string config_bogus6 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2168,7 +2367,7 @@ TEST_F(Dhcp4ParserTest, badPools) { "\"valid-lifetime\": 4000 }"; // out of range prefix length (new check) - string config_bogus7 = "{ " + genIfaceConfig() + "," + + string config_bogus7 = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2241,7 +2440,7 @@ TEST_F(Dhcp4ParserTest, badPools) { TEST_F(Dhcp4ParserTest, noPools) { // Configuration string. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2253,81 +2452,13 @@ TEST_F(Dhcp4ParserTest, noPools) { EXPECT_THROW(parseDHCP4(config, true), Dhcp4ParseError); } -// Goal of this test is to verify that invalid subnet fails to be parsed. -TEST_F(Dhcp4ParserTest, badSubnetValues) { - - // Contains parts needed for a single test scenario. - struct Scenario { - std::string description_; - std::string config_json_; - std::string exp_error_msg_; - }; - - // Vector of scenarios. - std::vector scenarios = { - { - "IP is not an address", - "{ \"subnet4\": [ { " - " \"subnet\": \"not an address/24\" } ]," - "\"valid-lifetime\": 4000 }", - "subnet configuration failed: " - "Failed to convert string to address 'notanaddress': Invalid argument" - }, - { - "IP is Invalid", - "{ \"subnet4\": [ { " - " \"subnet\": \"256.16.1.0/24\" } ]," - "\"valid-lifetime\": 4000 }", - "subnet configuration failed: " - "Failed to convert string to address '256.16.1.0': Invalid argument" - }, - { - "Missing prefix", - "{ \"subnet4\": [ { " - " \"subnet\": \"192.0.2.0\" } ]," - "\"valid-lifetime\": 4000 }", - "subnet configuration failed: " - "Invalid subnet syntax (prefix/len expected):192.0.2.0 (:1:32)" - }, - { - "Prefix not an integer (2 slashes)", - "{ \"subnet4\": [ { " - " \"subnet\": \"192.0.2.0//24\" } ]," - "\"valid-lifetime\": 4000 }", - "subnet configuration failed: " - "prefix length: '/24' is not an integer (:1:32)" - }, - { - "Prefix value is insane", - "{ \"subnet4\": [ { " - " \"subnet\": \"192.0.2.0/45938\" } ]," - "\"valid-lifetime\": 4000 }", - "subnet configuration failed: " - "Invalid prefix length specified for subnet: 45938 (:1:32)" - } - }; - - // Iterate over the list of scenarios. Each should fail to parse with - // a specific error message. - for (auto const& scenario : scenarios) { - SCOPED_TRACE(scenario.description_); - ConstElementPtr config; - ASSERT_NO_THROW(config = parseDHCP4(scenario.config_json_)) - << "invalid json, broken test"; - ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); - checkResult(status, 1); - ASSERT_TRUE(comment_); - EXPECT_EQ(comment_->stringValue(), scenario.exp_error_msg_); - } -} // Goal of this test is to verify that unknown interface fails // to be parsed. TEST_F(Dhcp4ParserTest, unknownInterface) { // Configuration string. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -2854,8 +2985,9 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulateOwnSpace) { /// used by any of the standard options. TEST_F(Dhcp4ParserTest, optionStandardDefOverride) { - // Configuration string. The option code 109 is unassigned so it - // can be used for a custom option definition in dhcp4 option space. + // Configuration string. The option code 109 is unassigned + // so it can be used for a custom option definition in + // dhcp4 option space. std::string config = "{ \"option-def\": [ {" " \"name\": \"foo\"," @@ -2889,9 +3021,9 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) { EXPECT_EQ(OPT_STRING_TYPE, def->getType()); EXPECT_FALSE(def->getArrayType()); - // The combination of option space and code is invalid. The 'dhcp4' option - // space groups standard options and the code 3 is reserved for one of - // them. + // The combination of option space and code is invalid. The 'dhcp4' + // option space groups standard options and the code 3 is reserved + // for one of them. config = "{ \"option-def\": [ {" " \"name\": \"routers\"," @@ -2941,7 +3073,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) { // Goal of this test is to verify that global option data is configured TEST_F(Dhcp4ParserTest, optionDataDefaultsGlobal) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," "\"option-data\": [ {" @@ -3013,7 +3145,7 @@ TEST_F(Dhcp4ParserTest, optionDataDefaultsGlobal) { // Goal of this test is to verify that subnet option data is configured TEST_F(Dhcp4ParserTest, optionDataDefaultsSubnet) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," "\"subnet4\": [ { " @@ -3089,7 +3221,7 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) { // The definition is not required for the option that // belongs to the 'dhcp4' option space as it is the // standard option. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -3138,8 +3270,8 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) { EXPECT_EQ(56, desc1.option_->getType()); // Try to get the non-existing option from the non-existing // option space and expect that option is not returned. - OptionDescriptor desc3 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get("non-existing", 56); + OptionDescriptor desc3 = CfgMgr::instance().getStagingCfg()-> + getCfgOption()->get("non-existing", 56); ASSERT_FALSE(desc3.option_); } @@ -3152,8 +3284,8 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) { TEST_F(Dhcp4ParserTest, optionDataEncapsulate) { // @todo DHCP configurations has many dependencies between - // parameters. First of all, configuration for subnet was - // inherited from the global values. Thus subnet had to be + // parameters. First of all, configuration for subnet is + // inherited from the global values. Thus subnet has to be // configured when all global values have been configured. // Also, an option can encapsulate another option only // if the latter has been configured. For this reason in this @@ -3164,7 +3296,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) { // at the very end (when all other parameters are configured). // Starting stage 1. Configure sub-options and their definitions. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -3207,7 +3339,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) { // the configuration from the stage 2 is repeated because Kea // configuration manager sends whole configuration for the lists // where at least one element is being modified or added. - config = "{ " + genIfaceConfig() + "," + + config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 3000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -3288,7 +3420,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) { // option setting. TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"option-data\": [ {" @@ -3369,8 +3501,7 @@ TEST_F(Dhcp4ParserTest, optionDataBoolean) { " boolean value")); // The subnet should now hold one option with the code 19. - OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"), - 19); + OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"), 19); ASSERT_TRUE(desc.option_); // This option should be set to "true", represented as 0x1 in the option @@ -3432,14 +3563,13 @@ TEST_F(Dhcp4ParserTest, optionDataBoolean) { params["data"] = "01"; testConfiguration(params, 19, expected_option_data, sizeof(expected_option_data)); - } // Goal of this test is to verify options configuration // for multiple subnets. TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -3578,6 +3708,7 @@ TEST_F(Dhcp4ParserTest, optionDataSinglePool) { range = idx.equal_range(23); ASSERT_EQ(1, std::distance(range.first, range.second)); // Do another round of testing with second option. + const uint8_t foo2_expected[] = { 0x01 }; @@ -3692,12 +3823,19 @@ TEST_F(Dhcp4ParserTest, optionCodeNegative) { // Verify that out of bounds option code is rejected in the configuration. TEST_F(Dhcp4ParserTest, optionCodeNonUint8) { - // The valid option codes are uint16_t values so passing - // uint16_t maximum value incremented by 1 should result + // The valid option codes are uint8_t values so passing + // uint8_t maximum value incremented by 1 should result // in failure. testInvalidOptionParam("257", "code"); } +// Verify that out of bounds option code is rejected in the configuration. +TEST_F(Dhcp4ParserTest, optionCodeHighNonUint8) { + // Another check for uint8_t overflow but this time + // let's pass even greater option code value. + testInvalidOptionParam("500", "code"); +} + // Verify that zero option code is rejected in the configuration. TEST_F(Dhcp4ParserTest, optionCodeZero) { // Option code 0 is reserved and should not be accepted @@ -3748,7 +3886,9 @@ TEST_F(Dhcp4ParserTest, optionDataValidHexLiterals) { // returned but in theory we may have multiple options with the same // code so we get the range. std::pair range = idx.equal_range(56); + OptionContainerTypeIndex::const_iterator> range = + idx.equal_range(56); + // Expect single option with the code equal to 100. ASSERT_EQ(1, std::distance(range.first, range.second)); const uint8_t foo_expected[] = { 0x0A, 0x0B, 0x0C, 0x0D }; @@ -3784,8 +3924,7 @@ TEST_F(Dhcp4ParserTest, stdOptionData) { Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()-> getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.5")); ASSERT_TRUE(subnet); - OptionContainerPtr options = - subnet->getCfgOption()->getAll(DHCP4_OPTION_SPACE); + OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP4_OPTION_SPACE); ASSERT_TRUE(options); ASSERT_EQ(1, options->size()); @@ -3886,7 +4025,7 @@ TEST_F(Dhcp4ParserTest, domainSearchOption) { // slp-service-scope without option scope list TEST_F(Dhcp4ParserTest, slpOptions) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," "\"option-data\": [ {" @@ -3950,7 +4089,7 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) { // In the first stage we create definitions of suboptions // that we will add to the base option. // Let's create some dummy options: foo and foo2. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -3997,7 +4136,7 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) { // We add our dummy options to this option space and thus // they should be included as sub-options in the // 'vendor-encapsulated-options' option. - config = "{ " + genIfaceConfig() + "," + + config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 3000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -4085,13 +4224,13 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) { } // This test checks if vendor options can be specified in the config file -// (in hex format), and later retrieved +// (in hex format), and later retrieved from configured subnet TEST_F(Dhcp4ParserTest, vendorOptionsHex) { // This configuration string is to configure two options // sharing the code 1 and belonging to the different vendor spaces. // (different vendor-id values). - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -4125,6 +4264,7 @@ TEST_F(Dhcp4ParserTest, vendorOptionsHex) { ASSERT_TRUE(status); checkResult(status, 0); + // Options should be now available // Try to get the option from the vendor space 4491 OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()-> getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); @@ -4144,13 +4284,13 @@ TEST_F(Dhcp4ParserTest, vendorOptionsHex) { } // This test checks if vendor options can be specified in the config file, -// (in csv format), and later retrieved +// (in csv format), and later retrieved from configured subnet TEST_F(Dhcp4ParserTest, vendorOptionsCsv) { // This configuration string is to configure two options // sharing the code 1 and belonging to the different vendor spaces. // (different vendor-id values). - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," @@ -4173,15 +4313,17 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) { " } ]" "}"; + ConstElementPtr status; + ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); - ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); ASSERT_TRUE(status); checkResult(status, 0); + // Options should be now available. // Try to get the option from the vendor space 4491 OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()-> getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); @@ -4204,20 +4346,22 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) { std::string buildHooksLibrariesConfig(const std::vector& libraries = {}, bool multi_threading = true) { + const string lbrace("{"); + const string rbrace("}"); + const string liblabel("\"library\": "); + const string quote("\""); // Create the first part of the configuration string. string config = - "{ \"interfaces-config\": {" - " \"interfaces\": [ \"*\" ]" - "}," - "\"hooks-libraries\": ["; + "{ \"interfaces-config\": { \"interfaces\": [] }," + "\"hooks-libraries\": ["; // Append the libraries (separated by commas if needed) for (unsigned int i = 0; i < libraries.size(); ++i) { if (i > 0) { config += string(", "); } - config += (string("{ \"library\": \"") + libraries[i] + string("\" }")); + config += (lbrace + liblabel + quote + libraries[i] + quote + rbrace); } // Append the remainder of the configuration. @@ -4282,6 +4426,7 @@ TEST_F(Dhcp4ParserTest, InvalidLibrary) { ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); + ConstElementPtr status; ASSERT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); @@ -4402,7 +4547,11 @@ TEST_F(Dhcp4ParserTest, IncompatibleLibrary3Specified) { TEST_F(Dhcp4ParserTest, selectedInterfaces) { IfaceMgrTestConfig test_config(true); - ConstElementPtr x; + // Make sure the config manager is clean and there is no hanging + // interface configuration. + ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET)); + ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET)); + string config = "{ \"interfaces-config\": {" " \"interfaces\": [ \"eth0\", \"eth1\" ]" "}," @@ -4415,15 +4564,10 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) { extractConfig(config); ConstElementPtr status; - - // Make sure the config manager is clean and there is no hanging - // interface configuration. - EXPECT_FALSE(test_config.socketOpen("eth0", AF_INET)); - EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET)); - // Apply configuration. EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); ASSERT_TRUE(status); + // returned value must be 0 (configuration accepted) checkResult(status, 0); CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET, 10000); @@ -4438,7 +4582,10 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) { TEST_F(Dhcp4ParserTest, allInterfaces) { IfaceMgrTestConfig test_config(true); - ConstElementPtr x; + // Make sure there is no old configuration. + ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET)); + ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET)); + // This configuration specifies two interfaces on which server should listen // but it also includes asterisk. The asterisk switches server into the // mode when it listens on all interfaces regardless of what interface names @@ -4456,10 +4603,6 @@ TEST_F(Dhcp4ParserTest, allInterfaces) { ConstElementPtr status; - // Make sure there is no old configuration. - ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET)); - ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET)); - // Apply configuration. EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); ASSERT_TRUE(status); @@ -4512,129 +4655,11 @@ TEST_F(Dhcp4ParserTest, selectedInterfacesAndAddresses) { EXPECT_FALSE(test_config.socketOpen("eth1", "192.0.2.5")); } -// This test verifies that valid d2CliengConfig works correctly. -TEST_F(Dhcp4ParserTest, d2ClientConfigValid) { - ConstElementPtr status; - - // Verify that the D2 configuration can be fetched and is set to disabled. - D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig(); - EXPECT_FALSE(d2_client_config->getEnableUpdates()); - - // Verify that the convenience method agrees. - ASSERT_FALSE(CfgMgr::instance().ddnsEnabled()); - - string config_str = "{ " + genIfaceConfig() + "," + - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"subnet4\": [ { " - " \"id\": 1," - " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," - " \"subnet\": \"192.0.2.0/24\" } ]," - " \"dhcp-ddns\" : {" - " \"enable-updates\" : true, " - " \"server-ip\" : \"192.168.2.1\", " - " \"server-port\" : 777, " - " \"sender-ip\" : \"192.168.2.2\", " - " \"sender-port\" : 778, " - " \"max-queue-size\" : 2048, " - " \"ncr-protocol\" : \"UDP\", " - " \"ncr-format\" : \"JSON\"}, " - "\"valid-lifetime\": 4000 }"; - - // Convert the JSON string to configuration elements. - ConstElementPtr config; - ASSERT_NO_THROW(config = parseDHCP4(config_str, true)); - extractConfig(config_str); - - // Pass the configuration in for parsing. - EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); - - // check if returned status is OK - checkResult(status, 0); - - // Verify that DHCP-DDNS updating is enabled. - EXPECT_TRUE(CfgMgr::instance().ddnsEnabled()); - - // Verify that the D2 configuration can be retrieved. - d2_client_config = CfgMgr::instance().getD2ClientConfig(); - ASSERT_TRUE(d2_client_config); - - // Verify that the configuration values are correct. - EXPECT_TRUE(d2_client_config->getEnableUpdates()); - EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText()); - EXPECT_EQ(777, d2_client_config->getServerPort()); - EXPECT_EQ("192.168.2.2", d2_client_config->getSenderIp().toText()); - EXPECT_EQ(778, d2_client_config->getSenderPort()); - EXPECT_EQ(2048, d2_client_config->getMaxQueueSize()); - EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol()); - EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat()); - - // ddns-send-updates should be global default - checkGlobal("ddns-send-updates", true); - checkGlobal("ddns-conflict-resolution-mode", "check-with-dhcid"); - - // The following, deprecated dhcp-ddns parameters, - // should all have global default values. - checkGlobal("ddns-override-no-update", false); - checkGlobal("ddns-override-client-update", false); - checkGlobal("ddns-replace-client-name", "never"); - checkGlobal("ddns-generated-prefix", "myhost"); - checkGlobal("ddns-qualifying-suffix", ""); -} - -// This test checks the ability of the server to handle a configuration -// containing an invalid dhcp-ddns (D2ClientConfig) entry. -TEST_F(Dhcp4ParserTest, invalidD2ClientConfig) { - ConstElementPtr status; - - // Configuration string with an invalid D2 client config, - // "server-ip" is invalid. - string config_str = "{ " + genIfaceConfig() + "," + - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"ddns-override-no-update\" : true, " - "\"ddns-override-client-update\" : true, " - "\"ddns-replace-client-name\" : \"when-present\", " - "\"ddns-generated-prefix\" : \"test.prefix\", " - "\"ddns-qualifying-suffix\" : \"test.suffix.\", " - "\"subnet4\": [ { " - " \"id\": 1," - " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," - " \"subnet\": \"192.0.2.0/24\" } ]," - " \"dhcp-ddns\" : {" - " \"enable-updates\" : true, " - " \"server-ip\" : \"bogus-value\", " - " \"server-port\" : 5301, " - " \"ncr-protocol\" : \"UDP\", " - " \"ncr-format\" : \"JSON\"}," - "\"valid-lifetime\": 4000 }"; - - // Convert the JSON string to configuration elements. - ConstElementPtr config; - ASSERT_NO_THROW(config = parseDHCP4(config_str)); - - // Configuration should not throw, but should fail. - EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); - - // check if returned status is failed. - checkResult(status, 1); - EXPECT_TRUE(errorContainsPosition(status, "")); - - // Verify that the D2 configuration can be fetched and is set to disabled. - D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig(); - EXPECT_FALSE(d2_client_config->getEnableUpdates()); - - // Verify that the convenience method agrees. - ASSERT_FALSE(CfgMgr::instance().ddnsEnabled()); -} - // This test checks if it is possible to specify relay information TEST_F(Dhcp4ParserTest, subnetRelayInfo) { - ConstElementPtr status; - // A config with relay information. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -4653,6 +4678,7 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfo) { ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); + ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 0 (configuration success) @@ -4668,11 +4694,8 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfo) { // This test checks if it is possible to specify a list of relays TEST_F(Dhcp4ParserTest, subnetRelayInfoList) { - - ConstElementPtr status; - // A config with relay information. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -4691,6 +4714,7 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfoList) { ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); + ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 0 (configuration success) @@ -4712,7 +4736,7 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfoList) { // with defined client classes. TEST_F(Dhcp4ParserTest, classifySubnets) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -4808,7 +4832,7 @@ TEST_F(Dhcp4ParserTest, classifySubnets) { // with defined client classes. TEST_F(Dhcp4ParserTest, classifyPools) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -4846,59 +4870,172 @@ TEST_F(Dhcp4ParserTest, classifyPools) { const PoolCollection& pools = (*subnets->begin())->getPools(Lease::TYPE_V4); ASSERT_EQ(4, pools.size()); // We expect 4 pools - // Let's check if client belonging to alpha class is supported in pool[0] - // and not supported in any other pool (except pool[3], which allows - // everyone). - ClientClasses classes; - classes.insert("alpha"); - EXPECT_TRUE(pools.at(0)->clientSupported(classes)); - EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + // Let's check if client belonging to alpha class is supported in pool[0] + // and not supported in any other pool (except pool[3], which allows + // everyone). + ClientClasses classes; + classes.insert("alpha"); + EXPECT_TRUE(pools.at(0)->clientSupported(classes)); + EXPECT_FALSE(pools.at(1)->clientSupported(classes)); + EXPECT_FALSE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + + // Let's check if client belonging to beta class is supported in pool[1] + // and not supported in any other pool (except pool[3], which allows + // everyone). + classes.clear(); + classes.insert("beta"); + EXPECT_FALSE(pools.at(0)->clientSupported(classes)); + EXPECT_TRUE(pools.at(1)->clientSupported(classes)); + EXPECT_FALSE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + + // Let's check if client belonging to gamma class is supported in pool[2] + // and not supported in any other pool (except pool[3], which allows + // everyone). + classes.clear(); + classes.insert("gamma"); + EXPECT_FALSE(pools.at(0)->clientSupported(classes)); + EXPECT_FALSE(pools.at(1)->clientSupported(classes)); + EXPECT_TRUE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + + // Let's check if client belonging to some other class (not mentioned in + // the config) is supported only in pool[3], which allows everyone. + classes.clear(); + classes.insert("delta"); + EXPECT_FALSE(pools.at(0)->clientSupported(classes)); + EXPECT_FALSE(pools.at(1)->clientSupported(classes)); + EXPECT_FALSE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + + // Finally, let's check class-less client. He should be allowed only in + // the last pool, which does not have any class restrictions. + classes.clear(); + EXPECT_FALSE(pools.at(0)->clientSupported(classes)); + EXPECT_FALSE(pools.at(1)->clientSupported(classes)); + EXPECT_FALSE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); +} + +// This test verifies that valid d2CliengConfig works correctly. +TEST_F(Dhcp4ParserTest, d2ClientConfigValid) { + // Verify that the D2 configuration can be fetched and is set to disabled. + D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig(); + EXPECT_FALSE(d2_client_config->getEnableUpdates()); + + // Verify that the convenience method agrees. + ASSERT_FALSE(CfgMgr::instance().ddnsEnabled()); + + string config_str = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"subnet\": \"192.0.2.0/24\" } ]," + " \"dhcp-ddns\" : {" + " \"enable-updates\" : true, " + " \"server-ip\" : \"192.168.2.1\", " + " \"server-port\" : 777, " + " \"sender-ip\" : \"192.168.2.2\", " + " \"sender-port\" : 778, " + " \"max-queue-size\" : 2048, " + " \"ncr-protocol\" : \"UDP\", " + " \"ncr-format\" : \"JSON\"}, " + "\"valid-lifetime\": 4000 }"; + + // Convert the JSON string to configuration elements. + ConstElementPtr config; + ASSERT_NO_THROW(config = parseDHCP4(config_str, true)); + extractConfig(config_str); + + // Pass the configuration in for parsing. + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); + + // check if returned status is OK + checkResult(status, 0); + + // Verify that DHCP-DDNS updating is enabled. + EXPECT_TRUE(CfgMgr::instance().ddnsEnabled()); + + // Verify that the D2 configuration can be retrieved. + d2_client_config = CfgMgr::instance().getD2ClientConfig(); + ASSERT_TRUE(d2_client_config); + + // Verify that the configuration values are correct. + EXPECT_TRUE(d2_client_config->getEnableUpdates()); + EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText()); + EXPECT_EQ(777, d2_client_config->getServerPort()); + EXPECT_EQ("192.168.2.2", d2_client_config->getSenderIp().toText()); + EXPECT_EQ(778, d2_client_config->getSenderPort()); + EXPECT_EQ(2048, d2_client_config->getMaxQueueSize()); + EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol()); + EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat()); + + // ddns-send-updates should be global default + checkGlobal("ddns-send-updates", true); + checkGlobal("ddns-conflict-resolution-mode", "check-with-dhcid"); + + // The following, deprecated dhcp-ddns parameters, + // should all have global default values. + checkGlobal("ddns-override-no-update", false); + checkGlobal("ddns-override-client-update", false); + checkGlobal("ddns-replace-client-name", "never"); + checkGlobal("ddns-generated-prefix", "myhost"); + checkGlobal("ddns-qualifying-suffix", ""); +} + +// This test checks the ability of the server to handle a configuration +// containing an invalid dhcp-ddns (D2ClientConfig) entry. +TEST_F(Dhcp4ParserTest, invalidD2ClientConfig) { + // Configuration string with an invalid D2 client config, + // "server-ip" is invalid. + string config_str = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"ddns-override-no-update\" : true, " + "\"ddns-override-client-update\" : true, " + "\"ddns-replace-client-name\" : \"when-present\", " + "\"ddns-generated-prefix\" : \"test.prefix\", " + "\"ddns-qualifying-suffix\" : \"test.suffix.\", " + "\"subnet4\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"subnet\": \"192.0.2.0/24\" } ]," + " \"dhcp-ddns\" : {" + " \"enable-updates\" : true, " + " \"server-ip\" : \"bogus-value\", " + " \"server-port\" : 5301, " + " \"ncr-protocol\" : \"UDP\", " + " \"ncr-format\" : \"JSON\"}," + "\"valid-lifetime\": 4000 }"; + + // Convert the JSON string to configuration elements. + ConstElementPtr config; + ASSERT_NO_THROW(config = parseDHCP4(config_str)); - // Let's check if client belonging to beta class is supported in pool[1] - // and not supported in any other pool (except pools[3], which allows - // everyone). - classes.clear(); - classes.insert("beta"); - EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_TRUE(pools.at(1)->clientSupported(classes)); - EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + // Configuration should not throw, but should fail. + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, config)); - // Let's check if client belonging to gamma class is supported in pool[2] - // and not supported in any other pool (except pool[3], which allows - // everyone). - classes.clear(); - classes.insert("gamma"); - EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_TRUE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + // check if returned status is failed. + checkResult(status, 1); + EXPECT_TRUE(errorContainsPosition(status, "")); - // Let's check if client belonging to some other class (not mentioned in - // the config) is supported only in pool[3], which allows everyone. - classes.clear(); - classes.insert("delta"); - EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + // Verify that the D2 configuration can be fetched and is set to disabled. + D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig(); + EXPECT_FALSE(d2_client_config->getEnableUpdates()); - // Finally, let's check class-less client. He should be allowed only in - // the last pool, which does not have any class restrictions. - classes.clear(); - EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE(pools.at(3)->clientSupported(classes)); + // Verify that the convenience method agrees. + ASSERT_FALSE(CfgMgr::instance().ddnsEnabled()); } - // This test verifies that the host reservations can be specified for // respective IPv4 subnets. TEST_F(Dhcp4ParserTest, reservations) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -4977,7 +5114,8 @@ TEST_F(Dhcp4ParserTest, reservations) { " \"hostname\": \"\"" " }" " ]" - " } ]," + " } " + "], " "\"valid-lifetime\": 4000 }"; ConstElementPtr json; @@ -5057,6 +5195,7 @@ TEST_F(Dhcp4ParserTest, reservations) { circuit_id.size()); EXPECT_TRUE(host); EXPECT_EQ("192.0.4.102", host->getIPv4Reservation().toText()); + // This reservation must not belong to other subnets. EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_CIRCUIT_ID, &circuit_id[0], circuit_id.size())); @@ -5068,6 +5207,7 @@ TEST_F(Dhcp4ParserTest, reservations) { host = hosts_cfg->get4(542, Host::IDENT_DUID, &duid_r[0], duid_r.size()); ASSERT_TRUE(host); EXPECT_EQ("192.0.4.101", host->getIPv4Reservation().toText()); + EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_DUID, &duid_r[0], duid_r.size())); EXPECT_FALSE(hosts_cfg->get4(234, Host::IDENT_DUID, @@ -5102,7 +5242,7 @@ TEST_F(Dhcp4ParserTest, reservationWithOptionDefinition) { // The following configuration contains host declaration in which // a non-standard option is used. This option has option definition // specified in the configuration. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"option-def\": [ {" @@ -5129,9 +5269,9 @@ TEST_F(Dhcp4ParserTest, reservationWithOptionDefinition) { " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," " \"subnet\": \"192.0.3.0/24\", " " \"id\": 234" - " } ]," - "\"valid-lifetime\": 4000" - "}"; + " }" + "]," + "\"valid-lifetime\": 4000 }"; ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config, true)); @@ -5151,8 +5291,8 @@ TEST_F(Dhcp4ParserTest, reservationWithOptionDefinition) { duid.push_back(static_cast(i)); } // Retrieve the reservation and sanity check the address reserved. - ConstHostPtr host = - hosts_cfg->get4(234, Host::IDENT_DUID, &duid[0], duid.size()); + ConstHostPtr host = hosts_cfg->get4(234, Host::IDENT_DUID, + &duid[0], duid.size()); ASSERT_TRUE(host); EXPECT_EQ("192.0.3.112", host->getIPv4Reservation().toText()); @@ -5169,7 +5309,7 @@ TEST_F(Dhcp4ParserTest, reservationWithOptionDefinition) { TEST_F(Dhcp4ParserTest, reservationBogus) { // Case 1: misspelled hw-address parameter. ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -5184,7 +5324,8 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { " \"hostname\": \"\"" " }" " ]" - " } ]," + " } " + "], " "\"valid-lifetime\": 4000 }"; ConstElementPtr json; @@ -5198,7 +5339,7 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { EXPECT_THROW(parseDHCP4(config), Dhcp4ParseError); // Case 2: DUID and HW Address both specified. - config = "{ " + genIfaceConfig() + "," + + config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -5226,7 +5367,7 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { checkResult(x, 1); // Case 3: Broken specification of option data. - config = "{ " + genIfaceConfig() + "," + + config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -5245,7 +5386,8 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { " ]" " }" " ]" - " } ]," + " } " + "], " "\"valid-lifetime\": 4000 }"; ASSERT_NO_THROW(json = parseDHCP4(config)); @@ -5272,7 +5414,7 @@ TEST_F(Dhcp4ParserTest, hostReservationPerSubnet) { /// - 192.0.6.0/24 (global + all enabled) /// - 192.0.7.0/24 (global + out-of-pool enabled) const char* hr_config = - "{ " + "{" "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5331,14 +5473,16 @@ TEST_F(Dhcp4ParserTest, hostReservationPerSubnet) { ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(hr_config)); extractConfig(hr_config); - ConstElementPtr result; - EXPECT_NO_THROW(result = Dhcpv4SrvTest::configure(*srv_, json)); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 0 (success) - checkResult(result, 0); + checkResult(status, 0); + CfgMgr::instance().commit(); // Let's get all subnets and check that there are 7 of them. - ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); + ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4(); ASSERT_TRUE(subnets); const Subnet4Collection* subnet_col = subnets->getAll(); ASSERT_EQ(7, subnet_col->size()); // We expect 7 subnets @@ -5406,7 +5550,7 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { /// - 192.0.2.0/24 (all reservations enabled) /// - 192.0.3.0/24 (reservations not specified) const char* hr_config = - "{ " + "{" "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"reservations-global\": false," @@ -5430,14 +5574,16 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(hr_config)); extractConfig(hr_config); - ConstElementPtr result; - EXPECT_NO_THROW(result = Dhcpv4SrvTest::configure(*srv_, json)); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 0 (success) - checkResult(result, 0); + checkResult(status, 0); + CfgMgr::instance().commit(); // Let's get all subnets and check that there are 4 of them. - ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); + ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4(); ASSERT_TRUE(subnets); const Subnet4Collection* subnet_col = subnets->getAll(); ASSERT_EQ(2, subnet_col->size()); // We expect 2 subnets @@ -5450,7 +5596,7 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { ASSERT_TRUE(subnet); // Reset the fetch global function to staging (vs current) config. subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { - return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); }); EXPECT_FALSE(subnet->getReservationsGlobal()); EXPECT_TRUE(subnet->getReservationsInSubnet()); @@ -5461,7 +5607,7 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { ASSERT_TRUE(subnet); // Reset the fetch global function to staging (vs current) config. subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { - return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); }); EXPECT_FALSE(subnet->getReservationsGlobal()); EXPECT_TRUE(subnet->getReservationsInSubnet()); @@ -5471,16 +5617,16 @@ TEST_F(Dhcp4ParserTest, hostReservationGlobal) { /// Check that the decline-probation-period has a default value when not /// specified. TEST_F(Dhcp4ParserTest, declineTimerDefault) { - ConstElementPtr status; - string config = "{ " + genIfaceConfig() + "," + - "\"subnet4\": [ ]" + string config = "{ " + genIfaceConfig() + "," + "\"subnet4\": [ ] " "}"; 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) @@ -5517,9 +5663,7 @@ TEST_F(Dhcp4ParserTest, dhcp4o6portDefault) { /// Check that the decline-probation-period value can be set properly. TEST_F(Dhcp4ParserTest, declineTimer) { - ConstElementPtr status; - - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"decline-probation-period\": 12345," "\"subnet4\": [ ]" "}"; @@ -5528,6 +5672,7 @@ TEST_F(Dhcp4ParserTest, declineTimer) { ASSERT_NO_THROW(json = parseDHCP4(config)); extractConfig(config); + ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 0 (success) @@ -5541,9 +5686,7 @@ TEST_F(Dhcp4ParserTest, declineTimer) { /// Check that an incorrect decline-probation-period value will be caught. TEST_F(Dhcp4ParserTest, declineTimerError) { - ConstElementPtr status; - - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"decline-probation-period\": \"soon\"," "\"subnet4\": [ ]" "}"; @@ -5551,6 +5694,7 @@ TEST_F(Dhcp4ParserTest, declineTimerError) { ConstElementPtr json; ASSERT_NO_THROW(json = parseJSON(config)); + ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); // returned value should be 1 (error) @@ -5567,7 +5711,7 @@ TEST_F(Dhcp4ParserTest, declineTimerError) { // specified. TEST_F(Dhcp4ParserTest, expiredLeasesProcessing) { // Create basic configuration with the expiration specific parameters. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"expired-leases-processing\": " "{" " \"reclaim-timer-wait-time\": 20," @@ -5609,7 +5753,7 @@ TEST_F(Dhcp4ParserTest, expiredLeasesProcessing) { TEST_F(Dhcp4ParserTest, expiredLeasesProcessingError) { // Create basic configuration with the expiration specific parameters. // One of the parameters holds invalid value. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"expired-leases-processing\": " "{" " \"reclaim-timer-wait-time\": -5," @@ -5642,7 +5786,7 @@ TEST_F(Dhcp4ParserTest, 4o6default) { ConstElementPtr status; // Just a plain v4 config (no 4o6 parameters) - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5677,7 +5821,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnet) { ConstElementPtr status; // Just a plain v4 config (no 4o6 parameters) - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5717,7 +5861,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetBogus) { // Just a plain v4 config (no 4o6 parameters) string config[] = { // Bogus configuration 1: missing / in subnet - "{ " + genIfaceConfig() + "," + + "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5728,7 +5872,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetBogus) { "\"valid-lifetime\": 4000 }", // Bogus configuration 2: incorrect address - "{ " + genIfaceConfig() + "," + + "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5739,7 +5883,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetBogus) { "\"valid-lifetime\": 4000 }", // Bogus configuration 3: incorrect prefix length - "{ " + genIfaceConfig() + "," + + "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5777,7 +5921,7 @@ TEST_F(Dhcp4ParserTest, 4o6iface) { ConstElementPtr status; // Just a plain v4 config (no 4o6 parameters) - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5814,7 +5958,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetIface) { ConstElementPtr status; // Just a plain v4 config (no 4o6 parameters) - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5855,7 +5999,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) { ConstElementPtr status; // Just a plain v4 config (no 4o6 parameters) - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ { " @@ -5894,7 +6038,7 @@ TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) { // Verifies that simple list of valid classes parses and // is staged for commit. TEST_F(Dhcp4ParserTest, validClientClassDictionary) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000, \n" "\"rebind-timer\": 2000, \n" "\"renew-timer\": 1000, \n" @@ -5943,7 +6087,7 @@ TEST_F(Dhcp4ParserTest, validClientClassDictionary) { // Verifies that a class list containing an invalid // class definition causes a configuration error. TEST_F(Dhcp4ParserTest, invalidClientClassDictionary) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 4000, \n" "\"rebind-timer\": 2000, \n" "\"renew-timer\": 1000, \n" @@ -5966,7 +6110,7 @@ TEST_F(Dhcp4ParserTest, invalidClientClassDictionary) { // Verifies that simple list of valid classes parses and // is staged for commit. TEST_F(Dhcp4ParserTest, clientClassValidLifetime) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"client-classes\" : [ \n" " { \n" " \"name\": \"one\", \n" @@ -6022,7 +6166,7 @@ TEST_F(Dhcp4ParserTest, clientClassValidLifetime) { // Verifies that simple list of valid template classes parses and // is staged for commit. TEST_F(Dhcp4ParserTest, templateClientClassValidLifetime) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"client-classes\" : [ \n" " { \n" " \"name\": \"one\", \n" @@ -6140,7 +6284,7 @@ TEST_F(Dhcp4ParserTest, poolUserContextData) { // Test verifies that it's possible to specify parameters in the user context // in the min-max address pool. -TEST_F(Dhcp4ParserTest, pooMinMaxlUserContext) { +TEST_F(Dhcp4ParserTest, poolMinMaxUserContext) { extractConfig(PARSER_CONFIGS[3]); PoolPtr pool; getPool(string(PARSER_CONFIGS[3]), 0, 0, pool); @@ -6299,12 +6443,10 @@ TEST_F(Dhcp4ParserTest, sharedNetworksName) { } // Test verifies that a degenerated shared-network (just one subnet) is -// accepted. +// accepted. Also tests that, unless explicitly specified, the subnet +// gets default values. TEST_F(Dhcp4ParserTest, sharedNetworks1subnet) { string config = "{\n" - "\"valid-lifetime\": 4000, \n" - "\"rebind-timer\": 2000, \n" - "\"renew-timer\": 1000, \n" "\"shared-networks\": [ {\n" " \"name\": \"foo\"\n," " \"subnet4\": [ { \n" @@ -6331,11 +6473,11 @@ TEST_F(Dhcp4ParserTest, sharedNetworks1subnet) { ASSERT_TRUE(net); EXPECT_EQ("foo", net->getName()); - // It should have one subnet. + // It should have one subnet. The subnet should have default values. const Subnet4SimpleCollection* subs = net->getAllSubnets(); ASSERT_TRUE(subs); EXPECT_EQ(1, subs->size()); - checkSubnet(*subs, "192.0.2.0/24", 1000, 2000, 4000); + checkSubnet(*subs, "192.0.2.0/24", 0, 0, 7200); // Now make sure the subnet was added to global list of subnets. CfgSubnets4Ptr subnets4 = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); @@ -6343,7 +6485,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworks1subnet) { const Subnet4Collection* gsubs = subnets4->getAll(); ASSERT_TRUE(gsubs); - checkSubnet(*gsubs, "192.0.2.0/24", 1000, 2000, 4000); + checkSubnet(*gsubs, "192.0.2.0/24", 0, 0, 7200); } // Test verifies that a proper shared-network (three subnets) is @@ -6359,8 +6501,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworks3subnets) { "\"valid-lifetime\": 4000, \n" "\"min-valid-lifetime\": 3000, \n" "\"max-valid-lifetime\": 5000, \n" - "\"rebind-timer\": 2000, \n" "\"renew-timer\": 1000, \n" + "\"rebind-timer\": 2000, \n" "\"shared-networks\": [ {\n" " \"name\": \"foo\"\n," " \"subnet4\": [\n" @@ -6517,6 +6659,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ASSERT_TRUE(nets); ASSERT_EQ(2, nets->size()); + // Let's check the first one. SharedNetwork4Ptr net = nets->at(0); ASSERT_TRUE(net); @@ -6588,6 +6731,130 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { EXPECT_FALSE(s->getReservationsOutOfPool()); } +// Since it is not allowed to define both interface-id and interface +// for the same subnet, we need dedicated test that will check +// interface separately. +TEST_F(Dhcp4ParserTest, sharedNetworksDeriveInterfaces) { + + // We need to fake the interfaces present, because we want to test + // interface names inheritance. However, there are sanity checks + // on subnet level that would refuse the value if the interface + // is not present. + IfaceMgrTestConfig iface_config(true); + + string config = "{\n" + "\"shared-networks\": [ {\n" + " \"name\": \"foo\"\n," + " \"interface\": \"eth0\",\n" + " \"rebind-timer\": 10, \n" + " \"subnet4\": [\n" + " { \n" + " \"id\": 1, \n" + " \"subnet\": \"192.0.1.0/24\",\n" + " \"pools\": [ { \"pool\": \"192.0.1.1-192.0.1.10\" } ]\n" + " },\n" + " { \n" + " \"id\": 2, \n" + " \"subnet\": \"192.0.2.0/24\",\n" + " \"rebind-timer\": 100, \n" + " \"pools\": [ { \"pool\": \"192.0.2.1-192.0.2.10\" } ],\n" + " \"interface\": \"eth0\"\n" + " }\n" + " ]\n" + " },\n" + "{ // second shared-network starts here\n" + " \"name\": \"bar\",\n" + " \"subnet4\": [\n" + " {\n" + " \"id\": 3, \n" + " \"subnet\": \"192.0.3.0/24\",\n" + " \"pools\": [ { \"pool\": \"192.0.3.1-192.0.3.10\" } ]\n" + " }\n" + " ]\n" + "} ]\n" + "} \n"; + + configure(config, CONTROL_RESULT_SUCCESS, ""); + + // Now verify that the shared network was indeed configured. + CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg() + ->getCfgSharedNetworks4(); + + // Two shared networks are expected. + ASSERT_TRUE(cfg_net); + const SharedNetwork4Collection* nets = cfg_net->getAll(); + ASSERT_TRUE(nets); + ASSERT_EQ(2, nets->size()); + + // Let's check the first one. + SharedNetwork4Ptr net = nets->at(0); + ASSERT_TRUE(net); + + const Subnet4SimpleCollection* subs = net->getAllSubnets(); + ASSERT_TRUE(subs); + EXPECT_EQ(2, subs->size()); + + // For the first subnet, the rebind-timer should be 10, because it was + // derived from shared-network level. Other parameters a derived + // from global scope to shared-network level and later again to + // subnet4 level. + Subnet4Ptr s = checkSubnet(*subs, "192.0.1.0/24", 0, 10, 7200); + ASSERT_TRUE(s); + EXPECT_EQ("eth0", s->getIface().get()); + + // For the second subnet, the rebind-timer should be 100, because it + // was specified explicitly. Other parameters a derived + // from global scope to shared-network level and later again to + // subnet4 level. + checkSubnet(*subs, "192.0.2.0/24", 0, 100, 7200); + EXPECT_EQ("eth0", s->getIface().get()); + + // Ok, now check the second shared subnet. + net = nets->at(1); + ASSERT_TRUE(net); + + subs = net->getAllSubnets(); + ASSERT_TRUE(subs); + EXPECT_EQ(1, subs->size()); + + // This subnet should derive its rebind-timer from global scope. + s = checkSubnet(*subs, "192.0.3.0/24", 0, 0, 7200); + EXPECT_EQ("", s->getIface().get()); +} + +// It is not allowed to have different values for interfaces names is subnets +// in the same shared network. +TEST_F(Dhcp4ParserTest, sharedNetworksInterfacesMixed) { + + // We need to fake the interfaces present, because we want to test + // interface names inheritance. However, there are sanity checks + // on subnet level that would refuse the value if the interface + // is not present. + IfaceMgrTestConfig iface_config(true); + + string config = "{\n" + "\"shared-networks\": [ {\n" + " \"name\": \"foo\"\n," + " \"subnet4\": [\n" + " { \n" + " \"id\": 1, \n" + " \"subnet\": \"192.0.1.0/24\",\n" + " \"interface\": \"eth0\"\n" + " },\n" + " { \n" + " \"id\": 2, \n" + " \"subnet\": \"192.0.2.0/24\",\n" + " \"interface\": \"eth1\"\n" + " }\n" + " ]\n" + " } ]\n" + "} \n"; + + configure(config, CONTROL_RESULT_ERROR, "Subnet 192.0.2.0/24 has specified " + "interface eth1, but earlier subnet in the same shared-network " + "or the shared-network itself used eth0"); +} + // This test checks if client-class is derived properly. TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) { @@ -6624,7 +6891,6 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) { " \"pools\": [ { \"pool\": \"192.0.3.1-192.0.3.10\" } ]\n" " }\n" " ]\n" - " } ]\n" "} \n"; @@ -6640,6 +6906,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) { ASSERT_TRUE(nets); ASSERT_EQ(2, nets->size()); + // Let's check the first one. SharedNetwork4Ptr net = nets->at(0); ASSERT_TRUE(net); @@ -6659,11 +6926,12 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) { // For the second subnet, the values are overridden on subnet level. // The value should not be inherited. s = checkSubnet(*subs, "192.0.2.0/24", 1, 2, 4); + ASSERT_TRUE(s); EXPECT_EQ("beta", s->getClientClass().get()); // beta defined on subnet level - // Ok, now check the second shared network. It doesn't have anything defined - // on shared-network or subnet level, so everything should have default - // values. + // Ok, now check the second shared network. It doesn't have + // anything defined on shared-network or subnet level, so + // everything should have default values. net = nets->at(1); ASSERT_TRUE(net); @@ -6671,6 +6939,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) { ASSERT_TRUE(subs); EXPECT_EQ(1, subs->size()); + // This subnet should derive its renew-timer from global scope. s = checkSubnet(*subs, "192.0.3.0/24", 1, 2, 4); EXPECT_TRUE(s->getClientClass().empty()); } @@ -6690,13 +6959,13 @@ TEST_F(Dhcp4ParserTest, hostsDatabases) { ASSERT_EQ(2, hal.size()); // Keywords are in alphabetical order EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal.front()); - EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal.back()); + EXPECT_EQ("name=keatest2 password=keatest retry-on-startup=true type=mysql user=keatest", hal.back()); } // This test checks comments. Please keep it last. TEST_F(Dhcp4ParserTest, comments) { - string config = PARSER_CONFIGS[5]; + string config = PARSER_CONFIGS[6]; extractConfig(config); configure(config, CONTROL_RESULT_SUCCESS, ""); @@ -6896,22 +7165,12 @@ TEST_F(Dhcp4ParserTest, comments) { ASSERT_EQ(1, ctx_d2->size()); ASSERT_TRUE(ctx_d2->get("comment")); EXPECT_EQ("\"No dynamic DNS\"", ctx_d2->get("comment")->str()); - -#if 0 - // Loggers section supports comments too. - - string logging = "{\n" - "\"loggers\": [ {\n" - " \"comment\": \"A logger\",\n" - " \"name\": \"kea-dhcp4\"\n" - "} ]\n"; -#endif } -// This test verifies that the global host reservations can be specified +// This test verifies that the global host reservations can be specified. TEST_F(Dhcp4ParserTest, globalReservations) { ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, \n" "\"renew-timer\": 1000,\n" "\"reservations\": [\n" @@ -6956,9 +7215,9 @@ TEST_F(Dhcp4ParserTest, globalReservations) { " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ],\n" " \"subnet\": \"192.0.4.0/24\",\n" " \"id\": 542\n" - " } ],\n" - "\"valid-lifetime\": 4000" - "}\n"; + " }\n" + "],\n" + "\"valid-lifetime\": 4000 }\n"; ConstElementPtr json; ASSERT_NO_THROW(json = parseDHCP4(config)); @@ -6991,7 +7250,14 @@ TEST_F(Dhcp4ParserTest, globalReservations) { ASSERT_TRUE(host); EXPECT_EQ("global2", host->getHostname()); - // Check that options are stored correctly. + // This reservation should be solely assigned to the subnet 234, + // and not to other two. + EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_HWADDR, + &hwaddr[0], hwaddr.size())); + + EXPECT_FALSE(hosts_cfg->get4(542, Host::IDENT_HWADDR, + &hwaddr[0], hwaddr.size())); + // Check that options are assigned correctly. Option4AddrLstPtr opt_dns = retrieveOption(*host, DHO_NAME_SERVERS); ASSERT_TRUE(opt_dns); @@ -7003,14 +7269,6 @@ TEST_F(Dhcp4ParserTest, globalReservations) { ASSERT_TRUE(opt_ttl); EXPECT_EQ(11, static_cast(opt_ttl->getValue())); - // This reservation should be global solely and not assigned to - // either subnet - EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_HWADDR, - &hwaddr[0], hwaddr.size())); - - EXPECT_FALSE(hosts_cfg->get4(542, Host::IDENT_HWADDR, - &hwaddr[0], hwaddr.size())); - // Do the same test for the DUID based reservation. std::vector duid; for (unsigned int i = 1; i < 0xb; ++i) { @@ -7042,7 +7300,7 @@ TEST_F(Dhcp4ParserTest, globalReservations) { // reporting as disabled and thereby drawing attention to them. // This test verifies that configuration control with unsupported type fails TEST_F(Dhcp4ParserTest, configControlInfoNoFactory) { - string config = PARSER_CONFIGS[6]; + string config = PARSER_CONFIGS[5]; // Unregister "mysql" and ignore the return value. static_cast(TestConfigBackendDHCPv4:: @@ -7058,7 +7316,7 @@ TEST_F(Dhcp4ParserTest, configControlInfoNoFactory) { // This test verifies that configuration control info gets populated. TEST_F(Dhcp4ParserTest, configControlInfo) { - string config = PARSER_CONFIGS[6]; + string config = PARSER_CONFIGS[5]; // Should be able to register a backend factory for "mysql". ASSERT_TRUE(TestConfigBackendDHCPv4:: @@ -7082,7 +7340,7 @@ TEST_F(Dhcp4ParserTest, configControlInfo) { // alphabetical order). EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", dblist.front().getAccessString()); - EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", + EXPECT_EQ("name=keatest2 password=keatest retry-on-startup=true type=mysql user=keatest", dblist.back().getAccessString()); // Verify that the config-fetch-wait-time is correct. @@ -7093,18 +7351,18 @@ TEST_F(Dhcp4ParserTest, configControlInfo) { // Check whether it is possible to configure server-tag TEST_F(Dhcp4ParserTest, serverTag) { // Config without server-tag - string config_no_tag = "{ " + genIfaceConfig() + "," + + string config_no_tag = "{ " + genIfaceConfig() + "," "\"subnet4\": [ ] " "}"; // Config with server-tag - string config_tag = "{ " + genIfaceConfig() + "," + + string config_tag = "{ " + genIfaceConfig() + "," "\"server-tag\": \"boo\", " "\"subnet4\": [ ] " "}"; // Config with an invalid server-tag - string bad_tag = "{ " + genIfaceConfig() + "," + + string bad_tag = "{ " + genIfaceConfig() + "," "\"server-tag\": 777, " "\"subnet4\": [ ] " "}"; @@ -7346,7 +7604,7 @@ TEST_F(Dhcp4ParserTest, calculateTeeTimesInheritence) { " { \n" " \"id\": 200, \n" " \"subnet\": \"192.0.2.0/24\", \n" - " \"pools\": [ { \"pool\": \"192.0.2.1-192.0.2.10\"} ] \n" + " \"pools\": [ { \"pool\": \"192.0.2.1-192.0.2.10\" } ] \n" " } \n" " ] \n" " } ], \n" @@ -7372,7 +7630,7 @@ TEST_F(Dhcp4ParserTest, calculateTeeTimesInheritence) { // Subnet 200 should use the shared-network values. subnet4 = subnets4->getBySubnetId(200); ASSERT_TRUE(subnet4); - EXPECT_EQ(true, subnet4->getCalculateTeeTimes()); + EXPECT_TRUE(subnet4->getCalculateTeeTimes()); EXPECT_TRUE(util::areDoublesEquivalent(0.4, subnet4->getT1Percent())); EXPECT_TRUE(util::areDoublesEquivalent(0.75, subnet4->getT2Percent())); @@ -7387,7 +7645,7 @@ TEST_F(Dhcp4ParserTest, calculateTeeTimesInheritence) { // This test checks that the global store-extended-info parameter is optional // and that values under the subnet are used. TEST_F(Dhcp4ParserTest, storeExtendedInfoNoGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + const string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " @@ -7413,29 +7671,31 @@ TEST_F(Dhcp4ParserTest, storeExtendedInfoNoGlobal) { ASSERT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(status, 0); + // First subnet should use global default. CfgSubnets4Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); - Subnet4Ptr subnet1 = cfg->selectSubnet(IOAddress("192.0.2.1")); - ASSERT_TRUE(subnet1); + Subnet4Ptr subnet = cfg->selectSubnet(IOAddress("192.0.2.1")); + ASSERT_TRUE(subnet); // Reset the fetch global function to staging (vs current) config. - subnet1->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); }); - EXPECT_TRUE(subnet1->getStoreExtendedInfo()); + EXPECT_TRUE(subnet->getStoreExtendedInfo()); - Subnet4Ptr subnet2 = cfg->selectSubnet(IOAddress("192.0.3.1")); - ASSERT_TRUE(subnet2); + // Second subnet should use its own value. + subnet = cfg->selectSubnet(IOAddress("192.0.3.1")); + ASSERT_TRUE(subnet); // Reset the fetch global function to staging (vs current) config. - subnet2->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); }); - EXPECT_FALSE(subnet2->getStoreExtendedInfo()); + EXPECT_FALSE(subnet->getStoreExtendedInfo()); } // This test checks that the global store-extended-info parameter is used // when there is no such parameter under subnet and that the parameter // specified for a subnet overrides the global setting. TEST_F(Dhcp4ParserTest, storeExtendedInfoGlobal) { - std::string config = "{ " + genIfaceConfig() + "," + + const string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"store-extended-info\": true," @@ -7461,6 +7721,7 @@ TEST_F(Dhcp4ParserTest, storeExtendedInfoGlobal) { ASSERT_NO_THROW(status = Dhcpv4SrvTest::configure(*srv_, json)); checkResult(status, 0); + // First subnet should override the global value. CfgSubnets4Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets4(); Subnet4Ptr subnet1 = cfg->selectSubnet(IOAddress("192.0.2.1")); ASSERT_TRUE(subnet1); @@ -7470,6 +7731,7 @@ TEST_F(Dhcp4ParserTest, storeExtendedInfoGlobal) { }); EXPECT_FALSE(subnet1->getStoreExtendedInfo()); + // Second subnet should use the global value. Subnet4Ptr subnet2 = cfg->selectSubnet(IOAddress("192.0.3.1")); ASSERT_TRUE(subnet2); // Reset the fetch global function to staging (vs current) config. @@ -7482,7 +7744,7 @@ TEST_F(Dhcp4ParserTest, storeExtendedInfoGlobal) { /// This test checks that the statistic-default-sample-count and age /// global parameters are committed to the stats manager as expected. TEST_F(Dhcp4ParserTest, statsDefaultLimits) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"statistic-default-sample-count\": 10, " @@ -7507,7 +7769,7 @@ TEST_F(Dhcp4ParserTest, statsDefaultLimits) { // This test checks that using default multi threading settings works. TEST_F(Dhcp4ParserTest, multiThreadingDefaultSettings) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"subnet4\": [ ]" "}"; @@ -7544,7 +7806,7 @@ TEST_F(Dhcp4ParserTest, multiThreadingSettings) { " \"thread-pool-size\": 48,\n" " \"packet-queue-size\": 1024\n" "}"; - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"subnet4\": [ ], " "\"multi-threading\": " + content_json + "}"; @@ -7571,18 +7833,18 @@ TEST_F(Dhcp4ParserTest, multiThreadingSettings) { // is correct. TEST_F(Dhcp4ParserTest, parkedPacketLimit) { // Config without parked-packet-limit - string config_no_limit = "{ " + genIfaceConfig() + "," + + string config_no_limit = "{ " + genIfaceConfig() + "," "\"subnet4\": [ ] " "}"; // Config with parked-packet-limit - string config_limit = "{ " + genIfaceConfig() + "," + + string config_limit = "{ " + genIfaceConfig() + "," "\"parked-packet-limit\": 777, " "\"subnet4\": [ ] " "}"; // Config with an invalid parked-packet-limit - string bad_limit = "{ " + genIfaceConfig() + "," + + string bad_limit = "{ " + genIfaceConfig() + "," "\"parked-packet-limit\": \"boo\", " "\"subnet4\": [ ] " "}"; @@ -7612,7 +7874,7 @@ TEST_F(Dhcp4ParserTest, parkedPacketLimit) { // This test checks that ddns-conflict-resolution-mode value can be specified at // global and subnet levels. TEST_F(Dhcp4ParserTest, storeDdnsConflictResolutionMode) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet4\": [ " diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc b/src/bin/dhcp4/tests/get_config_unittest.cc index 5e3149b9c5..36ff160cb8 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc +++ b/src/bin/dhcp4/tests/get_config_unittest.cc @@ -9,25 +9,24 @@ #include #include #include -#include -#include #include -#include -#include -#include #include +#include #include #include #include +#include #include - -#include -#include +#include #include -#include -#include #include +#include +#include + +#include + +#include using namespace isc::config; using namespace isc::data; @@ -76,17 +75,6 @@ const char* EXTRACTED_CONFIGS[] = { " \"re-detect\": false\n" " },\n" " \"rebind-timer\": 2000,\n" -" \"renew-timer\": 1000,\n" -" \"subnet4\": [ ],\n" -" \"valid-lifetime\": 4000\n" -" }\n", - // CONFIGURATION 1 -"{\n" -" \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" -" \"re-detect\": false\n" -" },\n" -" \"rebind-timer\": 2000,\n" " \"subnet4\": [\n" " {\n" " \"id\": 1,\n" @@ -100,7 +88,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 2 + // CONFIGURATION 1 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -119,6 +107,17 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ],\n" " \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 2 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [ ],\n" +" \"valid-lifetime\": 4000\n" " }\n", // CONFIGURATION 3 "{\n" @@ -193,6 +192,54 @@ const char* EXTRACTED_CONFIGS[] = { " }\n", // CONFIGURATION 5 "{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.2.0/24\"\n" +" },\n" +" {\n" +" \"id\": 2,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.3.101 - 192.0.3.150\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.3.0/24\"\n" +" },\n" +" {\n" +" \"id\": 3,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.4.101 - 192.0.4.150\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.4.0/24\"\n" +" },\n" +" {\n" +" \"id\": 4,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.5.101 - 192.0.5.150\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.5.0/24\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 6 +"{\n" " \"boot-file-name\": \"bar\",\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -215,7 +262,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 6 + // CONFIGURATION 7 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -239,7 +286,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 7 + // CONFIGURATION 8 "{\n" " \"boot-file-name\": \"nofile\",\n" " \"interfaces-config\": {\n" @@ -266,7 +313,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 8 + // CONFIGURATION 9 "{\n" " \"echo-client-id\": false,\n" " \"interfaces-config\": {\n" @@ -288,7 +335,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 9 + // CONFIGURATION 10 "{\n" " \"echo-client-id\": true,\n" " \"interfaces-config\": {\n" @@ -310,7 +357,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 10 + // CONFIGURATION 11 "{\n" " \"compatibility\": {\n" " \"exclude-first-last-24\": true,\n" @@ -337,7 +384,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 11 + // CONFIGURATION 12 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -369,7 +416,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 12 + // CONFIGURATION 13 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -401,7 +448,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 13 + // CONFIGURATION 14 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -433,7 +480,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 14 + // CONFIGURATION 15 "{\n" " \"authoritative\": true,\n" " \"interfaces-config\": {\n" @@ -465,7 +512,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 15 + // CONFIGURATION 16 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -493,7 +540,29 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 16 + // CONFIGURATION 17 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [\n" +" {\n" +" \"id\": 1,\n" +" \"interface\": \"eth0\",\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.2.0/24\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 18 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -529,7 +598,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 17 + // CONFIGURATION 19 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -550,7 +619,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 18 + // CONFIGURATION 20 "{\n" " \"option-def\": [\n" " {\n" @@ -561,7 +630,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 19 + // CONFIGURATION 21 "{\n" " \"option-def\": [\n" " {\n" @@ -573,7 +642,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 20 + // CONFIGURATION 22 "{\n" " \"option-def\": [\n" " {\n" @@ -590,7 +659,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 21 + // CONFIGURATION 23 "{\n" " \"option-def\": [\n" " {\n" @@ -602,7 +671,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 22 + // CONFIGURATION 24 "{\n" " \"option-def\": [\n" " {\n" @@ -614,7 +683,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 23 + // CONFIGURATION 25 "{\n" " \"option-def\": [\n" " {\n" @@ -625,7 +694,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 24 + // CONFIGURATION 26 "{\n" " \"option-def\": [\n" " {\n" @@ -636,7 +705,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 25 + // CONFIGURATION 27 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -669,7 +738,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 26 + // CONFIGURATION 28 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -702,7 +771,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 27 + // CONFIGURATION 29 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -743,7 +812,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 28 + // CONFIGURATION 30 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -779,7 +848,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 29 + // CONFIGURATION 31 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -837,7 +906,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 3000\n" " }\n", - // CONFIGURATION 30 + // CONFIGURATION 32 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -877,7 +946,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 33 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -921,7 +990,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 34 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -954,7 +1023,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 35 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -992,7 +1061,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 36 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1023,7 +1092,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 37 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1059,7 +1128,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 38 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1112,7 +1181,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 3000\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 39 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1149,7 +1218,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 40 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1186,7 +1255,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 39 + // CONFIGURATION 41 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\", \"eth1\" ],\n" @@ -1196,7 +1265,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 40 + // CONFIGURATION 42 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\", \"*\", \"eth1\" ],\n" @@ -1206,38 +1275,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 41 -"{\n" -" \"dhcp-ddns\": {\n" -" \"enable-updates\": true,\n" -" \"max-queue-size\": 2048,\n" -" \"ncr-format\": \"JSON\",\n" -" \"ncr-protocol\": \"UDP\",\n" -" \"sender-ip\": \"192.168.2.2\",\n" -" \"sender-port\": 778,\n" -" \"server-ip\": \"192.168.2.1\",\n" -" \"server-port\": 777\n" -" },\n" -" \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" -" \"re-detect\": false\n" -" },\n" -" \"rebind-timer\": 2000,\n" -" \"renew-timer\": 1000,\n" -" \"subnet4\": [\n" -" {\n" -" \"id\": 1,\n" -" \"pools\": [\n" -" {\n" -" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" -" }\n" -" ],\n" -" \"subnet\": \"192.0.2.0/24\"\n" -" }\n" -" ],\n" -" \"valid-lifetime\": 4000\n" -" }\n", - // CONFIGURATION 42 + // CONFIGURATION 43 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1264,7 +1302,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 44 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1291,7 +1329,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 44 + // CONFIGURATION 45 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1342,7 +1380,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 45 + // CONFIGURATION 46 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1375,7 +1413,38 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 47 +"{\n" +" \"dhcp-ddns\": {\n" +" \"enable-updates\": true,\n" +" \"max-queue-size\": 2048,\n" +" \"ncr-format\": \"JSON\",\n" +" \"ncr-protocol\": \"UDP\",\n" +" \"sender-ip\": \"192.168.2.2\",\n" +" \"sender-port\": 778,\n" +" \"server-ip\": \"192.168.2.1\",\n" +" \"server-port\": 777\n" +" },\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.2.0/24\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 48 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1474,7 +1543,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 49 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1516,7 +1585,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 50 "{\n" " \"rebind-timer\": 2000,\n" " \"renew-timer\": 1000,\n" @@ -1603,7 +1672,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 51 "{\n" " \"rebind-timer\": 2000,\n" " \"renew-timer\": 1000,\n" @@ -1635,7 +1704,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 52 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1643,7 +1712,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 53 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1651,7 +1720,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 54 "{\n" " \"decline-probation-period\": 12345,\n" " \"interfaces-config\": {\n" @@ -1660,7 +1729,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 55 "{\n" " \"expired-leases-processing\": {\n" " \"flush-reclaimed-timer-wait-time\": 35,\n" @@ -1676,7 +1745,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 56 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1697,7 +1766,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 55 + // CONFIGURATION 57 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1719,7 +1788,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 56 + // CONFIGURATION 58 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1741,7 +1810,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 57 + // CONFIGURATION 59 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1764,7 +1833,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 58 + // CONFIGURATION 60 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1786,7 +1855,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 59 + // CONFIGURATION 61 "{\n" " \"client-classes\": [\n" " {\n" @@ -1818,7 +1887,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 60 + // CONFIGURATION 62 "{\n" " \"client-classes\": [\n" " {\n" @@ -1847,7 +1916,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 61 + // CONFIGURATION 63 "{\n" " \"client-classes\": [\n" " {\n" @@ -1878,7 +1947,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 62 + // CONFIGURATION 64 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1899,7 +1968,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 63 + // CONFIGURATION 65 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1921,7 +1990,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 64 + // CONFIGURATION 66 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1947,7 +2016,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 65 + // CONFIGURATION 67 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1973,7 +2042,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 66 + // CONFIGURATION 68 "{\n" " \"hosts-databases\": [\n" " {\n" @@ -1985,6 +2054,7 @@ const char* EXTRACTED_CONFIGS[] = { " {\n" " \"name\": \"keatest2\",\n" " \"password\": \"keatest\",\n" +" \"retry-on-startup\": true,\n" " \"type\": \"mysql\",\n" " \"user\": \"keatest\"\n" " }\n" @@ -1997,7 +2067,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 67 + // CONFIGURATION 69 "{\n" " \"client-classes\": [\n" " {\n" @@ -2106,7 +2176,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"comment\": \"A DHCPv4 server\"\n" " }\n" " }\n", - // CONFIGURATION 68 + // CONFIGURATION 70 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2168,7 +2238,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 69 + // CONFIGURATION 71 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2218,7 +2288,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 70 + // CONFIGURATION 72 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2250,7 +2320,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 71 + // CONFIGURATION 73 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2282,7 +2352,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 72 + // CONFIGURATION 74 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2294,7 +2364,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"statistic-default-sample-count\": 10,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 73 + // CONFIGURATION 75 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2302,7 +2372,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 74 + // CONFIGURATION 76 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -2315,7 +2385,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 75 + // CONFIGURATION 77 "{\n" " \"ddns-conflict-resolution-mode\": \"no-check-with-dhcid\",\n" " \"interfaces-config\": {\n" @@ -2445,7 +2515,6 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"rebind-timer\": 2000,\n" -" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -2461,7 +2530,35 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet4\": [ ],\n" +" \"subnet4\": [\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.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" @@ -2529,7 +2626,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-data\": [ ],\n" " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" -" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -2562,10 +2659,10 @@ const char* UNPARSED_CONFIGS[] = { " \"pool\": \"192.0.2.1-192.0.2.100\"\n" " }\n" " ],\n" -" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" +" \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" " \"subnet\": \"192.0.2.0/24\",\n" @@ -2641,6 +2738,94 @@ const char* UNPARSED_CONFIGS[] = { " \"option-data\": [ ],\n" " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\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" +" \"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 3 +"{\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-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" +" \"max-valid-lifetime\": 5000,\n" +" \"min-valid-lifetime\": 3000,\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" +" \"rebind-timer\": 2000,\n" " \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" @@ -2665,8 +2850,8 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-valid-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 5000,\n" +" \"min-valid-lifetime\": 3000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" @@ -2674,6 +2859,7 @@ const char* UNPARSED_CONFIGS[] = { " \"pool\": \"192.0.2.1-192.0.2.100\"\n" " }\n" " ],\n" +" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" @@ -2690,7 +2876,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 3 + // CONFIGURATION 4 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -2744,8 +2930,6 @@ const char* UNPARSED_CONFIGS[] = { " \"type\": \"memfile\"\n" " },\n" " \"match-client-id\": true,\n" -" \"max-valid-lifetime\": 5000,\n" -" \"min-valid-lifetime\": 3000,\n" " \"multi-threading\": {\n" " \"enable-multi-threading\": true,\n" " \"packet-queue-size\": 64,\n" @@ -2780,8 +2964,92 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"max-valid-lifetime\": 5000,\n" -" \"min-valid-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.4.101-192.0.4.150\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.0.4.0/24\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.875,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 34,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.5.101-192.0.5.150\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.0.5.0/24\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.875,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 100,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.3.101-192.0.3.150\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.0.3.0/24\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.875,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 1024,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" @@ -2806,7 +3074,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 4 + // CONFIGURATION 5 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -2900,7 +3168,7 @@ const char* UNPARSED_CONFIGS[] = { " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"192.0.4.101-192.0.4.150\"\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" " }\n" " ],\n" " \"rebind-timer\": 2000,\n" @@ -2910,7 +3178,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.4.0/24\",\n" +" \"subnet\": \"192.0.2.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" @@ -2921,14 +3189,14 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" -" \"id\": 34,\n" +" \"id\": 2,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"192.0.5.101-192.0.5.150\"\n" +" \"pool\": \"192.0.3.101-192.0.3.150\"\n" " }\n" " ],\n" " \"rebind-timer\": 2000,\n" @@ -2938,7 +3206,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.5.0/24\",\n" +" \"subnet\": \"192.0.3.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" @@ -2949,14 +3217,14 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" -" \"id\": 100,\n" +" \"id\": 3,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"192.0.3.101-192.0.3.150\"\n" +" \"pool\": \"192.0.4.101-192.0.4.150\"\n" " }\n" " ],\n" " \"rebind-timer\": 2000,\n" @@ -2966,7 +3234,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.3.0/24\",\n" +" \"subnet\": \"192.0.4.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" @@ -2977,14 +3245,14 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" -" \"id\": 1024,\n" +" \"id\": 4,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" \"pool\": \"192.0.5.101-192.0.5.150\"\n" " }\n" " ],\n" " \"rebind-timer\": 2000,\n" @@ -2994,7 +3262,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.2.0/24\",\n" +" \"subnet\": \"192.0.5.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" @@ -3004,7 +3272,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 5 + // CONFIGURATION 6 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3118,7 +3386,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 6 + // CONFIGURATION 7 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3235,7 +3503,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 7 + // CONFIGURATION 8 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3352,7 +3620,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 8 + // CONFIGURATION 9 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3466,7 +3734,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 9 + // CONFIGURATION 10 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3580,7 +3848,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 10 + // CONFIGURATION 11 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3673,14 +3941,158 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" -" \"id\": 1,\n" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.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", + // CONFIGURATION 12 +"{\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-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" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\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" +" \"stash-agent-options\": false,\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\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" +" \"id\": 1,\n" +" \"match-client-id\": true,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.0.2.0/24\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.875,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 2,\n" +" \"match-client-id\": false,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" \"pool\": \"192.0.3.1-192.0.3.100\"\n" " }\n" " ],\n" " \"rebind-timer\": 2000,\n" @@ -3690,7 +4102,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.2.0/24\",\n" +" \"subnet\": \"192.0.3.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" @@ -3700,7 +4112,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 11 + // CONFIGURATION 13 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3788,7 +4200,7 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"match-client-id\": true,\n" +" \"match-client-id\": false,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" @@ -3817,7 +4229,6 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" " \"id\": 2,\n" -" \"match-client-id\": false,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" @@ -3844,7 +4255,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 12 + // CONFIGURATION 14 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -3930,9 +4341,9 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" +" \"authoritative\": true,\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"match-client-id\": false,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" @@ -3959,6 +4370,7 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" +" \"authoritative\": false,\n" " \"calculate-tee-times\": false,\n" " \"id\": 2,\n" " \"max-valid-lifetime\": 4000,\n" @@ -3987,10 +4399,10 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 13 + // CONFIGURATION 15 "{\n" " \"allocator\": \"iterative\",\n" -" \"authoritative\": false,\n" +" \"authoritative\": true,\n" " \"boot-file-name\": \"\",\n" " \"calculate-tee-times\": false,\n" " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" @@ -4073,7 +4485,7 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" -" \"authoritative\": true,\n" +" \"authoritative\": false,\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" " \"max-valid-lifetime\": 4000,\n" @@ -4102,7 +4514,6 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" -" \"authoritative\": false,\n" " \"calculate-tee-times\": false,\n" " \"id\": 2,\n" " \"max-valid-lifetime\": 4000,\n" @@ -4131,10 +4542,10 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 14 + // CONFIGURATION 16 "{\n" " \"allocator\": \"iterative\",\n" -" \"authoritative\": true,\n" +" \"authoritative\": false,\n" " \"boot-file-name\": \"\",\n" " \"calculate-tee-times\": false,\n" " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" @@ -4185,6 +4596,8 @@ const char* UNPARSED_CONFIGS[] = { " \"type\": \"memfile\"\n" " },\n" " \"match-client-id\": true,\n" +" \"max-valid-lifetime\": 5000,\n" +" \"min-valid-lifetime\": 3000,\n" " \"multi-threading\": {\n" " \"enable-multi-threading\": true,\n" " \"packet-queue-size\": 64,\n" @@ -4217,11 +4630,10 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" " \"allocator\": \"iterative\",\n" -" \"authoritative\": false,\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-valid-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 5,\n" +" \"min-valid-lifetime\": 3,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" @@ -4229,52 +4641,24 @@ const char* UNPARSED_CONFIGS[] = { " \"pool\": \"192.0.2.1-192.0.2.100\"\n" " }\n" " ],\n" -" \"rebind-timer\": 2000,\n" +" \"rebind-timer\": 2,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" -" \"renew-timer\": 1000,\n" +" \"renew-timer\": 1,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" " \"subnet\": \"192.0.2.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" -" \"valid-lifetime\": 4000\n" -" },\n" -" {\n" -" \"4o6-interface\": \"\",\n" -" \"4o6-interface-id\": \"\",\n" -" \"4o6-subnet\": \"\",\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": false,\n" -" \"id\": 2,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"192.0.3.1-192.0.3.100\"\n" -" }\n" -" ],\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.3.0/24\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.875,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 4\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 15 + // CONFIGURATION 17 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4328,8 +4712,6 @@ const char* UNPARSED_CONFIGS[] = { " \"type\": \"memfile\"\n" " },\n" " \"match-client-id\": true,\n" -" \"max-valid-lifetime\": 5000,\n" -" \"min-valid-lifetime\": 3000,\n" " \"multi-threading\": {\n" " \"enable-multi-threading\": true,\n" " \"packet-queue-size\": 64,\n" @@ -4364,8 +4746,9 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": false,\n" " \"id\": 1,\n" -" \"max-valid-lifetime\": 5,\n" -" \"min-valid-lifetime\": 3,\n" +" \"interface\": \"eth0\",\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pools\": [\n" " {\n" @@ -4373,24 +4756,24 @@ const char* UNPARSED_CONFIGS[] = { " \"pool\": \"192.0.2.1-192.0.2.100\"\n" " }\n" " ],\n" -" \"rebind-timer\": 2,\n" +" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" -" \"renew-timer\": 1,\n" +" \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" " \"subnet\": \"192.0.2.0/24\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" -" \"valid-lifetime\": 4\n" +" \"valid-lifetime\": 4000\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 16 + // CONFIGURATION 18 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4540,7 +4923,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 17 + // CONFIGURATION 19 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4654,7 +5037,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 18 + // CONFIGURATION 20 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4747,7 +5130,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 19 + // CONFIGURATION 21 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4840,7 +5223,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 20 + // CONFIGURATION 22 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -4942,7 +5325,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 21 + // CONFIGURATION 23 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5035,7 +5418,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 22 + // CONFIGURATION 24 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5128,7 +5511,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 23 + // CONFIGURATION 25 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5221,7 +5604,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 24 + // CONFIGURATION 26 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5314,7 +5697,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 25 + // CONFIGURATION 27 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5447,7 +5830,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 26 + // CONFIGURATION 28 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5580,7 +5963,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 27 + // CONFIGURATION 29 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5723,7 +6106,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 28 + // CONFIGURATION 30 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -5846,7 +6229,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 29 + // CONFIGURATION 31 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6016,7 +6399,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 3000\n" " }\n", - // CONFIGURATION 30 + // CONFIGURATION 32 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6159,7 +6542,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 33 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6321,7 +6704,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 34 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6454,7 +6837,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 35 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6592,7 +6975,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 36 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6725,7 +7108,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 37 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -6848,7 +7231,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 38 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7009,7 +7392,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 3000\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 39 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7140,7 +7523,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 40 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7245,121 +7628,36 @@ const char* UNPARSED_CONFIGS[] = { " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": false,\n" -" \"id\": 1,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"192.0.2.1-192.0.2.100\"\n" -" }\n" -" ],\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"192.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", - // CONFIGURATION 39 -"{\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-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\": [ \"eth0\", \"eth1\" ],\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" -" \"rebind-timer\": 2000,\n" -" \"renew-timer\": 1000,\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" -" \"stash-agent-options\": false,\n" -" \"statistic-default-sample-age\": 0,\n" -" \"statistic-default-sample-count\": 20,\n" -" \"store-extended-info\": false,\n" -" \"subnet4\": [ ],\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.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", - // CONFIGURATION 40 + // CONFIGURATION 41 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7405,7 +7703,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\", \"eth0\", \"eth1\" ],\n" +" \"interfaces\": [ \"eth0\", \"eth1\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -7444,7 +7742,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 41 + // CONFIGURATION 42 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7460,14 +7758,14 @@ const char* UNPARSED_CONFIGS[] = { " \"ddns-update-on-renew\": false,\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" -" \"enable-updates\": true,\n" -" \"max-queue-size\": 2048,\n" +" \"enable-updates\": false,\n" +" \"max-queue-size\": 1024,\n" " \"ncr-format\": \"JSON\",\n" " \"ncr-protocol\": \"UDP\",\n" -" \"sender-ip\": \"192.168.2.2\",\n" -" \"sender-port\": 778,\n" -" \"server-ip\": \"192.168.2.1\",\n" -" \"server-port\": 777\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" @@ -7490,7 +7788,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" +" \"interfaces\": [ \"*\", \"eth0\", \"eth1\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -7524,41 +7822,12 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\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" -" \"id\": 1,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"192.0.2.1-192.0.2.100\"\n" -" }\n" -" ],\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"192.0.2.0/24\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.875,\n" -" \"valid-lifetime\": 4000\n" -" }\n" -" ],\n" +" \"subnet4\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 42 + // CONFIGURATION 43 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7672,7 +7941,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 44 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7786,7 +8055,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 44 + // CONFIGURATION 45 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -7987,7 +8256,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 45 + // CONFIGURATION 46 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -8116,7 +8385,121 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 47 +"{\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-update-on-renew\": false,\n" +" \"decline-probation-period\": 86400,\n" +" \"dhcp-ddns\": {\n" +" \"enable-updates\": true,\n" +" \"max-queue-size\": 2048,\n" +" \"ncr-format\": \"JSON\",\n" +" \"ncr-protocol\": \"UDP\",\n" +" \"sender-ip\": \"192.168.2.2\",\n" +" \"sender-port\": 778,\n" +" \"server-ip\": \"192.168.2.1\",\n" +" \"server-port\": 777\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" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\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" +" \"stash-agent-options\": false,\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\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" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"192.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", + // CONFIGURATION 48 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -8395,7 +8778,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 49 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -8540,7 +8923,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 50 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -8838,7 +9221,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 51 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -8983,7 +9366,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 52 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9066,7 +9449,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 53 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9149,7 +9532,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 54 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9232,7 +9615,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 55 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9315,7 +9698,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 56 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9429,7 +9812,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 55 + // CONFIGURATION 57 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9543,7 +9926,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 56 + // CONFIGURATION 58 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9657,7 +10040,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 57 + // CONFIGURATION 59 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9771,7 +10154,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 58 + // CONFIGURATION 60 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -9885,7 +10268,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 59 + // CONFIGURATION 61 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10025,7 +10408,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 60 + // CONFIGURATION 62 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10156,7 +10539,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 61 + // CONFIGURATION 63 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10289,7 +10672,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 62 + // CONFIGURATION 64 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10403,7 +10786,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 63 + // CONFIGURATION 65 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10518,7 +10901,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 64 + // CONFIGURATION 66 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10637,7 +11020,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 65 + // CONFIGURATION 67 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10756,7 +11139,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 66 + // CONFIGURATION 68 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -10811,6 +11194,7 @@ const char* UNPARSED_CONFIGS[] = { " {\n" " \"name\": \"keatest2\",\n" " \"password\": \"keatest\",\n" +" \"retry-on-startup\": true,\n" " \"type\": \"mysql\",\n" " \"user\": \"keatest\"\n" " }\n" @@ -10855,7 +11239,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 67 + // CONFIGURATION 69 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11093,7 +11477,7 @@ const char* UNPARSED_CONFIGS[] = { " },\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 68 + // CONFIGURATION 70 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11294,7 +11678,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 69 + // CONFIGURATION 71 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11474,7 +11858,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 70 + // CONFIGURATION 72 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11616,7 +12000,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 71 + // CONFIGURATION 73 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11758,7 +12142,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 72 + // CONFIGURATION 74 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11843,7 +12227,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 73 + // CONFIGURATION 75 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -11926,7 +12310,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 74 + // CONFIGURATION 76 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" @@ -12009,7 +12393,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.875,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 75 + // CONFIGURATION 77 "{\n" " \"allocator\": \"iterative\",\n" " \"authoritative\": false,\n" diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc.skel b/src/bin/dhcp4/tests/get_config_unittest.cc.skel index 8be9f77c0e..6ef5349dcd 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc.skel +++ b/src/bin/dhcp4/tests/get_config_unittest.cc.skel @@ -9,25 +9,24 @@ #include #include #include -#include -#include #include -#include -#include -#include #include +#include #include #include #include +#include #include - -#include -#include +#include #include -#include -#include #include +#include +#include + +#include + +#include using namespace isc::config; using namespace isc::data; diff --git a/src/bin/dhcp4/tests/kea_controller_unittest.cc b/src/bin/dhcp4/tests/kea_controller_unittest.cc index c636be1238..e47c3ae14b 100644 --- a/src/bin/dhcp4/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp4/tests/kea_controller_unittest.cc @@ -176,7 +176,7 @@ typedef boost::shared_ptr TestCBControlDHCPv4Ptr; /// /// Exposes internal fields and installs stub implementation of the /// @c CBControlDHCPv4 object. -class NakedControlledDhcpv4Srv: public ControlledDhcpv4Srv { +class NakedControlledDhcpv4Srv : public ControlledDhcpv4Srv { public: /// @brief Constructor. @@ -188,7 +188,7 @@ public: } }; -/// @brief test class for Kea configuration backend +/// @brief test class for Kea configuration backend. /// /// This class is used for testing Kea configuration backend. /// It is very simple and currently focuses on reading @@ -301,7 +301,6 @@ public: EXPECT_EQ(0, cb_control->getDatabaseCurrentConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseStagingConfigFetchCalls()); - if (call_command) { // The case where there is no backend is tested in the // controlled server tests so we have only to verify @@ -1079,7 +1078,6 @@ testBackendReconfiguration(const std::string& backend_first, LeaseMgrFactory::instance().getType()); } - // This test verifies that backend specification can be added on // server reconfiguration. TEST_F(JSONFileBackendMySQLTest, reconfigureBackendUndefinedToMySQL) { diff --git a/src/bin/dhcp6/parser_context.cc b/src/bin/dhcp6/parser_context.cc index ebf7bef835..312c29991a 100644 --- a/src/bin/dhcp6/parser_context.cc +++ b/src/bin/dhcp6/parser_context.cc @@ -55,15 +55,14 @@ Parser6Context::parseCommon() { isc_throw(Dhcp6ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(Dhcp6ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(Dhcp6ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index eeda548db4..cff24255d2 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -6,22 +6,24 @@ #include +#include #include +#include #include +#include #include +#include #include -#include #include #include -#include #include -#include -#include #include -#include -#include +#include +#include #include #include +#include +#include #include #include #include @@ -34,25 +36,24 @@ #include #include #include - -#include "test_data_files_config.h" -#include "test_libraries.h" -#include "marker_file.h" -#include "dhcp6_test_utils.h" -#include "get_config_unittest.h" - -#include +#include #include -#include + #include #include #include #include #include +#include #include +#include "dhcp6_test_utils.h" +#include "get_config_unittest.h" +#include "marker_file.h" +#include "test_libraries.h" + using namespace isc; using namespace isc::asiolink; using namespace isc::config; @@ -66,7 +67,7 @@ using namespace std; namespace { const char* PARSER_CONFIGS[] = { - // CONFIGURATION 0: one subnet with one pool, no user contexts + // Configuration 0: one subnet with one pool, no user contexts "{" " \"interfaces-config\": {" " \"interfaces\": [\"*\" ]" @@ -242,12 +243,13 @@ const char* PARSER_CONFIGS[] = { " \"type\": \"mysql\"," " \"name\": \"keatest2\"," " \"user\": \"keatest\"," + " \"retry-on-startup\": true," " \"password\": \"keatest\"" " }" " ]" "}", - // Configuration 8: config control + // Configuration 8: config database "{ \n" " \"interfaces-config\": { \n" " \"interfaces\": [\"*\" ] \n" @@ -266,6 +268,7 @@ const char* PARSER_CONFIGS[] = { " \"type\": \"mysql\", \n" " \"name\": \"keatest2\", \n" " \"user\": \"keatest\", \n" + " \"retry-on-startup\": true, \n" " \"password\": \"keatest\" \n" " } \n" " ] \n" @@ -293,7 +296,7 @@ const char* PARSER_CONFIGS[] = { " \"comment\": \"Set option value\"," " \"name\": \"subscriber-id\"," " \"data\": \"ABCDEF0105\"," - " \"csv-format\": false" + " \"csv-format\": false" " } ]," " \"client-classes\": [" " {" @@ -373,8 +376,8 @@ protected: } public: - Dhcp6ParserTest() :rcode_(-1), srv_(0) { - // srv_(0) means to not open any sockets. We don't want to + Dhcp6ParserTest() : rcode_(-1), srv_(0) { + // Open port 0 means to not open any sockets. We don't want to // deal with sockets here, just check if configuration handling // is sane. @@ -394,7 +397,6 @@ public: << " while the test assumes that it doesn't, to execute" << " some negative scenarios. Can't continue this test."; } - // Reset configuration for each test. resetConfiguration(); } @@ -408,16 +410,13 @@ public: static_cast(remove(UNLOAD_MARKER_FILE)); }; - // Checks if config_result (result of DHCP server configuration) has + // Checks if the result of DHCP server configuration has // expected code (0 for success, other for failures). // Also stores result in rcode_ and comment_. void checkResult(ConstElementPtr status, int expected_code) { ASSERT_TRUE(status); comment_ = parseAnswerText(rcode_, status); - EXPECT_EQ(expected_code, rcode_); - if (expected_code != rcode_) { - cout << "The comment returned was: [" << comment_->stringValue() << "]" << endl; - } + EXPECT_EQ(expected_code, rcode_) << "error text:" << comment_->stringValue(); } // Checks if the result of DHCP server configuration has @@ -443,7 +442,7 @@ public: void configure(std::string config, int expected_code, std::string exp_error = "") { ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config, true)); + ASSERT_NO_THROW_LOG(json = parseDHCP6(config, true)); ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); @@ -468,51 +467,6 @@ public: } } - /// @brief Checks if specified subnet is part of the collection - /// - /// @tparam CollectionType type of subnet6 collections i.e. - /// either Subnet6SimpleCollection or Subnet6Collection - /// @param col collection of subnets to be inspected - /// @param subnet text notation (e.g. 192.0.2.0/24) - /// @param t1 expected renew-timer value - /// @param t2 expected rebind-timer value - /// @param preferred expected preferred-lifetime value - /// @param valid expected valid-lifetime value - /// @param min_preferred expected min-preferred-lifetime value - /// (0 (default) means same as preferred) - /// @param max_preferred expected max-preferred-lifetime value - /// (0 (default) means same as preferred) - /// @param min_valid expected min-valid-lifetime value - /// (0 (default) means same as valid) - /// @param max_valid expected max-valid-lifetime value - /// (0 (default) means same as valid) - /// @return the subnet that was examined - template - Subnet6Ptr - checkSubnet(const CollectionType& col, std::string subnet, - uint32_t t1, uint32_t t2, uint32_t pref, uint32_t valid, - uint32_t min_pref = 0, uint32_t max_pref = 0, - uint32_t min_valid = 0, uint32_t max_valid = 0) { - auto const& index = col.template get(); - auto subnet_it = index.find(subnet); - if (subnet_it == index.cend()) { - ADD_FAILURE() << "Unable to find expected subnet " << subnet; - return (Subnet6Ptr()); - } - Subnet6Ptr s = *subnet_it; - - EXPECT_EQ(t1, s->getT1().get()); - EXPECT_EQ(t2, s->getT2().get()); - EXPECT_EQ(pref, s->getPreferred().get()); - EXPECT_EQ(valid, s->getValid().get()); - EXPECT_EQ(min_pref ? min_pref : pref, s->getPreferred().getMin()); - EXPECT_EQ(max_pref ? max_pref : pref, s->getPreferred().getMax()); - EXPECT_EQ(min_valid ? min_valid : valid, s->getValid().getMin()); - EXPECT_EQ(max_valid ? max_valid : valid, s->getValid().getMax()); - - return (s); - } - /// @brief Returns an interface configuration used by the most of the /// unit tests. std::string genIfaceConfig() const { @@ -531,6 +485,8 @@ public: /// injected into the configuration string. /// @param parameter name of the parameter to be configured with /// param value. + /// @return configuration string containing custom values of parameters + /// describing an option. std::string createConfigWithOption(const std::string& param_value, const std::string& parameter) { std::map params; @@ -577,10 +533,9 @@ public: /// @return configuration string containing custom values of parameters /// describing an option. std::string createConfigWithOption(const std::map& params) - { + std::string>& params) { std::ostringstream stream; - stream << "{ " << genIfaceConfig() << "," + stream << "{ " << genIfaceConfig() << "," << "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -591,7 +546,7 @@ public: " \"space\": \"dhcp6\"" "} ]," "\"subnet6\": [ { " - " \"id\": 1, " + " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," " \"subnet\": \"2001:db8:1::/64\", " " \"option-data\": [ {"; @@ -608,7 +563,7 @@ public: } else if (param.first == "space") { stream << "\"space\": \"" << param.second << "\""; } else if (param.first == "code") { - stream << "\"code\": " << param.second;; + stream << "\"code\": " << param.second; } else if (param.first == "data") { stream << "\"data\": \"" << param.second << "\""; } else if (param.first == "csv-format") { @@ -641,8 +596,8 @@ public: getOptionFromSubnet(const IOAddress& subnet_address, const uint16_t option_code, const uint16_t expected_options_count = 1) { - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(subnet_address, classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(subnet_address, classify_); if (!subnet) { ADD_FAILURE() << "A subnet for the specified address " << subnet_address @@ -679,126 +634,6 @@ public: return (*range.first); } - /// @brief Parse and Execute configuration - /// - /// Parses a configuration and executes a configuration of the server. - /// If the operation fails, the current test will register a failure. - /// - /// @param config Configuration to parse - /// @param operation Operation being performed. In the case of an error, - /// the error text will include the string "unable to .". - /// - /// @return true if the configuration succeeded, false if not. In the - /// latter case, a failure will have been added to the current test. - bool - executeConfiguration(const std::string& config, const char* operation) { - ConstElementPtr json; - ConstElementPtr status; - try { - json = parseJSON(config); - status = Dhcpv6SrvTest::configure(srv_, json); - - } catch (const std::exception& ex) { - ADD_FAILURE() << "Unable to " << operation << ". " - << "The following configuration was used: " << std::endl - << config << std::endl - << " and the following error message was returned:" - << ex.what() << std::endl; - return (false); - } - - // The status object must not be NULL - if (!status) { - ADD_FAILURE() << "Unable to " << operation << ". " - << "The configuration function returned a null pointer."; - return (false); - } - - // Store the answer if we need it. - - // Returned value should be 0 (configuration success) - comment_ = parseAnswerText(rcode_, status); - if (rcode_ != 0) { - string reason = ""; - if (comment_) { - reason = string(" (") + comment_->stringValue() + string(")"); - } - ADD_FAILURE() << "Unable to " << operation << ". " - << "The configuration function returned error code " - << rcode_ << reason; - return (false); - } - - return (true); - } - - /// @brief Reset configuration database. - /// - /// This function resets configuration data base by removing all subnets - /// option-data, and hooks libraries. The reset must be performed after each - /// test to make sure that contents of the database do not affect the - /// results of subsequent tests. - void resetConfiguration() { - // The default setting is to listen on all interfaces. In order to - // properly test interface configuration we disable listening on - // all interfaces before each test and later check that this setting - // has been overridden by the configuration used in the test. - CfgMgr::instance().clear(); - string config = "{ \"interfaces-config\": {" - " \"interfaces\": [ ]" - "}," - "\"hooks-libraries\": [ ]," - "\"preferred-lifetime\": 3000," - "\"rebind-timer\": 2000, " - "\"renew-timer\": 1000, " - "\"valid-lifetime\": 4000, " - "\"subnet6\": [ ], " - "\"dhcp-ddns\": { \"enable-updates\" : false }, " - "\"option-def\": [ ], " - "\"option-data\": [ ] }"; - static_cast(executeConfiguration(config, - "reset configuration database")); - CfgMgr::instance().clearStagingConfiguration(); - } - - /// @brief Retrieve an option associated with a host. - /// - /// The option is retrieved from the "dhcp6" option space. - /// - /// @param host Reference to a host for which an option should be retrieved. - /// @param option_code Option code. - /// @tparam ReturnType Type of the pointer object returned. - /// - /// @return Pointer to an option or NULL pointer if not found. - template - ReturnType - retrieveOption(const Host& host, const uint16_t option_code) const { - return (retrieveOption(host, DHCP6_OPTION_SPACE, option_code)); - } - - /// @brief Retrieve an option associated with a host. - /// - /// @param host Reference to a host for which an option should be retrieved. - /// @param space Option space from which option should be retrieved. - /// @param option_code Option code. - /// @tparam ReturnType Type of the pointer object returned. - /// - /// @return Pointer to an option or NULL pointer if not found. - template - ReturnType - retrieveOption(const Host& host, const std::string& space, - const uint16_t option_code) const { - ConstCfgOptionPtr cfg_option = host.getCfgOption6(); - if (cfg_option) { - OptionDescriptor opt_desc = cfg_option->get(space, option_code); - if (opt_desc.option_) { - return (boost::dynamic_pointer_cast< - typename ReturnType::element_type>(opt_desc.option_)); - } - } - return (ReturnType()); - } - /// @brief Test invalid option parameter value. /// /// This test function constructs the simple configuration @@ -909,7 +744,7 @@ public: std::string config = createConfigWithOption(params); ASSERT_TRUE(executeConfiguration(config, "parse option configuration")); - // The subnet should now hold one option with the specified code. + // The subnet should now hold one option with the specified option code. OptionDescriptor desc = getOptionFromSubnet(IOAddress("2001:db8:1::5"), option_code); ASSERT_TRUE(desc.option_); @@ -951,36 +786,200 @@ public: // Clear any existing configuration. CfgMgr::instance().clear(); } - - /// @brief This utility method attempts to configure using specified - /// config and then returns requested pool from requested subnet + /// @brief Parse and Execute configuration /// - /// @param config configuration to be applied - /// @param subnet_index index of the subnet to be returned (0 - the first subnet) - /// @param pool_index index of the pool within a subnet (0 - the first pool) - /// @param type Pool type (TYPE_NA or TYPE_PD) - /// @param pool [out] Pool pointer will be stored here (if found) - void getPool(const std::string& config, size_t subnet_index, - size_t pool_index, Lease::Type type, PoolPtr& pool) { - ConstElementPtr status; + /// Parses a configuration and executes a configuration of the server. + /// If the operation fails, the current test will register a failure. + /// + /// @param config Configuration to parse + /// @param operation Operation being performed. In the case of an error, + /// the error text will include the string "unable to .". + /// + /// @return true if the configuration succeeded, false if not. In the + /// latter case, a failure will have been added to the current test. + bool + executeConfiguration(const std::string& config, const char* operation) { + CfgMgr::instance().clear(); ConstElementPtr json; + ConstElementPtr status; + try { + json = parseJSON(config); + status = Dhcpv6SrvTest::configure(srv_, json); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Unable to " << operation << ". " + << "The following configuration was used: " << std::endl + << config << std::endl + << " and the following error message was returned:" + << ex.what() << std::endl; + return (false); + } - EXPECT_NO_THROW(json = parseDHCP6(config, true)); - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - ASSERT_TRUE(status); - checkResult(status, 0); - - ConstCfgSubnets6Ptr subnets6 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); - ASSERT_TRUE(subnets6); + // The status object must not be NULL + if (!status) { + ADD_FAILURE() << "Unable to " << operation << ". " + << "The configuration function returned a null pointer."; + return (false); + } - const Subnet6Collection* subnets = subnets6->getAll(); - ASSERT_TRUE(subnets); - ASSERT_GE(subnets->size(), subnet_index + 1); + // Store the answer if we need it. - auto subnet = subnets->begin(); - // std::advance is not available for subnets iterators. - for (size_t i = 0; i < subnet_index; ++i) { - subnet = std::next(subnet); + // Returned value should be 0 (configuration success) + comment_ = parseAnswerText(rcode_, status); + if (rcode_ != 0) { + string reason = ""; + if (comment_) { + reason = string(" (") + comment_->stringValue() + string(")"); + } + ADD_FAILURE() << "Unable to " << operation << ". " + << "The configuration function returned error code " + << rcode_ << reason; + return (false); + } + + return (true); + } + + /// @brief Reset configuration database. + /// + /// This function resets configuration data base by removing all subnets + /// option-data, and hooks libraries. The reset must be performed after each + /// test to make sure that contents of the database do not affect the + /// results of subsequent tests. + void resetConfiguration() { + // The default setting is to listen on all interfaces. In order to + // properly test interface configuration we disable listening on + // all interfaces before each test and later check that this setting + // has been overridden by the configuration used in the test. + CfgMgr::instance().clear(); + string config = "{ \"interfaces-config\": {" + " \"interfaces\": [ ]" + "}," + "\"hooks-libraries\": [ ]," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"valid-lifetime\": 4000, " + "\"subnet6\": [ ], " + "\"dhcp-ddns\": { \"enable-updates\" : false }, " + "\"option-def\": [ ], " + "\"option-data\": [ ] }"; + static_cast(executeConfiguration(config, + "reset configuration database")); + CfgMgr::instance().clearStagingConfiguration(); + } + + /// @brief Retrieve an option associated with a host. + /// + /// The option is retrieved from the "dhcp6" option space. + /// + /// @param host Reference to a host for which an option should be retrieved. + /// @param option_code Option code. + /// @tparam ReturnType Type of the pointer object returned. + /// + /// @return Pointer to an option or NULL pointer if not found. + template + ReturnType + retrieveOption(const Host& host, const uint16_t option_code) const { + return (retrieveOption(host, DHCP6_OPTION_SPACE, option_code)); + } + + /// @brief Retrieve an option associated with a host. + /// + /// @param host Reference to a host for which an option should be retrieved. + /// @param space Option space from which option should be retrieved. + /// @param option_code Option code. + /// @tparam ReturnType Type of the pointer object returned. + /// + /// @return Pointer to an option or NULL pointer if not found. + template + ReturnType + retrieveOption(const Host& host, const std::string& space, + const uint16_t option_code) const { + ConstCfgOptionPtr cfg_option = host.getCfgOption6(); + if (cfg_option) { + OptionDescriptor opt_desc = cfg_option->get(space, option_code); + if (opt_desc.option_) { + return (boost::dynamic_pointer_cast< + typename ReturnType::element_type>(opt_desc.option_)); + } + } + return (ReturnType()); + } + + /// @brief Checks if specified subnet is part of the collection + /// + /// @tparam CollectionType type of subnet6 collections i.e. + /// either Subnet6SimpleCollection or Subnet6Collection + /// @param col collection of subnets to be inspected + /// @param subnet text notation (e.g. 192.0.2.0/24) + /// @param t1 expected renew-timer value + /// @param t2 expected rebind-timer value + /// @param preferred expected preferred-lifetime value + /// @param valid expected valid-lifetime value + /// @param min_preferred expected min-preferred-lifetime value + /// (0 (default) means same as preferred) + /// @param max_preferred expected max-preferred-lifetime value + /// (0 (default) means same as preferred) + /// @param min_valid expected min-valid-lifetime value + /// (0 (default) means same as valid) + /// @param max_valid expected max-valid-lifetime value + /// (0 (default) means same as valid) + /// @return the subnet that was examined + template + Subnet6Ptr + checkSubnet(const CollectionType& col, std::string subnet, + uint32_t t1, uint32_t t2, uint32_t pref, uint32_t valid, + uint32_t min_pref = 0, uint32_t max_pref = 0, + uint32_t min_valid = 0, uint32_t max_valid = 0) { + auto const& index = col.template get(); + auto subnet_it = index.find(subnet); + if (subnet_it == index.cend()) { + ADD_FAILURE() << "Unable to find expected subnet " << subnet; + return (Subnet6Ptr()); + } + Subnet6Ptr s = *subnet_it; + + EXPECT_EQ(t1, s->getT1().get()); + EXPECT_EQ(t2, s->getT2().get()); + EXPECT_EQ(pref, s->getPreferred().get()); + EXPECT_EQ(valid, s->getValid().get()); + EXPECT_EQ(min_pref ? min_pref : pref, s->getPreferred().getMin()); + EXPECT_EQ(max_pref ? max_pref : pref, s->getPreferred().getMax()); + EXPECT_EQ(min_valid ? min_valid : valid, s->getValid().getMin()); + EXPECT_EQ(max_valid ? max_valid : valid, s->getValid().getMax()); + + return (s); + } + + /// @brief This utility method attempts to configure using specified + /// config and then returns requested pool from requested subnet + /// + /// @param config configuration to be applied + /// @param subnet_index index of the subnet to be returned (0 - the first subnet) + /// @param pool_index index of the pool within a subnet (0 - the first pool) + /// @param type Pool type (TYPE_NA or TYPE_PD) + /// @param pool [out] Pool pointer will be stored here (if found) + void getPool(const std::string& config, size_t subnet_index, + size_t pool_index, Lease::Type type, PoolPtr& pool) { + ConstElementPtr status; + ConstElementPtr json; + + EXPECT_NO_THROW(json = parseDHCP6(config, true)); + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + ConstCfgSubnets6Ptr subnets6 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); + ASSERT_TRUE(subnets6); + + const Subnet6Collection* subnets = subnets6->getAll(); + ASSERT_TRUE(subnets); + ASSERT_GE(subnets->size(), subnet_index + 1); + + auto subnet = subnets->begin(); + // std::advance is not available for subnets iterators. + for (size_t i = 0; i < subnet_index; ++i) { + subnet = std::next(subnet); } const PoolCollection pools = (*subnet)->getPools(type); ASSERT_GE(pools.size(), pool_index + 1); @@ -1005,7 +1004,7 @@ public: << isc::data::prettyPrint(exp_value); } - int rcode_; ///< Return code (see @ref isc::config::parseAnswer) + int rcode_; ///< Return code from element parsing ControlledDhcpv6Srv srv_; ///< Instance of the ControlledDhcp6Srv used during tests ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer) string valid_iface_; ///< Valid network interface name (present in system) @@ -1033,7 +1032,8 @@ TEST_F(Dhcp6ParserTest, bogusCommand) { TEST_F(Dhcp6ParserTest, emptyInterfaceConfig) { ConstElementPtr json; - EXPECT_NO_THROW(json = parseDHCP6("{ \"preferred-lifetime\": 3000," + EXPECT_NO_THROW(json = parseDHCP6("{ " + "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"valid-lifetime\": 4000 }")); @@ -1050,7 +1050,7 @@ TEST_F(Dhcp6ParserTest, emptyInterfaceConfig) { /// specified (boundary check is done when lifetimes are applied). TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1068,7 +1068,7 @@ TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1083,7 +1083,7 @@ TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1099,7 +1099,7 @@ TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1115,7 +1115,7 @@ TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1136,7 +1136,7 @@ TEST_F(Dhcp6ParserTest, outBoundValidLifetime) { /// parameters only. TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1000, \"min-valid-lifetime\": 2000 }"; ConstElementPtr json; @@ -1150,7 +1150,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 2000, \"max-valid-lifetime\": 1000 }"; ASSERT_NO_THROW(json = parseDHCP6(too_large)); @@ -1161,7 +1161,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1000, \"min-valid-lifetime\": 2000, " "\"max-valid-lifetime\": 4000 }"; @@ -1173,7 +1173,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 5000, \"min-valid-lifetime\": 1000, " "\"max-valid-lifetime\": 4000 }"; @@ -1185,7 +1185,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"valid-lifetime\": 1500, \"min-valid-lifetime\": 2000, " "\"max-valid-lifetime\": 1000 }"; @@ -1197,12 +1197,81 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalValidLifetime) { checkResult(status, 1, expected); } +/// Check that the renew-timer doesn't have to be specified, in which case +/// it is marked unspecified in the Subnet. +TEST_F(Dhcp6ParserTest, unspecifiedRenewTimer) { + + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," + " \"subnet\": \"2001:db8::/32\" } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + + // returned value should be 0 (success) + checkResult(status, 0); + + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8::1")); + ASSERT_TRUE(subnet); + + EXPECT_TRUE(subnet->getT1().unspecified()); + EXPECT_FALSE(subnet->getT2().unspecified()); + EXPECT_EQ(2000, subnet->getT2().get()); + EXPECT_EQ(4000, subnet->getValid().get()); + + // Check that subnet-id is 1 + EXPECT_EQ(1, subnet->getID()); +} + +/// Check that the rebind-timer doesn't have to be specified, in which case +/// it is marked unspecified in the Subnet. +TEST_F(Dhcp6ParserTest, unspecifiedRebindTimer) { + + string config = "{ " + genIfaceConfig() + "," + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," + " \"subnet\": \"2001:db8::/32\" } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + + // returned value should be 0 (success) + checkResult(status, 0); + + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8::1")); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getT1().unspecified()); + EXPECT_EQ(1000, subnet->getT1().get()); + EXPECT_TRUE(subnet->getT2().unspecified()); + EXPECT_EQ(4000, subnet->getValid().get()); + + // Check that subnet-id is 1 + EXPECT_EQ(1, subnet->getID()); +} + /// Check that preferred-lifetime must be between min-preferred-lifetime and /// max-preferred-lifetime when a bound is specified, *AND* a subnet is /// specified (boundary check is done when lifetimes are applied). TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1220,7 +1289,7 @@ TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1235,7 +1304,7 @@ TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1251,7 +1320,7 @@ TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1267,7 +1336,7 @@ TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8::/64\" } ]," @@ -1288,7 +1357,7 @@ TEST_F(Dhcp6ParserTest, outBoundPreferredLifetime) { /// parameters only. TEST_F(Dhcp6ParserTest, outBoundGlobalPreferredLifetime) { - string too_small = "{ " + genIfaceConfig() + "," + + string too_small = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 1000, \"min-preferred-lifetime\": 2000 }"; ConstElementPtr json; @@ -1302,7 +1371,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string too_large = "{ " + genIfaceConfig() + "," + + string too_large = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 2000, \"max-preferred-lifetime\": 1000 }"; ASSERT_NO_THROW(json = parseDHCP6(too_large)); @@ -1313,7 +1382,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string before = "{ " + genIfaceConfig() + "," + + string before = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 1000, \"min-preferred-lifetime\": 2000, " "\"max-preferred-lifetime\": 4000 }"; @@ -1325,7 +1394,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string after = "{ " + genIfaceConfig() + "," + + string after = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 5000, \"min-preferred-lifetime\": 1000, " "\"max-preferred-lifetime\": 4000 }"; @@ -1337,7 +1406,7 @@ TEST_F(Dhcp6ParserTest, outBoundGlobalPreferredLifetime) { checkResult(status, 1, expected); resetConfiguration(); - string crossed = "{ " + genIfaceConfig() + "," + + string crossed = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 1500, \"min-preferred-lifetime\": 2000, " "\"max-preferred-lifetime\": 1000 }"; @@ -1401,8 +1470,8 @@ TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) { // Now check if the configuration was indeed handled and we have // expected pool configured. - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); EXPECT_EQ(1000, subnet->getT1().get()); EXPECT_EQ(2000, subnet->getT2().get()); @@ -1464,7 +1533,7 @@ TEST_F(Dhcp6ParserTest, multipleSubnetsExplicitIDs) { ASSERT_TRUE(subnets); ASSERT_EQ(4, subnets->size()); // We expect 4 subnets - // Check that subnet ids are as expected. + // Verify that subnet ids are as expected. // Now the subnet order is the subnet id one. auto subnet = subnets->begin(); EXPECT_EQ(1, (*subnet)->getID()); @@ -1521,7 +1590,7 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) { ConstElementPtr x; // All four subnets - string config4 = "{ " + genIfaceConfig() + "," + string config6 = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -1595,8 +1664,8 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) { // last one. ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config4)); - extractConfig(config4); + ASSERT_NO_THROW(json = parseDHCP6(config6)); + extractConfig(config6); EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 0); @@ -1607,6 +1676,8 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) { ASSERT_TRUE(subnets); ASSERT_EQ(4, subnets->size()); // We expect 4 subnets + CfgMgr::instance().clear(); + // Do the reconfiguration (the last subnet is removed) ASSERT_NO_THROW(json = parseDHCP6(config_first3)); EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); @@ -1618,15 +1689,17 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) { ASSERT_TRUE(subnets); ASSERT_EQ(3, subnets->size()); // We expect 3 subnets now (4th is removed) + // Check subnet-ids of each subnet (it should be monotonously increasing) auto subnet = subnets->begin(); EXPECT_EQ(1, (*subnet)->getID()); EXPECT_EQ(2, (*++subnet)->getID()); EXPECT_EQ(3, (*++subnet)->getID()); + CfgMgr::instance().clear(); + /// CASE 2: Configure 4 subnets, then reconfigure and remove one /// from in between (not first, not last) - - ASSERT_NO_THROW(json = parseDHCP6(config4)); + ASSERT_NO_THROW(json = parseDHCP6(config6)); EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 0); @@ -1652,7 +1725,7 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) { // Check whether it is possible to configure compatibility flags. TEST_F(Dhcp6ParserTest, compatibility) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -1682,7 +1755,7 @@ TEST_F(Dhcp6ParserTest, compatibility) { // Check that unknown compatibility flag raises error. TEST_F(Dhcp6ParserTest, compatibilityUnknown) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -1710,7 +1783,7 @@ TEST_F(Dhcp6ParserTest, compatibilityUnknown) { // Check that not boolean compatibility flag value raises error. TEST_F(Dhcp6ParserTest, compatibilityNotBool) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -1772,8 +1845,8 @@ TEST_F(Dhcp6ParserTest, subnetLocal) { // returned value should be 0 (configuration success) checkResult(status, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); EXPECT_EQ(1, subnet->getT1().get()); EXPECT_EQ(2, subnet->getT2().get()); @@ -1961,7 +2034,8 @@ TEST_F(Dhcp6ParserTest, interfaceIdGlobal) { // interface (i.e. local subnet) and interface-id (remote subnet) defined. TEST_F(Dhcp6ParserTest, subnetInterfaceAndInterfaceId) { - const string config = "{ \"preferred-lifetime\": 3000," + const string config = "{" + "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet6\": [ { " @@ -1998,35 +2072,40 @@ TEST_F(Dhcp6ParserTest, badSubnetValues) { { "IP is not an address", "{ \"subnet6\": [ { " - " \"subnet\": \"not an address/64\" } ]}", + " \"subnet\": \"not an address/64\" } ]," + "\"valid-lifetime\": 4000 }", "subnet configuration failed: " "Failed to convert string to address 'notanaddress': Invalid argument" }, { "IP is Invalid", "{ \"subnet6\": [ { " - " \"subnet\": \"200175:db8::/64\" } ]}", + " \"subnet\": \"200175:db8::/64\" } ]," + "\"valid-lifetime\": 4000 }", "subnet configuration failed: " "Failed to convert string to address '200175:db8::': Invalid argument" }, { "Missing prefix", "{ \"subnet6\": [ { " - " \"subnet\": \"2001:db8::\" } ]}", + " \"subnet\": \"2001:db8::\" } ]," + "\"valid-lifetime\": 4000 }", "subnet configuration failed: " "Invalid subnet syntax (prefix/len expected):2001:db8:: (:1:30)" }, { "Prefix not an integer (2 slashes)", "{ \"subnet6\": [ { " - " \"subnet\": \"2001:db8:://64\" } ]}", + " \"subnet\": \"2001:db8:://64\" } ]," + "\"valid-lifetime\": 4000 }", "subnet configuration failed: " "prefix length: '/64' is not an integer (:1:30)" }, { "Prefix value is insane", "{ \"subnet6\": [ { " - " \"subnet\": \"2001:db8::/43225\" } ]}", + " \"subnet\": \"2001:db8::/43225\" } ]," + "\"valid-lifetime\": 4000 }", "subnet configuration failed: " "Invalid prefix length specified for subnet: 43225 (:1:30)" } @@ -2042,6 +2121,7 @@ TEST_F(Dhcp6ParserTest, badSubnetValues) { ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, config)); checkResult(status, 1); + ASSERT_TRUE(comment_); EXPECT_EQ(comment_->stringValue(), scenario.exp_error_msg_); } } @@ -2192,9 +2272,6 @@ TEST_F(Dhcp6ParserTest, poolOutOfSubnet) { // Note this test also verifies that subnets can be configured without // prefix delegation pools. TEST_F(Dhcp6ParserTest, poolPrefixLen) { - - ConstElementPtr x; - string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " @@ -2209,13 +2286,14 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) { ASSERT_NO_THROW(json = parseDHCP6(config)); extractConfig(config); - EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - // returned value must be 1 (configuration parse error) - checkResult(x, 0); + // returned value must be 0 (configuration accepted) + checkResult(status, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); EXPECT_EQ(1000, subnet->getT1().get()); EXPECT_EQ(2000, subnet->getT2().get()); @@ -2363,6 +2441,24 @@ TEST_F(Dhcp6ParserTest, badPools) { EXPECT_TRUE(errorContainsPosition(status, "")); } +// Goal of this test is to verify no pool definitions is invalid +// and returns a location in the error message. +TEST_F(Dhcp6ParserTest, noPools) { + + // Configuration string. + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"user-context\": { } } ]," + " \"subnet\": \"2001:db8:1::/64\" } ]," + "\"valid-lifetime\": 4000 }"; + + EXPECT_THROW(parseDHCP6(config, true), Dhcp6ParseError); +} + // Goal of this test is to verify the basic parsing of a prefix delegation // pool. It uses a single, valid pd pool. TEST_F(Dhcp6ParserTest, pdPoolBasics) { @@ -2712,12 +2808,36 @@ TEST_F(Dhcp6ParserTest, invalidPdPools) { } } -// The goal of this test is to check whether an option definition -// that defines an option carrying an IPv6 address can be created. -TEST_F(Dhcp6ParserTest, optionDefIpv6Address) { +// Goal of this test is to verify that unknown interface fails +// to be parsed. +TEST_F(Dhcp6ParserTest, unknownInterface) { // Configuration string. - std::string config = + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ ]," + " \"subnet\": \"2001:db8:1::/64\"," + " \"interface\": \"ethX\" } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config, true)); + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + checkResult(status, 1); + EXPECT_TRUE(errorContainsPosition(status, "")); +} + +// The goal of this test is to check whether an option definition +// that defines an option carrying an IPv6 address can be created. +TEST_F(Dhcp6ParserTest, optionDefIpv6Address) { + + // Configuration string. + std::string config = "{ \"option-def\": [ {" " \"name\": \"foo\"," " \"code\": 100," @@ -2754,6 +2874,7 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) { EXPECT_EQ(100, def->getCode()); EXPECT_FALSE(def->getArrayType()); EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, def->getType()); + EXPECT_TRUE(def->getEncapsulatedSpace().empty()); // The copy of the option definition should be available in the libdhcp++. OptionDefinitionPtr def_libdhcp = LibDHCP::getRuntimeOptionDef("isc", 100); @@ -2813,6 +2934,7 @@ TEST_F(Dhcp6ParserTest, optionDefRecord) { EXPECT_EQ(100, def->getCode()); EXPECT_EQ(OPT_RECORD_TYPE, def->getType()); EXPECT_FALSE(def->getArrayType()); + EXPECT_TRUE(def->getEncapsulatedSpace().empty()); // The option comprises the record of data fields. Verify that all // fields are present and they are of the expected types. @@ -2869,6 +2991,7 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) { EXPECT_EQ(100, def1->getCode()); EXPECT_EQ(OPT_UINT32_TYPE, def1->getType()); EXPECT_FALSE(def1->getArrayType()); + EXPECT_TRUE(def1->getEncapsulatedSpace().empty()); // Check the second option definition we have created. OptionDefinitionPtr def2 = CfgMgr::instance().getStagingCfg()-> @@ -2880,6 +3003,7 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) { EXPECT_EQ(101, def2->getCode()); EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def2->getType()); EXPECT_FALSE(def2->getArrayType()); + EXPECT_TRUE(def2->getEncapsulatedSpace().empty()); } // The goal of this test is to verify that the duplicated option @@ -2973,7 +3097,8 @@ TEST_F(Dhcp6ParserTest, optionDefArray) { checkResult(status, 0); // The option definition should now be available in the CfgMgr. - def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("isc", 100); + def = CfgMgr::instance().getStagingCfg()-> + getCfgOptionDef()->get("isc", 100); ASSERT_TRUE(def); // Check the option data. @@ -2981,6 +3106,7 @@ TEST_F(Dhcp6ParserTest, optionDefArray) { EXPECT_EQ(100, def->getCode()); EXPECT_EQ(OPT_UINT32_TYPE, def->getType()); EXPECT_TRUE(def->getArrayType()); + EXPECT_TRUE(def->getEncapsulatedSpace().empty()); } // The purpose of this test to verify that encapsulated option @@ -3014,7 +3140,8 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulate) { checkResult(status, 0); // The option definition should now be available in the CfgMgr. - def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("isc", 100); + def = CfgMgr::instance().getStagingCfg()-> + getCfgOptionDef()->get("isc", 100); ASSERT_TRUE(def); // Check the option data. @@ -3227,6 +3354,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) { "}"; ConstElementPtr json; ASSERT_NO_THROW(json = parseOPTION_DEFS(config)); + extractConfig(config); OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()-> getCfgOptionDef()->get(DHCP6_OPTION_SPACE, 100); @@ -3260,7 +3388,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) { " \"space\": \"dhcp6\"" " } ]" "}"; - json = parseOPTION_DEFS(config); + ASSERT_NO_THROW(json = parseOPTION_DEFS(config)); // Use the configuration string to create new option definition. EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); @@ -3282,7 +3410,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) { " \"space\": \"dhcp6\"" " } ]" "}"; - json = parseOPTION_DEFS(config); + ASSERT_NO_THROW(json = parseOPTION_DEFS(config)); + extractConfig(config); // Use the configuration string to create new option definition. EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); @@ -3332,8 +3461,8 @@ TEST_F(Dhcp6ParserTest, optionDataDefaultsGlobal) { checkResult(x, 0); // These options are global - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(0, options->size()); @@ -3410,8 +3539,8 @@ TEST_F(Dhcp6ParserTest, optionDataDefaultsSubnet) { CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(0, options->size()); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(2, options->size()); @@ -3579,7 +3708,7 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) { CfgMgr::instance().clear(); // Stage 2. Configure base option and a subnet. Please note that - // the configuration from the stage 2 is repeated because BIND + // the configuration from the stage 2 is repeated because Kea // configuration manager sends whole configuration for the lists // where at least one element is being modified or added. config = "{ " + genIfaceConfig() + "," @@ -3647,7 +3776,7 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) { EXPECT_EQ(100, desc.option_->getType()); // This option should comprise two sub-options. - // Onf of them is 'foo' with code 110. + // One of them is 'foo' with code 110. OptionPtr option_foo = desc.option_->getOption(110); ASSERT_TRUE(option_foo); EXPECT_EQ(110, option_foo->getType()); @@ -3658,6 +3787,159 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) { EXPECT_EQ(111, option_foo2->getType()); } +// Goal of this test is to verify options configuration +// for a single subnet. In particular this test checks +// that local options configuration overrides global +// option setting. +TEST_F(Dhcp6ParserTest, optionDataInSingleSubnet) { + ConstElementPtr x; + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-data\": [ {" + " \"name\": \"subscriber-id\"," + " \"data\": \"AB\"," + " \"csv-format\": false" + " } ]," + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," + " \"subnet\": \"2001:db8:1::/64\", " + " \"option-data\": [ {" + " \"name\": \"subscriber-id\"," + " \"data\": \"ABCDEF0105\"," + " \"csv-format\": false" + " }," + " {" + " \"name\": \"user-class\"," + " \"data\": \"FFFEFDFCFB\"," + " \"csv-format\": false" + " } ]" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); + checkResult(x, 0); + + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); + ASSERT_TRUE(subnet); + OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + ASSERT_EQ(2, options->size()); + + // Get the search index. Index #1 is to search using option code. + const OptionContainerTypeIndex& idx = options->get<1>(); + + // Get the options for specified index. Expecting one option to be + // returned but in theory we may have multiple options with the same + // code so we get the range. + std::pair range = + idx.equal_range(D6O_SUBSCRIBER_ID); + // Expect single option with the code equal to 100. + ASSERT_EQ(1, std::distance(range.first, range.second)); + const uint8_t subid_expected[] = { + 0xAB, 0xCD, 0xEF, 0x01, 0x05 + }; + // Check if option is valid in terms of code and carried data. + testOption(*range.first, D6O_SUBSCRIBER_ID, subid_expected, sizeof(subid_expected)); + + range = idx.equal_range(D6O_USER_CLASS); + ASSERT_EQ(1, std::distance(range.first, range.second)); + // Do another round of testing with second option. + const uint8_t user_class_expected[] = { + 0xFF, 0xFE, 0xFD, 0xFC, 0xFB + }; + testOption(*range.first, D6O_USER_CLASS, user_class_expected, + sizeof(user_class_expected)); +} + +// The goal of this test is to check that the option carrying a boolean +// value can be configured using one of the values: "true", "false", "0" +// or "1". +TEST_F(Dhcp6ParserTest, optionDataBoolean) { + // Create configuration. Use standard option 1000. + std::map params; + params["name"] = "bool-option"; + params["space"] = DHCP6_OPTION_SPACE; + params["code"] = "1000"; + params["data"] = "true"; + params["csv-format"] = "true"; + + std::string config = createConfigWithOption(params); + ASSERT_TRUE(executeConfiguration(config, "parse configuration with a" + " boolean value")); + + // The subnet should now hold one option with the code 1000. + OptionDescriptor desc = getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000); + ASSERT_TRUE(desc.option_); + + // This option should be set to "true", represented as 0x1 in the option + // buffer. + uint8_t expected_option_data[] = { + 0x1 + }; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // Configure the option with the "1" value. This should have the same + // effect as if "true" was specified. + params["data"] = "1"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // The value of "1" with a few leading zeros should work too. + params["data"] = "00001"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // Configure the option with the "false" value. + params["data"] = "false"; + // The option buffer should now hold the value of 0. + expected_option_data[0] = 0; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // Specifying "0" should have the same effect as "false". + params["data"] = "0"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // The same effect should be for multiple 0 chars. + params["data"] = "00000"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // Bogus values should not be accepted. + params["data"] = "bogus"; + testInvalidOptionParam(params); + + params["data"] = "2"; + testInvalidOptionParam(params); + + // Now let's test that it is possible to use binary format. + params["data"] = "0"; + params["csv-format"] = "false"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // The binary 1 should work as well. + params["data"] = "1"; + expected_option_data[0] = 1; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); + + // As well as an even number of digits. + params["data"] = "01"; + testConfiguration(params, 1000, expected_option_data, + sizeof(expected_option_data)); +} + // Goal of this test is to verify options configuration // for multiple subnets. TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) { @@ -3695,8 +3977,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) { EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 0); - Subnet6Ptr subnet1 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet1 = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet1); OptionContainerPtr options1 = subnet1->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(1, options1->size()); @@ -3721,8 +4003,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) { sizeof(subid_expected)); // Test another subnet in the same way. - Subnet6Ptr subnet2 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:2::4"), classify_); + Subnet6Ptr subnet2 = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:2::4"), classify_); ASSERT_TRUE(subnet2); OptionContainerPtr options2 = subnet2->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(1, options2->size()); @@ -3742,6 +4024,82 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) { // This test verifies that it is possible to specify options on // pool levels. +TEST_F(Dhcp6ParserTest, optionDataSinglePool) { + ConstElementPtr x; + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { " + " \"pool\": \"2001:db8:1::10 - 2001:db8:1::100\"," + " \"option-data\": [ {" + " \"name\": \"subscriber-id\"," + " \"data\": \"0102030405060708090A\"," + " \"csv-format\": false" + " }," + " {" + " \"name\": \"user-class\"," + " \"data\": \"FFFEFDFCFB\"," + " \"csv-format\": false" + " } ]" + " } ]," + " \"subnet\": \"2001:db8:1::/64\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); + checkResult(x, 0); + + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> + selectSubnet(IOAddress("2001:db8:1::5"), classify_); + ASSERT_TRUE(subnet); + + PoolPtr pool = subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1::10"), false); + ASSERT_TRUE(pool); + Pool6Ptr pool6 = boost::dynamic_pointer_cast(pool); + ASSERT_TRUE(pool6); + + OptionContainerPtr options = + pool6->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + ASSERT_EQ(2, options->size()); + + // Get the search index. Index #1 is to search using option code. + const OptionContainerTypeIndex& idx = options->get<1>(); + + // Get the options for specified index. Expecting one option to be + // returned but in theory we may have multiple options with the same + // code so we get the range. + std::pair range = + idx.equal_range(D6O_SUBSCRIBER_ID); + // Expect a single Subscriber ID option instance. + ASSERT_EQ(1, std::distance(range.first, range.second)); + const uint8_t subscriber_id_expected[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A + }; + // Check if option is valid in terms of code and carried data. + testOption(*range.first, D6O_SUBSCRIBER_ID, subscriber_id_expected, + sizeof(subscriber_id_expected)); + + range = idx.equal_range(D6O_USER_CLASS); + ASSERT_EQ(1, std::distance(range.first, range.second)); + // Do another round of testing with second option. + + const uint8_t user_class_expected[] = { + 0xFF, 0xFE, 0xFD, 0xFC, 0xFB + }; + testOption(*range.first, D6O_USER_CLASS, user_class_expected, + sizeof(user_class_expected)); +} + +// This test verifies that it's possible to define different options in +// different pools and those options are not confused. TEST_F(Dhcp6ParserTest, optionDataMultiplePools) { ConstElementPtr x; string config = "{ " + genIfaceConfig() + "," @@ -3894,89 +4252,6 @@ TEST_F(Dhcp6ParserTest, optionDataMultiplePools) { sizeof(user_class_expected2)); } -// The goal of this test is to check that the option carrying a boolean -// value can be configured using one of the values: "true", "false", "0" -// or "1". -TEST_F(Dhcp6ParserTest, optionDataBoolean) { - // Create configuration. Use standard option 1000. - std::map params; - params["name"] = "bool-option"; - params["space"] = DHCP6_OPTION_SPACE; - params["code"] = "1000"; - params["data"] = "true"; - params["csv-format"] = "true"; - - std::string config = createConfigWithOption(params); - ASSERT_TRUE(executeConfiguration(config, "parse configuration with a" - " boolean value")); - - // The subnet should now hold one option with the code 1000. - OptionDescriptor desc = - getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000); - ASSERT_TRUE(desc.option_); - - // This option should be set to "true", represented as 0x1 in the option - // buffer. - uint8_t expected_option_data[] = { - 0x1 - }; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // Configure the option with the "1" value. This should have the same - // effect as if "true" was specified. - params["data"] = "1"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // The value of "1" with a few leading zeros should work too. - params["data"] = "00001"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // Configure the option with the "false" value. - params["data"] = "false"; - // The option buffer should now hold the value of 0. - expected_option_data[0] = 0; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // Specifying "0" should have the same effect as "false". - params["data"] = "0"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // The same effect should be for multiple 0 chars. - params["data"] = "00000"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // Bogus values should not be accepted. - params["data"] = "bogus"; - testInvalidOptionParam(params); - - params["data"] = "2"; - testInvalidOptionParam(params); - - // Now let's test that it is possible to use binary format. - params["data"] = "0"; - params["csv-format"] = "false"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // The binary 1 should work as well. - params["data"] = "1"; - expected_option_data[0] = 1; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - - // As well as an even number of digits. - params["data"] = "01"; - testConfiguration(params, 1000, expected_option_data, - sizeof(expected_option_data)); - -} - // Verify that empty option name is rejected in the configuration. TEST_F(Dhcp6ParserTest, optionNameEmpty) { // Empty option names not allowed. @@ -4048,8 +4323,8 @@ TEST_F(Dhcp6ParserTest, optionDataValidHexLiterals) { EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); ASSERT_EQ(1, options->size()); @@ -4061,8 +4336,8 @@ TEST_F(Dhcp6ParserTest, optionDataValidHexLiterals) { // returned but in theory we may have multiple options with the same // code so we get the range. std::pair range = - idx.equal_range(D6O_SUBSCRIBER_ID); + OptionContainerTypeIndex::const_iterator> range = + idx.equal_range(D6O_SUBSCRIBER_ID); // Expect single option with the code equal to 38. ASSERT_EQ(1, std::distance(range.first, range.second)); @@ -4085,19 +4360,22 @@ TEST_F(Dhcp6ParserTest, stdOptionData) { params["space"] = DHCP6_OPTION_SPACE; // Option code 3 means OPTION_IA_NA. params["code"] = "3"; + // Specify option values in a CSV (user friendly) format. params["data"] = "12345, 6789, 1516"; params["csv-format"] = "true"; std::string config = createConfigWithOption(params); - ConstElementPtr json = parseDHCP6(config); + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::5"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::5"), classify_); ASSERT_TRUE(subnet); OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE); + ASSERT_TRUE(options); ASSERT_EQ(1, options->size()); // Get the search index. Index #1 is to search using option code. @@ -4189,122 +4467,6 @@ TEST_F(Dhcp6ParserTest, rdnssOption) { EXPECT_EQ("example.com.", optionCustom->readFqdn(4)); } -// This test checks if vendor options can be specified in the config file -// (in hex format), and later retrieved from configured subnet -TEST_F(Dhcp6ParserTest, vendorOptionsHex) { - - // This configuration string is to configure two options - // sharing the code 1 and belonging to the different vendor spaces. - // (different vendor-id values). - string config = "{ " + genIfaceConfig() + "," - "\"preferred-lifetime\": 3000," - "\"valid-lifetime\": 4000," - "\"rebind-timer\": 2000," - "\"renew-timer\": 1000," - "\"option-data\": [ {" - " \"name\": \"option-one\"," - " \"space\": \"vendor-4491\"," - " \"code\": 100," - " \"data\": \"ABCDEF0105\"," - " \"csv-format\": false" - " }," - " {" - " \"name\": \"option-two\"," - " \"space\": \"vendor-1234\"," - " \"code\": 100," - " \"data\": \"1234\"," - " \"csv-format\": false" - " } ]," - "\"subnet6\": [ { " - " \"id\": 1," - " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," - " \"subnet\": \"2001:db8:1::/64\"" - " } ]" - "}"; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config)); - extractConfig(config); - - ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - ASSERT_TRUE(status); - checkResult(status, 0); - - // Options should be now available - // Try to get the option from the vendor space 4491 - OptionDescriptor desc1 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); - ASSERT_TRUE(desc1.option_); - EXPECT_EQ(100, desc1.option_->getType()); - // Try to get the option from the vendor space 1234 - OptionDescriptor desc2 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get(1234, 100); - ASSERT_TRUE(desc2.option_); - EXPECT_EQ(100, desc1.option_->getType()); - - // Try to get the non-existing option from the non-existing - // option space and expect that option is not returned. - OptionDescriptor desc3 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 38); - ASSERT_FALSE(desc3.option_); -} - -// This test checks if vendor options can be specified in the config file, -// (in csv format), and later retrieved from configured subnet -TEST_F(Dhcp6ParserTest, vendorOptionsCsv) { - - // This configuration string is to configure two options - // sharing the code 1 and belonging to the different vendor spaces. - // (different vendor-id values). - string config = "{ " + genIfaceConfig() + "," - "\"preferred-lifetime\": 3000," - "\"valid-lifetime\": 4000," - "\"rebind-timer\": 2000," - "\"renew-timer\": 1000," - "\"option-data\": [ {" - " \"name\": \"foo\"," - " \"space\": \"vendor-4491\"," - " \"code\": 100," - " \"data\": \"this is a string vendor-opt\"" - " } ]," - "\"option-def\": [ {" - " \"name\": \"foo\"," - " \"code\": 100," - " \"type\": \"string\"," - " \"space\": \"vendor-4491\"" - " } ]," - "\"subnet6\": [ { " - " \"id\": 1," - " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," - " \"subnet\": \"2001:db8:1::/64\"" - " } ]" - "}"; - - ConstElementPtr status; - - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config)); - extractConfig(config); - - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - ASSERT_TRUE(status); - checkResult(status, 0); - - // Options should be now available. - // Try to get the option from the vendor space 4491 - OptionDescriptor desc1 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); - ASSERT_TRUE(desc1.option_); - EXPECT_EQ(100, desc1.option_->getType()); - - // Try to get the non-existing option from the non-existing - // option space and expect that option is not returned. - OptionDescriptor desc2 = - CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 100); - ASSERT_FALSE(desc2.option_); -} - /// @todo add tests similar to vendorOptionsCsv and vendorOptionsHex, but for /// vendor options defined in a subnet. @@ -4369,6 +4531,7 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) { // they should be included as sub-options in the 'vendor-opts' // option. config = "{ " + genIfaceConfig() + "," + "\"valid-lifetime\": 3000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," "\"option-data\": [ {" @@ -4406,6 +4569,7 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) { ASSERT_NO_THROW(json = parseDHCP6(config)); extractConfig(config); + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); ASSERT_TRUE(status); checkResult(status, 0); @@ -4438,20 +4602,136 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) { // Validate the value according to the configuration. EXPECT_EQ(1234, option_foo_uint32->getValue()); - // Option with the code 111 should be added as a sub-option. - OptionPtr option_foo2 = desc.option_->getOption(111); - ASSERT_TRUE(option_foo2); - EXPECT_EQ(111, option_foo2->getType()); - // This option comprises the IPV4 address. Such option is - // represented by OptionCustom object. - OptionCustomPtr option_foo2_v4 = - boost::dynamic_pointer_cast(option_foo2); - ASSERT_TRUE(option_foo2_v4); - // Get the IP address carried by this option and validate it. - EXPECT_EQ("192.168.2.1", option_foo2_v4->readAddress().toText()); + // Option with the code 111 should be added as a sub-option. + OptionPtr option_foo2 = desc.option_->getOption(111); + ASSERT_TRUE(option_foo2); + EXPECT_EQ(111, option_foo2->getType()); + // This option comprises the IPV4 address. Such option is + // represented by OptionCustom object. + OptionCustomPtr option_foo2_v4 = + boost::dynamic_pointer_cast(option_foo2); + ASSERT_TRUE(option_foo2_v4); + // Get the IP address carried by this option and validate it. + EXPECT_EQ("192.168.2.1", option_foo2_v4->readAddress().toText()); + + // Option with the code 112 should not be added. + EXPECT_FALSE(desc.option_->getOption(112)); +} + +// This test checks if vendor options can be specified in the config file +// (in hex format), and later retrieved from configured subnet +TEST_F(Dhcp6ParserTest, vendorOptionsHex) { + + // This configuration string is to configure two options + // sharing the code 1 and belonging to the different vendor spaces. + // (different vendor-id values). + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"valid-lifetime\": 4000," + "\"rebind-timer\": 2000," + "\"renew-timer\": 1000," + "\"option-data\": [ {" + " \"name\": \"option-one\"," + " \"space\": \"vendor-4491\"," // VENDOR_ID_CABLE_LABS = 4491 + " \"code\": 100," // just a random code + " \"data\": \"ABCDEF0105\"," + " \"csv-format\": false" + " }," + " {" + " \"name\": \"option-two\"," + " \"space\": \"vendor-1234\"," + " \"code\": 100," + " \"data\": \"1234\"," + " \"csv-format\": false" + " } ]," + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," + " \"subnet\": \"2001:db8:1::/64\"" + " } ]" + "}"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + // Options should be now available + // Try to get the option from the vendor space 4491 + OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()-> + getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); + ASSERT_TRUE(desc1.option_); + EXPECT_EQ(100, desc1.option_->getType()); + // Try to get the option from the vendor space 1234 + OptionDescriptor desc2 = + CfgMgr::instance().getStagingCfg()->getCfgOption()->get(1234, 100); + ASSERT_TRUE(desc2.option_); + EXPECT_EQ(100, desc1.option_->getType()); + + // Try to get the non-existing option from the non-existing + // option space and expect that option is not returned. + OptionDescriptor desc3 = + CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 38); + ASSERT_FALSE(desc3.option_); +} + +// This test checks if vendor options can be specified in the config file, +// (in csv format), and later retrieved from configured subnet +TEST_F(Dhcp6ParserTest, vendorOptionsCsv) { + + // This configuration string is to configure two options + // sharing the code 1 and belonging to the different vendor spaces. + // (different vendor-id values). + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000," + "\"valid-lifetime\": 4000," + "\"rebind-timer\": 2000," + "\"renew-timer\": 1000," + "\"option-data\": [ {" + " \"name\": \"foo\"," + " \"space\": \"vendor-4491\"," + " \"code\": 100," + " \"data\": \"this is a string vendor-opt\"" + " } ]," + "\"option-def\": [ {" + " \"name\": \"foo\"," + " \"code\": 100," + " \"type\": \"string\"," + " \"space\": \"vendor-4491\"" + " } ]," + "\"subnet6\": [ { " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ]," + " \"subnet\": \"2001:db8:1::/64\"" + " } ]" + "}"; + + ConstElementPtr status; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); - // Option with the code 112 should not be added. - EXPECT_FALSE(desc.option_->getOption(112)); + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + // Options should be now available. + // Try to get the option from the vendor space 4491 + OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()-> + getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100); + ASSERT_TRUE(desc1.option_); + EXPECT_EQ(100, desc1.option_->getType()); + + // Try to get the non-existing option from the non-existing + // option space and expect that option is not returned. + OptionDescriptor desc2 = + CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 100); + ASSERT_FALSE(desc2.option_); } // Tests of the hooks libraries configuration. All tests have the pre- @@ -4484,6 +4764,7 @@ buildHooksLibrariesConfig(const std::vector& libraries = {}, // Append the remainder of the configuration. config += string( "]," + "\"valid-lifetime\": 4000," "\"rebind-timer\": 2000," "\"renew-timer\": 1000," "\"option-data\": [ {" @@ -4562,6 +4843,7 @@ TEST_F(Dhcp6ParserTest, LibrariesSpecified) { EXPECT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE)); // Set up the configuration with two libraries and load them. + // Disable multi-threading since one of the libraries is single-threaded. string config = buildHooksLibrariesConfig({CALLOUT_LIBRARY_1, CALLOUT_LIBRARY_2}, /* multi_threading = */ false); ASSERT_TRUE(executeConfiguration(config, @@ -4574,6 +4856,8 @@ TEST_F(Dhcp6ParserTest, LibrariesSpecified) { EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "12")); EXPECT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE)); + // Commit the changes so as we get the fresh configuration for the + // second part of this test. CfgMgr::instance().commit(); // Unload the libraries. The load file should not have changed, but @@ -4655,12 +4939,14 @@ TEST_F(Dhcp6ParserTest, IncompatibleLibrary3Specified) { libraries = HooksManager::getLibraryNames(); EXPECT_TRUE(libraries.empty()); } -// This test verifies that it is possible to select subset of interfaces on -// which server should listen. + +// This test verifies that it is possible to select subset of interfaces +// on which server should listen. TEST_F(Dhcp6ParserTest, selectedInterfaces) { IfaceMgrTestConfig test_config(true); - // Make sure there is no garbage interface configuration in the CfgMgr. + // Make sure the config manager is clean and there is no hanging + // interface configuration. ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET6)); ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET6)); @@ -4677,10 +4963,10 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) { extractConfig(config); ConstElementPtr status; + // Apply configuration. EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - - // returned value must be 1 (values error) - // as the pool does not belong to that subnet + ASSERT_TRUE(status); + // returned value must be 0 (configuration accepted) checkResult(status, 0); CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET6, 10000); @@ -4690,16 +4976,17 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) { EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET6)); } -// This test verifies that it is possible to configure the server to listen on -// all interfaces. +// This test verifies that it is possible to configure the server in such a way +// that it listens on all interfaces. TEST_F(Dhcp6ParserTest, allInterfaces) { IfaceMgrTestConfig test_config(true); + // Make sure there is no old configuration. ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET6)); ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET6)); // This configuration specifies two interfaces on which server should listen - // but also includes '*'. This keyword switches server into the + // but it also includes asterisk. The asterisk switches server into the // mode when it listens on all interfaces regardless of what interface names // were specified in the "interfaces" parameter. string config = "{ \"interfaces-config\": {" @@ -4715,13 +5002,53 @@ TEST_F(Dhcp6ParserTest, allInterfaces) { extractConfig(config); ConstElementPtr status; + + // Apply configuration. EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); checkResult(status, 0); CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET6, 10000); // All interfaces should be now active. + ASSERT_TRUE(test_config.socketOpen("eth0", AF_INET6)); + ASSERT_TRUE(test_config.socketOpen("eth1", AF_INET6)); +} + +// This test verifies that it is possible to select subset of interfaces +// and addresses. +TEST_F(Dhcp6ParserTest, selectedInterfacesAndAddresses) { + IfaceMgrTestConfig test_config(true); + + ConstElementPtr x; + string config = "{ \"interfaces-config\": {" + " \"interfaces\": [ \"eth0/2001:db8:1::1\", \"eth1/fe80::3a60:77ff:fed5:abcd\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + + ConstElementPtr status; + + // Make sure the config manager is clean and there is no hanging + // interface configuration. + ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET6)); + ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET6)); + + // Apply configuration. + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET6, 10000); + + // An address on eth0 was selected EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6)); + // The 2001:db8:1::1 address on eth1 was selected. EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET6)); } @@ -4735,6 +5062,9 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfo) { "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ]," + " \"renew-timer\": 1, " + " \"rebind-timer\": 2, " + " \"valid-lifetime\": 4," " \"relay\": { " " \"ip-addresses\": [ \"2001:db8:1::abcd\" ]" " }," @@ -4752,8 +5082,8 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfo) { // returned value should be 0 (configuration success) checkResult(status, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db8:1::1"), classify_); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db8:1::1"), classify_); ASSERT_TRUE(subnet); EXPECT_TRUE(subnet->hasRelays()); @@ -4769,6 +5099,9 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfoList) { "\"subnet6\": [ { " " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ]," + " \"renew-timer\": 1, " + " \"rebind-timer\": 2, " + " \"valid-lifetime\": 4," " \"relay\": { " " \"ip-addresses\": [ \"2001:db9::abcd\", \"2001:db9::abce\" ]" " }," @@ -4786,8 +5119,8 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfoList) { // returned value should be 0 (configuration success) checkResult(status, 0); - Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()-> - selectSubnet(IOAddress("2001:db9::abcd"), classify_, true); + Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()-> + getCfgSubnets6()->selectSubnet(IOAddress("2001:db9::abcd"), classify_, true); ASSERT_TRUE(subnet); EXPECT_TRUE(subnet->hasRelays()); @@ -4940,10 +5273,10 @@ TEST_F(Dhcp6ParserTest, classifyPools) { // everyone). ClientClasses classes; classes.insert("alpha"); - EXPECT_TRUE (pools.at(0)->clientSupported(classes)); + EXPECT_TRUE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to beta class is supported in pool[1] // and not supported in any other pool (except pool[3], which allows @@ -4951,9 +5284,9 @@ TEST_F(Dhcp6ParserTest, classifyPools) { classes.clear(); classes.insert("beta"); EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_TRUE (pools.at(1)->clientSupported(classes)); + EXPECT_TRUE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to gamma class is supported in pool[2] // and not supported in any other pool (except pool[3], which allows @@ -4962,8 +5295,8 @@ TEST_F(Dhcp6ParserTest, classifyPools) { classes.insert("gamma"); EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_TRUE (pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to some other class (not mentioned in // the config) is supported only in pool[3], which allows everyone. @@ -4972,7 +5305,7 @@ TEST_F(Dhcp6ParserTest, classifyPools) { EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Finally, let's check class-less client. He should be allowed only in // the last pool, which does not have any class restrictions. @@ -4980,7 +5313,7 @@ TEST_F(Dhcp6ParserTest, classifyPools) { EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); } // Goal of this test is to verify that multiple pdpools can be configured @@ -5039,10 +5372,10 @@ TEST_F(Dhcp6ParserTest, classifyPdPools) { // everyone). ClientClasses classes; classes.insert("alpha"); - EXPECT_TRUE (pools.at(0)->clientSupported(classes)); + EXPECT_TRUE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to beta class is supported in pool[1] // and not supported in any other pool (except pool[3], which allows @@ -5050,9 +5383,9 @@ TEST_F(Dhcp6ParserTest, classifyPdPools) { classes.clear(); classes.insert("beta"); EXPECT_FALSE(pools.at(0)->clientSupported(classes)); - EXPECT_TRUE (pools.at(1)->clientSupported(classes)); + EXPECT_TRUE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to gamma class is supported in pool[2] // and not supported in any other pool (except pool[3], which allows @@ -5061,8 +5394,8 @@ TEST_F(Dhcp6ParserTest, classifyPdPools) { classes.insert("gamma"); EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); - EXPECT_TRUE (pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(2)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Let's check if client belonging to some other class (not mentioned in // the config) is supported only in pool[3], which allows everyone. @@ -5071,7 +5404,7 @@ TEST_F(Dhcp6ParserTest, classifyPdPools) { EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); // Finally, let's check class-less client. He should be allowed only in // the last pool, which does not have any class restrictions. @@ -5079,7 +5412,7 @@ TEST_F(Dhcp6ParserTest, classifyPdPools) { EXPECT_FALSE(pools.at(0)->clientSupported(classes)); EXPECT_FALSE(pools.at(1)->clientSupported(classes)); EXPECT_FALSE(pools.at(2)->clientSupported(classes)); - EXPECT_TRUE (pools.at(3)->clientSupported(classes)); + EXPECT_TRUE(pools.at(3)->clientSupported(classes)); } // This test verifies that valid d2CliengConfig works correctly. @@ -5476,6 +5809,11 @@ TEST_F(Dhcp6ParserTest, reservationWithOptionDefinition) { ConstHostPtr host = hosts_cfg->get6(234, Host::IDENT_DUID, &duid[0], duid.size()); ASSERT_TRUE(host); + IPv6ResrvRange resrv = host->getIPv6Reservations(IPv6Resrv::TYPE_NA); + ASSERT_EQ(1, std::distance(resrv.first, resrv.second)); + EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA, + IOAddress("2001:db8:2::1234")), + resrv)); // Check if the option has been parsed. OptionUint32Ptr opt_foo = retrieveOption(*host, "isc", @@ -5510,7 +5848,10 @@ TEST_F(Dhcp6ParserTest, reservationBogus) { "\"preferred-lifetime\": 3000," "\"valid-lifetime\": 4000 }"; - ConstElementPtr json = parseJSON(config); + ConstElementPtr json; + ASSERT_NO_THROW(json = parseJSON(config)); + + CfgMgr::instance().clear(); EXPECT_NO_THROW(x = Dhcpv6SrvTest::configure(srv_, json)); checkResult(x, 1); @@ -5572,7 +5913,7 @@ TEST_F(Dhcp6ParserTest, reservationBogus) { "\"preferred-lifetime\": 3000," "\"valid-lifetime\": 4000 }"; - json = parseDHCP6(config); + ASSERT_NO_THROW(json = parseDHCP6(config)); // Remove existing configuration, if any. CfgMgr::instance().clear(); @@ -5820,7 +6161,6 @@ TEST_F(Dhcp6ParserTest, hostReservationPerSubnet) { EXPECT_TRUE(subnet->getReservationsGlobal()); EXPECT_TRUE(subnet->getReservationsInSubnet()); EXPECT_TRUE(subnet->getReservationsOutOfPool()); - } /// The goal of this test is to verify that Host Reservation flags can be @@ -5878,6 +6218,10 @@ TEST_F(Dhcp6ParserTest, hostReservationGlobal) { Subnet6Ptr subnet; subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1")); ASSERT_TRUE(subnet); + // Reset the fetch global function to staging (vs current) config. + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); + }); EXPECT_FALSE(subnet->getReservationsGlobal()); EXPECT_TRUE(subnet->getReservationsInSubnet()); EXPECT_FALSE(subnet->getReservationsOutOfPool()); @@ -5885,11 +6229,39 @@ TEST_F(Dhcp6ParserTest, hostReservationGlobal) { // Subnet 2 subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1")); ASSERT_TRUE(subnet); + // Reset the fetch global function to staging (vs current) config. + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); + }); EXPECT_FALSE(subnet->getReservationsGlobal()); EXPECT_TRUE(subnet->getReservationsInSubnet()); EXPECT_TRUE(subnet->getReservationsOutOfPool()); } +/// Check that the decline-probation-period has a default value when not +/// specified. +TEST_F(Dhcp6ParserTest, declineTimerDefault) { + + string config = "{ " + genIfaceConfig() + "," + "\"subnet6\": [ ] " + "}"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + + // returned value should be 0 (success) + checkResult(status, 0); + + // The value of decline-probation-period must be equal to the + // default value (86400). The default value is defined in GLOBAL6_DEFAULTS in + // simple_parser6.cc. + EXPECT_EQ(86400, CfgMgr::instance().getStagingCfg()->getDeclinePeriod()); +} + /// The goal of this test is to verify that configuration can include /// Relay Supplied options (specified as numbers). TEST_F(Dhcp6ParserTest, rsooNumbers) { @@ -6084,29 +6456,6 @@ TEST_F(Dhcp6ParserTest, testDataDir) { EXPECT_NE(original_datadir, string(CfgMgr::instance().getDataDir())); } -/// Check that the decline-probation-period value has a default value if not -/// specified explicitly. -TEST_F(Dhcp6ParserTest, declineTimerDefault) { - - string config_txt = "{ " + genIfaceConfig() + "," - "\"subnet6\": [ ] " - "}"; - ConstElementPtr config; - ASSERT_NO_THROW(config = parseDHCP6(config_txt)); - extractConfig(config_txt); - - ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, config)); - - // returned value should be 0 (success) - checkResult(status, 0); - - // The value of decline-probation-period must be equal to the - // default value (86400). The default value is defined in GLOBAL6_DEFAULTS in - // simple_parser6.cc. - EXPECT_EQ(86400, CfgMgr::instance().getStagingCfg()->getDeclinePeriod()); -} - /// Check that the dhcp4o6-port default value has a default value if not /// specified explicitly. TEST_F(Dhcp6ParserTest, dhcp4o6portDefault) { @@ -6132,7 +6481,7 @@ TEST_F(Dhcp6ParserTest, dhcp4o6portDefault) { /// Check that the decline-probation-period value can be set properly. TEST_F(Dhcp6ParserTest, declineTimer) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"decline-probation-period\": 12345," "\"subnet6\": [ ]" "}"; @@ -6155,12 +6504,13 @@ TEST_F(Dhcp6ParserTest, declineTimer) { /// Check that an incorrect decline-probation-period value will be caught. TEST_F(Dhcp6ParserTest, declineTimerError) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"decline-probation-period\": \"soon\"," "\"subnet6\": [ ]" "}"; - ConstElementPtr json = parseJSON(config); + ConstElementPtr json; + ASSERT_NO_THROW(json = parseJSON(config)); ConstElementPtr status; EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); @@ -6179,7 +6529,7 @@ TEST_F(Dhcp6ParserTest, declineTimerError) { // specified. TEST_F(Dhcp6ParserTest, expiredLeasesProcessing) { // Create basic configuration with the expiration specific parameters. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"expired-leases-processing\": " "{" " \"reclaim-timer-wait-time\": 20," @@ -6221,7 +6571,7 @@ TEST_F(Dhcp6ParserTest, expiredLeasesProcessing) { TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) { // Create basic configuration with the expiration specific parameters. // One of the parameters holds invalid value. - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"expired-leases-processing\": " "{" " \"reclaim-timer-wait-time\": -5," @@ -6252,31 +6602,160 @@ TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) { TEST_F(Dhcp6ParserTest, validClientClassDictionary) { string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000, \n" + "\"valid-lifetime\": 4000, \n" "\"rebind-timer\": 2000, \n" "\"renew-timer\": 1000, \n" "\"client-classes\" : [ \n" " { \n" - " \"name\": \"one\" \n" - " }, \n" - " { \n" - " \"name\": \"two\" \n" + " \"name\": \"one\" \n" + " }, \n" + " { \n" + " \"name\": \"two\" \n" + " }, \n" + " { \n" + " \"name\": \"three\" \n" + " } \n" + "], \n" + "\"subnet6\": [ { \n" + " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ], \n" + " \"subnet\": \"2001:db8:1::/64\" \n" + " } ] \n" + "} \n"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + // We check staging config because CfgMgr::commit hasn't been executed. + ClientClassDictionaryPtr dictionary; + dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(3, dictionary->getClasses()->size()); + + // Execute the commit + ASSERT_NO_THROW(CfgMgr::instance().commit()); + + // Verify that after commit, the current config has the correct dictionary + dictionary = CfgMgr::instance().getCurrentCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(3, dictionary->getClasses()->size()); +} + +// Verifies that a class list containing an invalid +// class definition causes a configuration error. +TEST_F(Dhcp6ParserTest, invalidClientClassDictionary) { + string config = "{ " + genIfaceConfig() + "," + "\"valid-lifetime\": 4000, \n" + "\"rebind-timer\": 2000, \n" + "\"renew-timer\": 1000, \n" + "\"client-classes\" : [ \n" + " { \n" + " \"name\": \"one\", \n" + " \"bogus\": \"bad\" \n" + " } \n" + "], \n" + "\"subnet6\": [ { \n" + " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ], \n" + " \"subnet\": \"2001:db8::/64\" \n" + " } ] \n" + "} \n"; + + EXPECT_THROW(parseDHCP6(config), Dhcp6ParseError); +} + +// Verifies that simple list of valid classes parses and +// is staged for commit. +TEST_F(Dhcp6ParserTest, clientClassValidLifetime) { + string config = "{ " + genIfaceConfig() + "," + "\"client-classes\" : [ \n" + " { \n" + " \"name\": \"one\", \n" + " \"min-valid-lifetime\": 1000, \n" + " \"valid-lifetime\": 2000, \n" + " \"max-valid-lifetime\": 3000 \n" + " }, \n" + " { \n" + " \"name\": \"two\" \n" + " } \n" + "], \n" + "\"subnet6\": [ { \n" + " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ], \n" + " \"subnet\": \"2001:db8::/64\" \n" + " } ] \n" + "} \n"; + + ConstElementPtr json; + ASSERT_NO_THROW_LOG(json = parseDHCP6(config)); + extractConfig(config); + + ConstElementPtr status; + ASSERT_NO_THROW_LOG(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + // We check staging config because CfgMgr::commit hasn't been executed. + ClientClassDictionaryPtr dictionary; + dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(2, dictionary->getClasses()->size()); + + // Execute the commit + ASSERT_NO_THROW(CfgMgr::instance().commit()); + + // Verify that after commit, the current config has the correct dictionary + dictionary = CfgMgr::instance().getCurrentCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(2, dictionary->getClasses()->size()); + + ClientClassDefPtr class_def = dictionary->findClass("one"); + ASSERT_TRUE(class_def); + EXPECT_EQ(class_def->getValid().getMin(), 1000); + EXPECT_EQ(class_def->getValid().get(), 2000); + EXPECT_EQ(class_def->getValid().getMax(), 3000); + + class_def = dictionary->findClass("two"); + ASSERT_TRUE(class_def); + EXPECT_TRUE(class_def->getValid().unspecified()); +} + +// Verifies that simple list of valid template classes parses and +// is staged for commit. +TEST_F(Dhcp6ParserTest, templateClientClassValidLifetime) { + string config = "{ " + genIfaceConfig() + "," + "\"client-classes\" : [ \n" + " { \n" + " \"name\": \"one\", \n" + " \"min-valid-lifetime\": 1000, \n" + " \"valid-lifetime\": 2000, \n" + " \"max-valid-lifetime\": 3000, \n" + " \"template-test\": \"''\" \n" " }, \n" " { \n" - " \"name\": \"three\" \n" + " \"name\": \"two\", \n" + " \"template-test\": \"''\" \n" " } \n" "], \n" "\"subnet6\": [ { \n" " \"id\": 1, \n" - " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ], \n" - " \"subnet\": \"2001:db8:1::/64\" } ], \n" - "\"valid-lifetime\": 4000 } \n"; + " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ], \n" + " \"subnet\": \"2001:db8::/64\" \n" + " } ] \n" + "} \n"; ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config)); + ASSERT_NO_THROW_LOG(json = parseDHCP6(config)); extractConfig(config); ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_NO_THROW_LOG(status = Dhcpv6SrvTest::configure(srv_, json)); ASSERT_TRUE(status); checkResult(status, 0); @@ -6284,7 +6763,7 @@ TEST_F(Dhcp6ParserTest, validClientClassDictionary) { ClientClassDictionaryPtr dictionary; dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary(); ASSERT_TRUE(dictionary); - EXPECT_EQ(3, dictionary->getClasses()->size()); + EXPECT_EQ(2, dictionary->getClasses()->size()); // Execute the commit ASSERT_NO_THROW(CfgMgr::instance().commit()); @@ -6292,30 +6771,19 @@ TEST_F(Dhcp6ParserTest, validClientClassDictionary) { // Verify that after commit, the current config has the correct dictionary dictionary = CfgMgr::instance().getCurrentCfg()->getClientClassDictionary(); ASSERT_TRUE(dictionary); - EXPECT_EQ(3, dictionary->getClasses()->size()); -} + EXPECT_EQ(2, dictionary->getClasses()->size()); -// Verifies that a class list containing an invalid -// class definition causes a configuration error. -TEST_F(Dhcp6ParserTest, invalidClientClassDictionary) { - string config = "{ " + genIfaceConfig() + "," + - "\"valid-lifetime\": 4000, \n" - "\"rebind-timer\": 2000, \n" - "\"renew-timer\": 1000, \n" - "\"client-classes\" : [ \n" - " { \n" - " \"name\": \"one\", \n" - " \"bogus\": \"bad\" \n" - " } \n" - "], \n" - "\"subnet6\": [ { \n" - " \"id\": 1, \n" - " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ], \n" - " \"subnet\": \"2001:db8::/64\" \n" - " } ] \n" - "} \n"; + ClientClassDefPtr class_def = dictionary->findClass("one"); + ASSERT_TRUE(class_def); + ASSERT_TRUE(dynamic_cast(class_def.get())); + EXPECT_EQ(class_def->getValid().getMin(), 1000); + EXPECT_EQ(class_def->getValid().get(), 2000); + EXPECT_EQ(class_def->getValid().getMax(), 3000); - EXPECT_THROW(parseDHCP6(config), Dhcp6ParseError); + class_def = dictionary->findClass("two"); + ASSERT_TRUE(class_def); + ASSERT_TRUE(dynamic_cast(class_def.get())); + EXPECT_TRUE(class_def->getValid().unspecified()); } // Test verifies that regular configuration does not provide any user context @@ -6383,6 +6851,46 @@ TEST_F(Dhcp6ParserTest, poolUserContextlw4over6) { EXPECT_EQ(56L, int_value); } +// Test verifies that it's possible to specify parameters in the user context +// in the address pool. +TEST_F(Dhcp6ParserTest, poolUserContextData) { + extractConfig(PARSER_CONFIGS[2]); + PoolPtr pool; + getPool(string(PARSER_CONFIGS[2]), 0, 0, Lease::TYPE_NA, pool); + ASSERT_TRUE(pool); + ConstElementPtr ctx = pool->getContext(); + ASSERT_TRUE(ctx); + + // The context should be of type map and contain 4 parameters. + EXPECT_EQ(Element::map, ctx->getType()); + EXPECT_EQ(4, ctx->size()); + ConstElementPtr ratio = ctx->get("lw4over6-sharing-ratio"); + ConstElementPtr v4pool = ctx->get("lw4over6-v4-pool"); + ConstElementPtr exclude = ctx->get("lw4over6-sysports-exclude"); + ConstElementPtr v6len = ctx->get("lw4over6-bind-prefix-len"); + + ASSERT_TRUE(ratio); + ASSERT_EQ(Element::integer, ratio->getType()); + int64_t int_value; + EXPECT_NO_THROW(ratio->getValue(int_value)); + EXPECT_EQ(64L, int_value); + + ASSERT_TRUE(v4pool); + ASSERT_EQ(Element::string, v4pool->getType()); + EXPECT_EQ("192.0.2.0/24", v4pool->stringValue()); + + ASSERT_TRUE(exclude); + bool bool_value; + ASSERT_EQ(Element::boolean, exclude->getType()); + EXPECT_NO_THROW(exclude->getValue(bool_value)); + EXPECT_EQ(true, bool_value); + + ASSERT_TRUE(v6len); + ASSERT_EQ(Element::integer, v6len->getType()); + EXPECT_NO_THROW(v6len->getValue(int_value)); + EXPECT_EQ(56L, int_value); +} + // Test verifies that it's possible to specify parameters in the user context // in the min-max address pool. TEST_F(Dhcp6ParserTest, poolMinMaxUserContext) { @@ -6503,21 +7011,10 @@ TEST_F(Dhcp6ParserTest, invalidPoolRange) { " } ] \n" "} \n"; - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config, true)); - - ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - ASSERT_TRUE(status); - int rcode; - ConstElementPtr comment = parseAnswerText(rcode, status); - string text; - ASSERT_NO_THROW(text = comment->stringValue()); - - EXPECT_EQ(1, rcode); string expected = "Failed to create pool defined by: " "2001:db8::-200:1db8::ffff (:8:26)"; - EXPECT_EQ(expected, text); + + configure(config, CONTROL_RESULT_ERROR, expected); } // Test verifies the error message for an outside subnet pool range @@ -6535,23 +7032,12 @@ TEST_F(Dhcp6ParserTest, outsideSubnetPool) { " } ] \n" "} \n"; - ConstElementPtr json; - ASSERT_NO_THROW(json = parseDHCP6(config, true)); - - ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); - ASSERT_TRUE(status); - int rcode; - ConstElementPtr comment = parseAnswerText(rcode, status); - string text; - ASSERT_NO_THROW(text = comment->stringValue()); - - EXPECT_EQ(1, rcode); string expected = "subnet configuration failed: " "a pool of type IA_NA, with the following address range: " "2001:db8::-2001:db8::ffff does not match the prefix of a subnet: " "2001:dc8::/32 to which it is being added (:6:14)"; - EXPECT_EQ(expected, text); + + configure(config, CONTROL_RESULT_ERROR, expected); } // Test verifies that empty shared networks are accepted. @@ -6562,6 +7048,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksEmpty) { "\"renew-timer\": 1000, \n" "\"subnet6\": [ { \n" " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8:: - 2001:db8::ffff\" } ], \n" " \"subnet\": \"2001:db8::/48\" \n" " } ],\n" "\"shared-networks\": [ ]\n" @@ -6579,6 +7066,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksNoName) { "\"renew-timer\": 1000, \n" "\"subnet6\": [ { \n" " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8:: - 2001:db8::ffff\" } ], \n" " \"subnet\": \"2001:db8::/48\" \n" " } ],\n" "\"shared-networks\": [ { } ]\n" @@ -6595,6 +7083,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksEmptyName) { "\"renew-timer\": 1000, \n" "\"subnet6\": [ { \n" " \"id\": 1, \n" + " \"pools\": [ { \"pool\": \"2001:db8:: - 2001:db8::ffff\" } ], \n" " \"subnet\": \"2001:db8::/48\" \n" " } ],\n" "\"shared-networks\": [ { \"name\": \"\" } ]\n" @@ -6610,8 +7099,8 @@ TEST_F(Dhcp6ParserTest, sharedNetworksName) { string config = "{\n" "\"subnet6\": [ { \n" " \"id\": 1, \n" - " \"subnet\": \"2001:db8::/48\",\n" - " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ]\n" + " \"pools\": [ { \"pool\": \"2001:db8:: - 2001:db8::ffff\" } ], \n" + " \"subnet\": \"2001:db8::/48\"\n" " } ],\n" "\"shared-networks\": [ { \"name\": \"foo\" } ]\n" "} \n"; @@ -6643,7 +7132,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworks1subnet) { "\"shared-networks\": [ {\n" " \"name\": \"foo\"\n," " \"subnet6\": [ { \n" - " \"id\": 1, \n" + " \"id\": 1,\n" " \"subnet\": \"2001:db8::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db8::1 - 2001:db8::ffff\" } ]\n" " } ]\n" @@ -6691,24 +7180,24 @@ TEST_F(Dhcp6ParserTest, sharedNetworks1subnet) { // - that overridden parameters only affect one subnet and not others TEST_F(Dhcp6ParserTest, sharedNetworks3subnets) { string config = "{\n" + "\"valid-lifetime\": 4000, \n" + "\"min-valid-lifetime\": 3000, \n" + "\"max-valid-lifetime\": 5000, \n" "\"renew-timer\": 1000, \n" "\"rebind-timer\": 2000, \n" "\"preferred-lifetime\": 3000, \n" "\"min-preferred-lifetime\": 2000, \n" "\"max-preferred-lifetime\": 4000, \n" - "\"valid-lifetime\": 4000, \n" - "\"min-valid-lifetime\": 3000, \n" - "\"max-valid-lifetime\": 5000, \n" "\"shared-networks\": [ {\n" " \"name\": \"foo\"\n," " \"subnet6\": [\n" " { \n" - " \"id\": 1, \n" + " \"id\": 1,\n" " \"subnet\": \"2001:db1::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db1::/64\" } ]\n" " },\n" " { \n" - " \"id\": 2, \n" + " \"id\": 2,\n" " \"subnet\": \"2001:db2::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db2::/64\" } ],\n" " \"renew-timer\": 2,\n" @@ -6721,7 +7210,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworks3subnets) { " \"max-valid-lifetime\": 3333\n" " },\n" " { \n" - " \"id\": 3, \n" + " \"id\": 3,\n" " \"subnet\": \"2001:db3::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db3::/64\" } ]\n" " }\n" @@ -6797,7 +7286,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { Option iface_id2(Option::V6, D6O_INTERFACE_ID, buffer2); string config = "{\n" - "\"renew-timer\": 1, \n" + "\"renew-timer\": 1, \n" // global values here "\"rebind-timer\": 2, \n" "\"preferred-lifetime\": 3,\n" "\"min-preferred-lifetime\": 2,\n" @@ -6806,7 +7295,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { "\"min-valid-lifetime\": 3, \n" "\"max-valid-lifetime\": 5, \n" "\"shared-networks\": [ {\n" - " \"name\": \"foo\"\n," + " \"name\": \"foo\"\n," // shared network values here " \"renew-timer\": 10,\n" " \"rebind-timer\": 20, \n" " \"preferred-lifetime\": 30,\n" @@ -6825,12 +7314,12 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { " \"reservations-in-subnet\": false,\n" " \"subnet6\": [\n" " { \n" - " \"id\": 1, \n" + " \"id\": 1,\n" " \"subnet\": \"2001:db1::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db1::/64\" } ]\n" " },\n" " { \n" - " \"id\": 2, \n" + " \"id\": 2,\n" " \"subnet\": \"2001:db2::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db2::/64\" } ],\n" " \"renew-timer\": 100\n," @@ -6856,12 +7345,12 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { " \"name\": \"bar\",\n" " \"subnet6\": [\n" " {\n" - " \"id\": 3, \n" + " \"id\": 3,\n" " \"subnet\": \"2001:db3::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db3::/64\" } ]\n" " }\n" " ]\n" - "} ]\n" + " } ]\n" "} \n"; configure(config, CONTROL_RESULT_SUCCESS, ""); @@ -6880,6 +7369,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { SharedNetwork6Ptr net = nets->at(0); ASSERT_TRUE(net); + // The first shared network has two subnets. const Subnet6SimpleCollection* subs = net->getAllSubnets(); ASSERT_TRUE(subs); EXPECT_EQ(2, subs->size()); @@ -6924,6 +7414,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { EXPECT_EQ(1, subs->size()); // This subnet should derive its renew-timer from global scope. + // All other parameters should have default values. s = checkSubnet(*subs, "2001:db3::/48", 1, 2, 3, 4, 2, 4, 3, 5); EXPECT_FALSE(s->getInterfaceId()); EXPECT_FALSE(s->hasRelays()); @@ -7061,18 +7552,25 @@ TEST_F(Dhcp6ParserTest, sharedNetworksInterfacesMixed) { // This test checks if client-class is derived properly. TEST_F(Dhcp6ParserTest, sharedNetworksDeriveClientClass) { + // This config is structured in a way that the first shared network has + // client-class defined. This should in general be inherited by subnets, but + // it's also possible to override the values on subnet level. string config = "{\n" + "\"renew-timer\": 1, \n" // global values here + "\"rebind-timer\": 2, \n" + "\"preferred-lifetime\": 3,\n" + "\"valid-lifetime\": 4, \n" "\"shared-networks\": [ {\n" - " \"name\": \"foo\"\n," + " \"name\": \"foo\"\n," // shared network values here " \"client-class\": \"alpha\",\n" " \"subnet6\": [\n" " { \n" - " \"id\": 1, \n" + " \"id\": 1,\n" " \"subnet\": \"2001:db1::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db1::/64\" } ]\n" " },\n" " { \n" - " \"id\": 2, \n" + " \"id\": 2,\n" " \"subnet\": \"2001:db2::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db2::/64\" } ],\n" " \"client-class\": \"beta\"\n" @@ -7083,12 +7581,12 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDeriveClientClass) { " \"name\": \"bar\",\n" " \"subnet6\": [\n" " {\n" - " \"id\": 3, \n" + " \"id\": 3,\n" " \"subnet\": \"2001:db3::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db3::/64\" } ]\n" " }\n" " ]\n" - "} ]\n" + " } ]\n" "} \n"; configure(config, CONTROL_RESULT_SUCCESS, ""); @@ -7106,21 +7604,23 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDeriveClientClass) { // Let's check the first one. SharedNetwork6Ptr net = nets->at(0); ASSERT_TRUE(net); + EXPECT_EQ("alpha", net->getClientClass().get()); + // The first shared network has two subnets. const Subnet6SimpleCollection* subs = net->getAllSubnets(); ASSERT_TRUE(subs); EXPECT_EQ(2, subs->size()); // For the first subnet, the client-class should be inherited from // shared-network level. - Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 0, 0, 0, 7200); + Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 1, 2, 3, 4); ASSERT_TRUE(s); EXPECT_EQ("alpha", s->getClientClass().get()); // For the second subnet, the values are overridden on subnet level. // The value should not be inherited. - s = checkSubnet(*subs, "2001:db2::/48", 0, 0, 0, 7200); + s = checkSubnet(*subs, "2001:db2::/48", 1, 2, 3, 4); ASSERT_TRUE(s); EXPECT_EQ("beta", s->getClientClass().get()); // beta defined on subnet level @@ -7135,7 +7635,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDeriveClientClass) { EXPECT_EQ(1, subs->size()); // This subnet should derive its renew-timer from global scope. - s = checkSubnet(*subs, "2001:db3::/48", 0, 0, 0, 7200); + s = checkSubnet(*subs, "2001:db3::/48", 1, 2, 3, 4); EXPECT_TRUE(s->getClientClass().empty()); } @@ -7257,7 +7757,7 @@ TEST_F(Dhcp6ParserTest, hostsDatabases) { ASSERT_EQ(2, hal.size()); // Keywords are in alphabetical order EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal.front()); - EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal.back()); + EXPECT_EQ("name=keatest2 password=keatest retry-on-startup=true type=mysql user=keatest", hal.back()); } // This test checks comments. Please keep it last. @@ -7403,6 +7903,8 @@ TEST_F(Dhcp6ParserTest, comments) { ASSERT_EQ(1, subs->size()); Subnet6Ptr sub = *subs->begin(); ASSERT_TRUE(sub); + EXPECT_EQ(100, sub->getID()); + EXPECT_EQ("2001:db1::/48", sub->toText()); // Check subnet user context. ConstElementPtr ctx_sub = sub->getContext(); @@ -7410,8 +7912,6 @@ TEST_F(Dhcp6ParserTest, comments) { ASSERT_EQ(1, ctx_sub->size()); ASSERT_TRUE(ctx_sub->get("comment")); EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str()); - EXPECT_EQ(100, sub->getID()); - EXPECT_EQ("2001:db1::/48", sub->toText()); // The subnet has a pool. const PoolCollection& pools = sub->getPools(Lease::TYPE_NA); @@ -7551,7 +8051,6 @@ TEST_F(Dhcp6ParserTest, globalReservations) { "\"valid-lifetime\": 4000 }\n"; ConstElementPtr json; - (json = parseDHCP6(config)); ASSERT_NO_THROW(json = parseDHCP6(config)); extractConfig(config); @@ -7577,6 +8076,7 @@ TEST_F(Dhcp6ParserTest, globalReservations) { for (unsigned int i = 1; i < 7; ++i) { hwaddr.push_back(static_cast(i)); } + // Retrieve the reservation and sanity check the address reserved. ConstHostPtr host = hosts_cfg->get6(SUBNET_ID_GLOBAL, Host::IDENT_HWADDR, &hwaddr[0], hwaddr.size()); @@ -7586,10 +8086,12 @@ TEST_F(Dhcp6ParserTest, globalReservations) { EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:2::abcd")), resrv)); + // This reservation should be solely assigned to the subnet 234, // and not to other two. EXPECT_FALSE(hosts_cfg->get6(123, Host::IDENT_HWADDR, &hwaddr[0], hwaddr.size())); + EXPECT_FALSE(hosts_cfg->get6(542, Host::IDENT_HWADDR, &hwaddr[0], hwaddr.size())); // Check that options are assigned correctly. @@ -7609,6 +8111,8 @@ TEST_F(Dhcp6ParserTest, globalReservations) { for (unsigned int i = 1; i < 0xb; ++i) { duid.push_back(static_cast(i)); } + + // Retrieve the global reservation and sanity check the hostname reserved. host = hosts_cfg->get6(SUBNET_ID_GLOBAL, Host::IDENT_DUID, &duid[0], duid.size()); ASSERT_TRUE(host); resrv = host->getIPv6Reservations(IPv6Resrv::TYPE_NA); @@ -7616,8 +8120,7 @@ TEST_F(Dhcp6ParserTest, globalReservations) { EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:2::1234")), resrv)); - EXPECT_FALSE(hosts_cfg->get6(123, Host::IDENT_DUID, &duid[0], duid.size())); - EXPECT_FALSE(hosts_cfg->get6(542, Host::IDENT_DUID, &duid[0], duid.size())); + // Check that options are assigned correctly. opt_dns = retrieveOption(*host, D6O_NAME_SERVERS); ASSERT_TRUE(opt_dns); @@ -7627,6 +8130,29 @@ TEST_F(Dhcp6ParserTest, globalReservations) { opt_prf = retrieveOption(*host, D6O_PREFERENCE); ASSERT_TRUE(opt_prf); EXPECT_EQ(11, static_cast(opt_prf->getValue())); + + // This reservation should be global solely and not assigned to + // either subnet + EXPECT_FALSE(hosts_cfg->get6(123, Host::IDENT_DUID, &duid[0], duid.size())); + EXPECT_FALSE(hosts_cfg->get6(542, Host::IDENT_DUID, &duid[0], duid.size())); +} + +// Rather than disable these tests they are compiled out. This avoids them +// reporting as disabled and thereby drawing attention to them. +// This test verifies that configuration control with unsupported type fails +TEST_F(Dhcp6ParserTest, configControlInfoNoFactory) { + string config = PARSER_CONFIGS[8]; + + // Unregister "mysql" and ignore the return value. + static_cast(TestConfigBackendDHCPv6:: + unregisterBackendType(ConfigBackendDHCPv6Mgr::instance(), + "mysql")); + + // Should fail because "type=mysql" has no factories. + configure(config, CONTROL_RESULT_ERROR, + "during update from config backend database: " + "The type of the configuration backend: " + "'mysql' is not supported"); } // This test verifies that configuration control info gets populated. @@ -7655,7 +8181,7 @@ TEST_F(Dhcp6ParserTest, configControlInfo) { // alphabetical order). EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", dblist.front().getAccessString()); - EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", + EXPECT_EQ("name=keatest2 password=keatest retry-on-startup=true type=mysql user=keatest", dblist.back().getAccessString()); // Verify that the config-fetch-wait-time is correct. @@ -7666,18 +8192,18 @@ TEST_F(Dhcp6ParserTest, configControlInfo) { // Check whether it is possible to configure server-tag TEST_F(Dhcp6ParserTest, serverTag) { // Config without server-tag - string config_no_tag = "{ " + genIfaceConfig() + "," + + string config_no_tag = "{ " + genIfaceConfig() + "," "\"subnet6\": [ ] " "}"; // Config with server-tag - string config_tag = "{ " + genIfaceConfig() + "," + + string config_tag = "{ " + genIfaceConfig() + "," "\"server-tag\": \"boo\", " "\"subnet6\": [ ] " "}"; // Config with an invalid server-tag - string bad_tag = "{ " + genIfaceConfig() + "," + + string bad_tag = "{ " + genIfaceConfig() + "," "\"server-tag\": 777, " "\"subnet6\": [ ] " "}"; @@ -7707,6 +8233,7 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControl) { std::string json_; std::string mt_json_; }; + std::vector scenarios = { { "no entry", @@ -7892,87 +8419,175 @@ TEST_F(Dhcp6ParserTest, dhcpQueueControlInvalid) { } } -// Verifies the value of store-extended-info for subnets when there -// is a global value defined. -TEST_F(Dhcp6ParserTest, storeExtendedInfoGlobal) { +// Checks inheritence of calculate-tee-times, t1-percent, t2-percent +TEST_F(Dhcp6ParserTest, calculateTeeTimesInheritence) { + // Configure the server. This should succeed. + string config = + "{ \n" + " \"interfaces-config\": { \n" + " \"interfaces\": [\"*\" ] \n" + " }, \n" + " \"valid-lifetime\": 4000, \n" + " \"preferred-lifetime\": 3000," + " \"shared-networks\": [ { \n" + " \"name\": \"foo\", \n" + " \"calculate-tee-times\": true, \n" + " \"t1-percent\": .4, \n" + " \"t2-percent\": .75,\n" + " \"subnet6\": [" + " { " + " \"id\": 100," + " \"subnet\": \"2001:db8:1::/64\", \n" + " \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ], \n" + " \"calculate-tee-times\": false,\n" + " \"t1-percent\": .45, \n" + " \"t2-percent\": .65 \n" + " }, \n" + " { \n" + " \"id\": 200, \n" + " \"subnet\": \"2001:db8:2::/64\", \n" + " \"pools\": [ { \"pool\": \"2001:db8:2::/80\" } ] \n" + " } \n" + " ] \n" + " } ], \n" + " \"subnet6\": [ { \n" + " \"id\": 300, \n" + " \"subnet\":\"2001:db8:3::/64\", \n" + " \"pools\": [ { \"pool\": \"2001:db8:3::/80\" } ]\n" + " } ] \n" + "} \n"; + + extractConfig(config); + configure(config, CONTROL_RESULT_SUCCESS, ""); + + CfgSubnets6Ptr subnets6 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); + + // Subnet 100 should use its own explicit values. + ConstSubnet6Ptr subnet6 = subnets6->getBySubnetId(100); + ASSERT_TRUE(subnet6); + EXPECT_FALSE(subnet6->getCalculateTeeTimes()); + EXPECT_TRUE(util::areDoublesEquivalent(0.45, subnet6->getT1Percent())); + EXPECT_TRUE(util::areDoublesEquivalent(0.65, subnet6->getT2Percent())); + + // Subnet 200 should use the shared-network values. + subnet6 = subnets6->getBySubnetId(200); + ASSERT_TRUE(subnet6); + EXPECT_TRUE(subnet6->getCalculateTeeTimes()); + EXPECT_TRUE(util::areDoublesEquivalent(0.4, subnet6->getT1Percent())); + EXPECT_TRUE(util::areDoublesEquivalent(0.75, subnet6->getT2Percent())); + + // Subnet 300 should use the global values. + subnet6 = subnets6->getBySubnetId(300); + ASSERT_TRUE(subnet6); + EXPECT_TRUE(subnet6->getCalculateTeeTimes()); + EXPECT_TRUE(util::areDoublesEquivalent(0.5, subnet6->getT1Percent())); + EXPECT_TRUE(util::areDoublesEquivalent(0.8, subnet6->getT2Percent())); +} + +// This test checks that the global store-extended-info parameter is optional +// and that values under the subnet are used. +TEST_F(Dhcp6ParserTest, storeExtendedInfoNoGlobal) { const string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " - "\"store-extended-info\": true," "\"subnet6\": [ " - "{ " - " \"id\": 1, " + "{" + " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ]," - " \"subnet\": \"2001:db8:1::/64\"," - " \"store-extended-info\": false" + " \"subnet\": \"2001:db8:1::/64\"" "}," "{" " \"id\": 2, " + " \"store-extended-info\": true," " \"pools\": [ { \"pool\": \"2001:db8:2::1 - 2001:db8:2::ffff\" } ]," - " \"subnet\": \"2001:db8:2::/64\" " + " \"subnet\": \"2001:db8:2::/64\"" "} ]," "\"valid-lifetime\": 4000 }"; - ConstElementPtr json = parseJSON(config); + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); checkResult(status, 0); - // First subnet should override the global value. + // First subnet should use global default. CfgSubnets6Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); Subnet6Ptr subnet = cfg->selectSubnet(IOAddress("2001:db8:1::")); ASSERT_TRUE(subnet); + // Reset the fetch global function to staging (vs current) config. + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + }); EXPECT_FALSE(subnet->getStoreExtendedInfo()); - // Second subnet should use the global value. + // Second subnet should use its own value. subnet = cfg->selectSubnet(IOAddress("2001:db8:2::")); ASSERT_TRUE(subnet); + // Reset the fetch global function to staging (vs current) config. + subnet->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + }); EXPECT_TRUE(subnet->getStoreExtendedInfo()); } -// Verifies the value of store-extended-info for subnets when there -// is no global value defined. -TEST_F(Dhcp6ParserTest, storeExtendedInfoNoGlobal) { +// This test checks that the global store-extended-info parameter is used +// when there is no such parameter under subnet and that the parameter +// specified for a subnet overrides the global setting. +TEST_F(Dhcp6ParserTest, storeExtendedInfoGlobal) { const string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " + "\"store-extended-info\": true," "\"subnet6\": [ " "{ " - " \"id\": 1, " + " \"id\": 1," + " \"store-extended-info\": false," " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ]," " \"subnet\": \"2001:db8:1::/64\"" "}," "{" - " \"id\": 2, " + " \"id\": 2," " \"pools\": [ { \"pool\": \"2001:db8:2::1 - 2001:db8:2::ffff\" } ]," - " \"subnet\": \"2001:db8:2::/64\"," - " \"store-extended-info\": true" + " \"subnet\": \"2001:db8:2::/64\" " "} ]," "\"valid-lifetime\": 4000 }"; - ConstElementPtr json = parseJSON(config); + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP6(config)); + extractConfig(config); + ConstElementPtr status; - EXPECT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); + ASSERT_NO_THROW(status = Dhcpv6SrvTest::configure(srv_, json)); checkResult(status, 0); - // First subnet should use global default. + // First subnet should override the global value. CfgSubnets6Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); - Subnet6Ptr subnet = cfg->selectSubnet(IOAddress("2001:db8:1::")); - ASSERT_TRUE(subnet); - EXPECT_FALSE(subnet->getStoreExtendedInfo()); + Subnet6Ptr subnet1 = cfg->selectSubnet(IOAddress("2001:db8:1::")); + ASSERT_TRUE(subnet1); + // Reset the fetch global function to staging (vs current) config. + subnet1->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + }); + EXPECT_FALSE(subnet1->getStoreExtendedInfo()); - // Second subnet should use its own value. - subnet = cfg->selectSubnet(IOAddress("2001:db8:2::")); - ASSERT_TRUE(subnet); - EXPECT_TRUE(subnet->getStoreExtendedInfo()); + // Second subnet should use the global value. + Subnet6Ptr subnet2 = cfg->selectSubnet(IOAddress("2001:db8:2::")); + ASSERT_TRUE(subnet2); + // Reset the fetch global function to staging (vs current) config. + subnet2->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { + return (CfgMgr::instance().getStagingCfg()->getConfiguredGlobals()); + }); + EXPECT_TRUE(subnet2->getStoreExtendedInfo()); } /// This test checks that the statistic-default-sample-count and age /// global parameters are committed to the stats manager as expected. TEST_F(Dhcp6ParserTest, statsDefaultLimits) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -7998,7 +8613,7 @@ TEST_F(Dhcp6ParserTest, statsDefaultLimits) { // This test checks that using default multi threading settings works. TEST_F(Dhcp6ParserTest, multiThreadingDefaultSettings) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"subnet6\": [ ]" "}"; @@ -8035,7 +8650,7 @@ TEST_F(Dhcp6ParserTest, multiThreadingSettings) { " \"thread-pool-size\": 48,\n" " \"packet-queue-size\": 1024\n" "}"; - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"subnet6\": [ ], " "\"multi-threading\": " + content_json + "}"; @@ -8058,10 +8673,52 @@ TEST_F(Dhcp6ParserTest, multiThreadingSettings) { << " actual: " << *(cfg) << std::endl; } +// Verify that parsing for the global parameter, parked-packet-limit, +// is correct. +TEST_F(Dhcp6ParserTest, parkedPacketLimit) { + // Config without parked-packet-limit + string config_no_limit = "{ " + genIfaceConfig() + "," + "\"subnet6\": [ ] " + "}"; + + // Config with parked-packet-limit + string config_limit = "{ " + genIfaceConfig() + "," + "\"parked-packet-limit\": 777, " + "\"subnet6\": [ ] " + "}"; + + // Config with an invalid parked-packet-limit + string bad_limit = "{ " + genIfaceConfig() + "," + "\"parked-packet-limit\": \"boo\", " + "\"subnet6\": [ ] " + "}"; + + // Should not exist after construction. + ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->getConfiguredGlobal("parked-packet-limit")); + + // Configuration with no limit should default to 256. + configure(config_no_limit, CONTROL_RESULT_SUCCESS, ""); + ConstElementPtr ppl; + ASSERT_TRUE(ppl = CfgMgr::instance().getStagingCfg()->getConfiguredGlobal("parked-packet-limit")); + EXPECT_EQ(256, ppl->intValue()); + + // Clear the config + CfgMgr::instance().clear(); + + // Configuration with the limit should have the limit value. + configure(config_limit, CONTROL_RESULT_SUCCESS, ""); + + ASSERT_TRUE(ppl = CfgMgr::instance().getStagingCfg()->getConfiguredGlobal("parked-packet-limit")); + EXPECT_EQ(777, ppl->intValue()); + + // Make sure an invalid limit fails to parse. + ASSERT_THROW(parseDHCP6(bad_limit), std::exception); +} + // Verifies that client class definitions may specify // valid and preferred lifetime triplets. TEST_F(Dhcp6ParserTest, clientClassValidPreferredLifetime) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"client-classes\" : [ \n" " { \n" " \"name\": \"one\", \n" @@ -8124,7 +8781,7 @@ TEST_F(Dhcp6ParserTest, clientClassValidPreferredLifetime) { // Verifies that template client class definitions may specify // valid and preferred lifetime triplets. TEST_F(Dhcp6ParserTest, templateClientClassValidPreferredLifetime) { - string config = "{ " + genIfaceConfig() + "," + + string config = "{ " + genIfaceConfig() + "," "\"client-classes\" : [ \n" " { \n" " \"name\": \"one\", \n" @@ -8191,17 +8848,17 @@ TEST_F(Dhcp6ParserTest, templateClientClassValidPreferredLifetime) { // This test checks that ddns-conflict-resolution-mode value can be specified at // global and subnet levels. TEST_F(Dhcp6ParserTest, storeDdnsConflictResolutionMode) { - std::string config = "{ " + genIfaceConfig() + "," + + std::string config = "{ " + genIfaceConfig() + "," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " "\"subnet6\": [ " - "{ " + "{" " \"id\": 1," " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ]," " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\"," " \"subnet\": \"2001:db8:1::/64\"" "}," - "{ " + "{" " \"id\": 2," " \"pools\": [ { \"pool\": \"2001:db8:2::1 - 2001:db8:2::ffff\" } ]," " \"ddns-conflict-resolution-mode\": \"check-exists-with-dhcid\"," diff --git a/src/bin/dhcp6/tests/get_config_unittest.cc b/src/bin/dhcp6/tests/get_config_unittest.cc index 83c306f56c..2111763ae2 100644 --- a/src/bin/dhcp6/tests/get_config_unittest.cc +++ b/src/bin/dhcp6/tests/get_config_unittest.cc @@ -9,25 +9,24 @@ #include #include #include -#include -#include #include -#include -#include -#include #include +#include #include #include #include +#include #include - -#include -#include +#include #include -#include -#include #include +#include +#include + +#include + +#include using namespace isc::config; using namespace isc::data; @@ -75,13 +74,53 @@ const char* EXTRACTED_CONFIGS[] = { " \"interfaces\": [ \"*\" ],\n" " \"re-detect\": false\n" " },\n" +" \"rebind-timer\": 2000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8::/64\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8::/32\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 1 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8::/64\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8::/32\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 2 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" " \"preferred-lifetime\": 3000,\n" " \"rebind-timer\": 2000,\n" " \"renew-timer\": 1000,\n" " \"subnet6\": [ ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 1 + // CONFIGURATION 3 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -107,7 +146,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 2 + // CONFIGURATION 4 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -156,7 +195,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 3 + // CONFIGURATION 5 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -205,7 +244,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 4 + // CONFIGURATION 6 "{\n" " \"compatibility\": {\n" " \"lenient-option-parsing\": true\n" @@ -230,7 +269,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 5 + // CONFIGURATION 7 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -264,7 +303,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 6 + // CONFIGURATION 8 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -287,7 +326,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 7 + // CONFIGURATION 9 "{\n" " \"preferred-lifetime\": 3000,\n" " \"rebind-timer\": 2000,\n" @@ -306,7 +345,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 8 + // CONFIGURATION 10 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -343,7 +382,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 9 + // CONFIGURATION 11 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -365,7 +404,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 10 + // CONFIGURATION 12 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -389,7 +428,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 11 + // CONFIGURATION 13 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -415,7 +454,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 12 + // CONFIGURATION 14 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -454,7 +493,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 13 + // CONFIGURATION 15 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -478,7 +517,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 14 + // CONFIGURATION 16 "{\n" " \"option-def\": [\n" " {\n" @@ -489,7 +528,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 15 + // CONFIGURATION 17 "{\n" " \"option-def\": [\n" " {\n" @@ -501,7 +540,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 16 + // CONFIGURATION 18 "{\n" " \"option-def\": [\n" " {\n" @@ -518,7 +557,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 17 + // CONFIGURATION 19 "{\n" " \"option-def\": [\n" " {\n" @@ -530,7 +569,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 18 + // CONFIGURATION 20 "{\n" " \"option-def\": [\n" " {\n" @@ -542,7 +581,29 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 19 + // CONFIGURATION 21 +"{\n" +" \"option-def\": [\n" +" {\n" +" \"code\": 100,\n" +" \"name\": \"foo\",\n" +" \"space\": \"dhcp6\",\n" +" \"type\": \"string\"\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 22 +"{\n" +" \"option-def\": [\n" +" {\n" +" \"code\": 63,\n" +" \"name\": \"geolocation\",\n" +" \"space\": \"dhcp6\",\n" +" \"type\": \"string\"\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 23 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -575,7 +636,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 20 + // CONFIGURATION 24 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -608,7 +669,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 21 + // CONFIGURATION 25 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -650,7 +711,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 22 + // CONFIGURATION 26 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -687,7 +748,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 23 + // CONFIGURATION 27 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -746,7 +807,48 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 24 + // CONFIGURATION 28 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"AB\",\n" +" \"name\": \"subscriber-id\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"name\": \"subscriber-id\"\n" +" },\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\"\n" +" }\n" +" ],\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:1::/64\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 29 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -791,7 +893,41 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 25 + // CONFIGURATION 30 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"0102030405060708090A\",\n" +" \"name\": \"subscriber-id\"\n" +" },\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\"\n" +" }\n" +" ],\n" +" \"pool\": \"2001:db8:1::10 - 2001:db8:1::100\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:1::/64\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 31 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -856,7 +992,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 26 + // CONFIGURATION 32 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -894,7 +1030,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 27 + // CONFIGURATION 33 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -932,7 +1068,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 28 + // CONFIGURATION 34 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\" ],\n" @@ -943,7 +1079,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 29 + // CONFIGURATION 35 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\", \"eth1\", \"*\" ],\n" @@ -954,7 +1090,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 30 + // CONFIGURATION 36 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -971,15 +1107,18 @@ const char* EXTRACTED_CONFIGS[] = { " \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\"\n" " }\n" " ],\n" +" \"rebind-timer\": 2,\n" " \"relay\": {\n" " \"ip-addresses\": [ \"2001:db8:1::abcd\" ]\n" " },\n" -" \"subnet\": \"2001:db8:1::/64\"\n" +" \"renew-timer\": 1,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"valid-lifetime\": 4\n" " }\n" " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 37 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -996,15 +1135,18 @@ const char* EXTRACTED_CONFIGS[] = { " \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\"\n" " }\n" " ],\n" +" \"rebind-timer\": 2,\n" " \"relay\": {\n" " \"ip-addresses\": [ \"2001:db9::abcd\", \"2001:db9::abce\" ]\n" " },\n" -" \"subnet\": \"2001:db8:1::/64\"\n" +" \"renew-timer\": 1,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"valid-lifetime\": 4\n" " }\n" " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 38 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1056,7 +1198,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 39 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1090,7 +1232,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 40 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1132,7 +1274,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 41 "{\n" " \"dhcp-ddns\": {\n" " \"enable-updates\": true,\n" @@ -1164,7 +1306,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 42 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1251,7 +1393,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 43 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1291,7 +1433,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 44 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1304,7 +1446,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"subnet6\": [ ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 39 + // CONFIGURATION 45 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1317,7 +1459,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"subnet6\": [ ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 40 + // CONFIGURATION 46 "{\n" " \"preferred-lifetime\": 3000,\n" " \"rebind-timer\": 2000,\n" @@ -1405,7 +1547,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 41 + // CONFIGURATION 47 "{\n" " \"preferred-lifetime\": 3000,\n" " \"rebind-timer\": 2000,\n" @@ -1438,7 +1580,15 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 42 + // CONFIGURATION 48 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"subnet6\": [ ]\n" +" }\n", + // CONFIGURATION 49 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1451,7 +1601,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"subnet6\": [ ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 50 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1459,15 +1609,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet6\": [ ]\n" " }\n", - // CONFIGURATION 44 -"{\n" -" \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" -" \"re-detect\": false\n" -" },\n" -" \"subnet6\": [ ]\n" -" }\n", - // CONFIGURATION 45 + // CONFIGURATION 51 "{\n" " \"decline-probation-period\": 12345,\n" " \"interfaces-config\": {\n" @@ -1476,7 +1618,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet6\": [ ]\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 52 "{\n" " \"expired-leases-processing\": {\n" " \"flush-reclaimed-timer-wait-time\": 35,\n" @@ -1492,7 +1634,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet6\": [ ]\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 53 "{\n" " \"client-classes\": [\n" " {\n" @@ -1525,7 +1667,67 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 54 +"{\n" +" \"client-classes\": [\n" +" {\n" +" \"max-valid-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 1000,\n" +" \"name\": \"one\",\n" +" \"valid-lifetime\": 2000\n" +" },\n" +" {\n" +" \"name\": \"two\"\n" +" }\n" +" ],\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8::1 - 2001:db8::ffff\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8::/64\"\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 55 +"{\n" +" \"client-classes\": [\n" +" {\n" +" \"max-valid-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 1000,\n" +" \"name\": \"one\",\n" +" \"template-test\": \"''\",\n" +" \"valid-lifetime\": 2000\n" +" },\n" +" {\n" +" \"name\": \"two\",\n" +" \"template-test\": \"''\"\n" +" }\n" +" ],\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8::1 - 2001:db8::ffff\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8::/64\"\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 56 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1547,7 +1749,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 57 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1570,7 +1772,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 58 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1598,7 +1800,35 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 59 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8::/64\",\n" +" \"user-context\": {\n" +" \"lw4over6-bind-prefix-len\": 56,\n" +" \"lw4over6-sharing-ratio\": 64,\n" +" \"lw4over6-sysports-exclude\": true,\n" +" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" +" }\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8::/32\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 60 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1626,7 +1856,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 61 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1650,7 +1880,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 62 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1675,7 +1905,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 63 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1705,7 +1935,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 55 + // CONFIGURATION 64 "{\n" " \"hosts-databases\": [\n" " {\n" @@ -1717,6 +1947,7 @@ const char* EXTRACTED_CONFIGS[] = { " {\n" " \"name\": \"keatest2\",\n" " \"password\": \"keatest\",\n" +" \"retry-on-startup\": true,\n" " \"type\": \"mysql\",\n" " \"user\": \"keatest\"\n" " }\n" @@ -1730,7 +1961,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 56 + // CONFIGURATION 65 "{\n" " \"client-classes\": [\n" " {\n" @@ -1855,7 +2086,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"comment\": \"A DHCPv6 server\"\n" " }\n" " }\n", - // CONFIGURATION 57 + // CONFIGURATION 66 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1920,7 +2151,123 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 58 + // CONFIGURATION 67 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"preferred-lifetime\": 3000,\n" +" \"shared-networks\": [\n" +" {\n" +" \"calculate-tee-times\": true,\n" +" \"name\": \"foo\",\n" +" \"subnet6\": [\n" +" {\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 100,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.45,\n" +" \"t2-percent\": 0.65\n" +" },\n" +" {\n" +" \"id\": 200,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:2::/80\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:2::/64\"\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.4,\n" +" \"t2-percent\": 0.75\n" +" }\n" +" ],\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 300,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:3::/80\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:3::/64\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 68 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:1::/64\"\n" +" },\n" +" {\n" +" \"id\": 2,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:2::1 - 2001:db8:2::ffff\"\n" +" }\n" +" ],\n" +" \"store-extended-info\": true,\n" +" \"subnet\": \"2001:db8:2::/64\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 69 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"store-extended-info\": true,\n" +" \"subnet6\": [\n" +" {\n" +" \"id\": 1,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\"\n" +" }\n" +" ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\"\n" +" },\n" +" {\n" +" \"id\": 2,\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"2001:db8:2::1 - 2001:db8:2::ffff\"\n" +" }\n" +" ],\n" +" \"subnet\": \"2001:db8:2::/64\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 70 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1933,7 +2280,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"statistic-default-sample-count\": 10,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 59 + // CONFIGURATION 71 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1941,7 +2288,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet6\": [ ]\n" " }\n", - // CONFIGURATION 60 + // CONFIGURATION 72 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" @@ -1954,7 +2301,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet6\": [ ]\n" " }\n", - // CONFIGURATION 61 + // CONFIGURATION 73 "{\n" " \"client-classes\": [\n" " {\n" @@ -1986,7 +2333,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 62 + // CONFIGURATION 74 "{\n" " \"client-classes\": [\n" " {\n" @@ -2020,7 +2367,7 @@ const char* EXTRACTED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 63 + // CONFIGURATION 75 "{\n" " \"ddns-conflict-resolution-mode\": \"no-check-with-dhcid\",\n" " \"interfaces-config\": {\n" @@ -2146,10 +2493,8 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" -" \"preferred-lifetime\": 3000,\n" " \"rebind-timer\": 2000,\n" " \"relay-supplied-options\": [ \"65\" ],\n" -" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -2171,7 +2516,35 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [ ],\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8::/64\"\n" +" }\n" +" ],\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8::/32\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" @@ -2227,8 +2600,214 @@ const char* UNPARSED_CONFIGS[] = { " \"type\": \"memfile\"\n" " },\n" " \"mac-sources\": [ \"any\" ],\n" -" \"max-preferred-lifetime\": 4000,\n" -" \"max-valid-lifetime\": 5000,\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8::/64\"\n" +" }\n" +" ],\n" +" \"rapid-commit\": false,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8::/32\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 2 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [ ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 3 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"max-preferred-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 5000,\n" " \"min-preferred-lifetime\": 2000,\n" " \"min-valid-lifetime\": 3000,\n" " \"multi-threading\": {\n" @@ -2302,7 +2881,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 2 + // CONFIGURATION 4 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -2517,7 +3096,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 3 + // CONFIGURATION 5 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -2732,7 +3311,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 4 + // CONFIGURATION 6 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -2857,7 +3436,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 5 + // CONFIGURATION 7 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -2983,7 +3562,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 6 + // CONFIGURATION 8 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3106,7 +3685,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 7 + // CONFIGURATION 9 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3229,7 +3808,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 8 + // CONFIGURATION 10 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3390,7 +3969,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 9 + // CONFIGURATION 11 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3512,7 +4091,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 10 + // CONFIGURATION 12 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3636,7 +4215,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 11 + // CONFIGURATION 13 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3762,7 +4341,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 12 + // CONFIGURATION 14 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -3903,7 +4482,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 13 + // CONFIGURATION 15 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4027,7 +4606,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 14 + // CONFIGURATION 16 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4124,7 +4703,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 15 + // CONFIGURATION 17 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4221,7 +4800,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 16 + // CONFIGURATION 18 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4327,7 +4906,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 17 + // CONFIGURATION 19 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4424,7 +5003,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 18 + // CONFIGURATION 20 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4521,7 +5100,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 19 + // CONFIGURATION 21 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4564,7 +5143,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" +" \"interfaces\": [ ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -4577,15 +5156,209 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [\n" +" \"option-data\": [ ],\n" +" \"option-def\": [\n" " {\n" -" \"always-send\": false,\n" -" \"code\": 38,\n" -" \"csv-format\": false,\n" -" \"data\": \"ABCDEF0105\",\n" -" \"name\": \"subscriber-id\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" +" \"array\": false,\n" +" \"code\": 100,\n" +" \"encapsulate\": \"\",\n" +" \"name\": \"foo\",\n" +" \"record-types\": \"\",\n" +" \"space\": \"dhcp6\",\n" +" \"type\": \"string\"\n" +" }\n" +" ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"relay-supplied-options\": [ \"65\" ],\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [ ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 7200\n" +" }\n", + // CONFIGURATION 22 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [\n" +" {\n" +" \"array\": false,\n" +" \"code\": 63,\n" +" \"encapsulate\": \"\",\n" +" \"name\": \"geolocation\",\n" +" \"record-types\": \"\",\n" +" \"space\": \"dhcp6\",\n" +" \"type\": \"string\"\n" +" }\n" +" ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"relay-supplied-options\": [ \"65\" ],\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [ ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 7200\n" +" }\n", + // CONFIGURATION 23 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" " },\n" " {\n" " \"always-send\": false,\n" @@ -4662,7 +5435,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 20 + // CONFIGURATION 24 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4803,7 +5576,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 21 + // CONFIGURATION 25 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -4954,7 +5727,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 22 + // CONFIGURATION 26 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5082,7 +5855,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 23 + // CONFIGURATION 27 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5260,7 +6033,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 24 + // CONFIGURATION 28 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5316,7 +6089,17 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [ ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"AB\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" @@ -5359,10 +6142,19 @@ const char* UNPARSED_CONFIGS[] = { " \"always-send\": false,\n" " \"code\": 38,\n" " \"csv-format\": false,\n" -" \"data\": \"0102030405060708090A\",\n" +" \"data\": \"ABCDEF0105\",\n" " \"name\": \"subscriber-id\",\n" " \"never-send\": false,\n" " \"space\": \"dhcp6\"\n" +" },\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 15,\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" " }\n" " ],\n" " \"pd-allocator\": \"iterative\",\n" @@ -5386,54 +6178,13 @@ const char* UNPARSED_CONFIGS[] = { " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" -" },\n" -" {\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"id\": 2,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 15,\n" -" \"csv-format\": false,\n" -" \"data\": \"FFFEFDFCFB\",\n" -" \"name\": \"user-class\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:2::/80\"\n" -" }\n" -" ],\n" -" \"preferred-lifetime\": 3000,\n" -" \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:2::/64\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 25 + // CONFIGURATION 29 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5527,70 +6278,64 @@ const char* UNPARSED_CONFIGS[] = { " \"max-valid-lifetime\": 4000,\n" " \"min-preferred-lifetime\": 3000,\n" " \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"0102030405060708090A\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" " \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" " {\n" -" \"delegated-len\": 64,\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 38,\n" -" \"csv-format\": false,\n" -" \"data\": \"112233445566\",\n" -" \"name\": \"subscriber-id\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"prefix\": \"3000::\",\n" -" \"prefix-len\": 48\n" -" },\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 2,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [\n" " {\n" -" \"delegated-len\": 64,\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 15,\n" -" \"csv-format\": false,\n" -" \"data\": \"AABBCCDDEE\",\n" -" \"name\": \"user-class\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"prefix\": \"3001::\",\n" -" \"prefix-len\": 48\n" +" \"always-send\": false,\n" +" \"code\": 15,\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" " }\n" " ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" " \"pools\": [\n" " {\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 38,\n" -" \"csv-format\": false,\n" -" \"data\": \"0102030405060708090A\",\n" -" \"name\": \"subscriber-id\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"pool\": \"2001:db8:1::10-2001:db8:1::100\"\n" -" },\n" -" {\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 15,\n" -" \"csv-format\": false,\n" -" \"data\": \"FFFEFDFCFB\",\n" -" \"name\": \"user-class\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"pool\": \"2001:db8:1::300-2001:db8:1::400\"\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:2::/80\"\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" @@ -5602,7 +6347,7 @@ const char* UNPARSED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:1::/64\",\n" +" \"subnet\": \"2001:db8:2::/64\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" @@ -5612,7 +6357,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 26 + // CONFIGURATION 30 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5668,24 +6413,7 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 100,\n" -" \"csv-format\": false,\n" -" \"data\": \"1234\",\n" -" \"never-send\": false,\n" -" \"space\": \"vendor-1234\"\n" -" },\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 100,\n" -" \"csv-format\": false,\n" -" \"data\": \"ABCDEF0105\",\n" -" \"never-send\": false,\n" -" \"space\": \"vendor-4491\"\n" -" }\n" -" ],\n" +" \"option-data\": [ ],\n" " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" @@ -5728,8 +6456,27 @@ const char* UNPARSED_CONFIGS[] = { " \"pd-pools\": [ ],\n" " \"pools\": [\n" " {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::/80\"\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"0102030405060708090A\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" },\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 15,\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"pool\": \"2001:db8:1::10-2001:db8:1::100\"\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" @@ -5751,7 +6498,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 27 + // CONFIGURATION 31 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -5807,28 +6554,8 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 100,\n" -" \"csv-format\": true,\n" -" \"data\": \"this is a string vendor-opt\",\n" -" \"name\": \"foo\",\n" -" \"never-send\": false,\n" -" \"space\": \"vendor-4491\"\n" -" }\n" -" ],\n" -" \"option-def\": [\n" -" {\n" -" \"array\": false,\n" -" \"code\": 100,\n" -" \"encapsulate\": \"\",\n" -" \"name\": \"foo\",\n" -" \"record-types\": \"\",\n" -" \"space\": \"vendor-4491\",\n" -" \"type\": \"string\"\n" -" }\n" -" ],\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" " \"preferred-lifetime\": 3000,\n" @@ -5867,37 +6594,94 @@ const char* UNPARSED_CONFIGS[] = { " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [ ],\n" -" \"pools\": [\n" +" \"pd-pools\": [\n" " {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::/80\"\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"112233445566\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"prefix\": \"3000::\",\n" +" \"prefix-len\": 48\n" +" },\n" +" {\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 15,\n" +" \"csv-format\": false,\n" +" \"data\": \"AABBCCDDEE\",\n" +" \"name\": \"user-class\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"prefix\": \"3001::\",\n" +" \"prefix-len\": 48\n" " }\n" " ],\n" -" \"preferred-lifetime\": 3000,\n" -" \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:1::/64\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" -" }\n" -" ],\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" -" }\n", - // CONFIGURATION 28 -"{\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"0102030405060708090A\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"pool\": \"2001:db8:1::10-2001:db8:1::100\"\n" +" },\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 15,\n" +" \"csv-format\": false,\n" +" \"data\": \"FFFEFDFCFB\",\n" +" \"name\": \"user-class\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"pool\": \"2001:db8:1::300-2001:db8:1::400\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 32 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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" @@ -5936,7 +6720,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"eth0\" ],\n" +" \"interfaces\": [ \"*\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -5949,7 +6733,24 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [ ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 100,\n" +" \"csv-format\": false,\n" +" \"data\": \"1234\",\n" +" \"never-send\": false,\n" +" \"space\": \"vendor-1234\"\n" +" },\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 100,\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"never-send\": false,\n" +" \"space\": \"vendor-4491\"\n" +" }\n" +" ],\n" " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" @@ -5978,12 +6779,44 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [ ],\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 29 + // CONFIGURATION 33 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6026,7 +6859,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\", \"eth0\", \"eth1\" ],\n" +" \"interfaces\": [ \"*\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -6039,8 +6872,28 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [ ],\n" -" \"option-def\": [ ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 100,\n" +" \"csv-format\": true,\n" +" \"data\": \"this is a string vendor-opt\",\n" +" \"name\": \"foo\",\n" +" \"never-send\": false,\n" +" \"space\": \"vendor-4491\"\n" +" }\n" +" ],\n" +" \"option-def\": [\n" +" {\n" +" \"array\": false,\n" +" \"code\": 100,\n" +" \"encapsulate\": \"\",\n" +" \"name\": \"foo\",\n" +" \"record-types\": \"\",\n" +" \"space\": \"vendor-4491\",\n" +" \"type\": \"string\"\n" +" }\n" +" ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" " \"preferred-lifetime\": 3000,\n" @@ -6068,12 +6921,44 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [ ],\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 30 + // CONFIGURATION 34 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6116,7 +7001,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" +" \"interfaces\": [ \"eth0\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -6158,44 +7043,12 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [\n" -" {\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"id\": 1,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" -" }\n" -" ],\n" -" \"preferred-lifetime\": 3000,\n" -" \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ \"2001:db8:1::abcd\" ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:1::/64\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" -" }\n" -" ],\n" +" \"subnet6\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 35 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6238,7 +7091,7 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" -" \"interfaces\": [ \"*\" ],\n" +" \"interfaces\": [ \"*\", \"eth0\", \"eth1\" ],\n" " \"re-detect\": false\n" " },\n" " \"ip-reservations-unique\": true,\n" @@ -6280,44 +7133,12 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [\n" -" {\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"id\": 1,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [ ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" -" }\n" -" ],\n" -" \"preferred-lifetime\": 3000,\n" -" \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ \"2001:db9::abcd\", \"2001:db9::abce\" ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:1::/64\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" -" }\n" -" ],\n" +" \"subnet6\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 36 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6406,24 +7227,268 @@ const char* UNPARSED_CONFIGS[] = { " {\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" -" \"client-class\": \"alpha\",\n" " \"id\": 1,\n" " \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 4,\n" " \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" +" \"min-valid-lifetime\": 4,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" " \"pd-pools\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::/80\"\n" +" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" +" \"rebind-timer\": 2,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ \"2001:db8:1::abcd\" ]\n" +" },\n" +" \"renew-timer\": 1,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 37 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ \"2001:db9::abcd\", \"2001:db9::abce\" ]\n" +" },\n" +" \"renew-timer\": 1,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 38 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"client-class\": \"alpha\",\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" @@ -6535,7 +7600,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 39 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6672,7 +7737,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 40 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6817,7 +7882,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 41 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -6939,7 +8004,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 42 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -7204,7 +8269,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 43 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -7350,7 +8415,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 44 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -7440,7 +8505,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 39 + // CONFIGURATION 45 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -7530,7 +8595,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 40 + // CONFIGURATION 46 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -7854,7 +8919,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 41 + // CONFIGURATION 47 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8010,7 +9075,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 42 + // CONFIGURATION 48 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8070,10 +9135,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" -" \"preferred-lifetime\": 3000,\n" -" \"rebind-timer\": 2000,\n" -" \"relay-supplied-options\": [ \"23\", \"37\", \"65\" ],\n" -" \"renew-timer\": 1000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -8098,9 +9160,9 @@ const char* UNPARSED_CONFIGS[] = { " \"subnet6\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 49 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8160,7 +9222,10 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" -" \"relay-supplied-options\": [ \"65\" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"23\", \"37\", \"65\" ],\n" +" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -8185,9 +9250,9 @@ const char* UNPARSED_CONFIGS[] = { " \"subnet6\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 7200\n" +" \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 44 + // CONFIGURATION 50 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8274,7 +9339,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 45 + // CONFIGURATION 51 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8361,7 +9426,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 52 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8448,7 +9513,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 53 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8584,10 +9649,23 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 54 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" +" \"client-classes\": [\n" +" {\n" +" \"max-valid-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 1000,\n" +" \"name\": \"one\",\n" +" \"option-data\": [ ],\n" +" \"valid-lifetime\": 2000\n" +" },\n" +" {\n" +" \"name\": \"two\",\n" +" \"option-data\": [ ]\n" +" }\n" +" ],\n" " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" " \"ddns-generated-prefix\": \"myhost\",\n" " \"ddns-override-client-update\": false,\n" @@ -8644,10 +9722,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" -" \"preferred-lifetime\": 3000,\n" -" \"rebind-timer\": 2000,\n" " \"relay-supplied-options\": [ \"65\" ],\n" -" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -8674,42 +9749,52 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" " \"id\": 1,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 7200,\n" +" \"min-valid-lifetime\": 7200,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" " \"pd-pools\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"2001:db8::/64\"\n" +" \"pool\": \"2001:db8::1-2001:db8::ffff\"\n" " }\n" " ],\n" -" \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" -" \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8::/32\",\n" +" \"subnet\": \"2001:db8::/64\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 7200\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 55 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" +" \"client-classes\": [\n" +" {\n" +" \"max-valid-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 1000,\n" +" \"name\": \"one\",\n" +" \"option-data\": [ ],\n" +" \"template-test\": \"''\",\n" +" \"valid-lifetime\": 2000\n" +" },\n" +" {\n" +" \"name\": \"two\",\n" +" \"option-data\": [ ],\n" +" \"template-test\": \"''\"\n" +" }\n" +" ],\n" " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" " \"ddns-generated-prefix\": \"myhost\",\n" " \"ddns-override-client-update\": false,\n" @@ -8766,10 +9851,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" -" \"preferred-lifetime\": 3000,\n" -" \"rebind-timer\": 2000,\n" " \"relay-supplied-options\": [ \"65\" ],\n" -" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -8796,40 +9878,34 @@ const char* UNPARSED_CONFIGS[] = { " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" " \"id\": 1,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" +" \"max-valid-lifetime\": 7200,\n" +" \"min-valid-lifetime\": 7200,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" " \"pd-pools\": [ ],\n" " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"2001:db8::/64\",\n" -" \"user-context\": { }\n" +" \"pool\": \"2001:db8::1-2001:db8::ffff\"\n" " }\n" " ],\n" -" \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" -" \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8::/32\",\n" +" \"subnet\": \"2001:db8::/64\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 7200\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" +" \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 56 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -8929,13 +10005,7 @@ const char* UNPARSED_CONFIGS[] = { " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"2001:db8::/64\",\n" -" \"user-context\": {\n" -" \"lw4over6-bind-prefix-len\": 56,\n" -" \"lw4over6-sharing-ratio\": 64,\n" -" \"lw4over6-sysports-exclude\": true,\n" -" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" -" }\n" +" \"pool\": \"2001:db8::/64\"\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" @@ -8957,7 +10027,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 57 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9058,12 +10128,7 @@ const char* UNPARSED_CONFIGS[] = { " {\n" " \"option-data\": [ ],\n" " \"pool\": \"2001:db8::/64\",\n" -" \"user-context\": {\n" -" \"lw4over6-bind-prefix-len\": 56,\n" -" \"lw4over6-sharing-ratio\": 64,\n" -" \"lw4over6-sysports-exclude\": true,\n" -" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" -" }\n" +" \"user-context\": { }\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" @@ -9085,7 +10150,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 58 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9181,15 +10246,19 @@ const char* UNPARSED_CONFIGS[] = { " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" " {\n" -" \"delegated-len\": 64,\n" " \"option-data\": [ ],\n" -" \"prefix\": \"2001:db8::\",\n" -" \"prefix-len\": 56\n" +" \"pool\": \"2001:db8::/64\",\n" +" \"user-context\": {\n" +" \"lw4over6-bind-prefix-len\": 56,\n" +" \"lw4over6-sharing-ratio\": 64,\n" +" \"lw4over6-sysports-exclude\": true,\n" +" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" +" }\n" " }\n" " ],\n" -" \"pools\": [ ],\n" " \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 2000,\n" @@ -9209,7 +10278,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 59 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9305,16 +10374,19 @@ const char* UNPARSED_CONFIGS[] = { " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" " {\n" -" \"delegated-len\": 64,\n" " \"option-data\": [ ],\n" -" \"prefix\": \"2001:db8::\",\n" -" \"prefix-len\": 56,\n" -" \"user-context\": { }\n" +" \"pool\": \"2001:db8::/64\",\n" +" \"user-context\": {\n" +" \"lw4over6-bind-prefix-len\": 56,\n" +" \"lw4over6-sharing-ratio\": 64,\n" +" \"lw4over6-sysports-exclude\": true,\n" +" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" +" }\n" " }\n" " ],\n" -" \"pools\": [ ],\n" " \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 2000,\n" @@ -9334,7 +10406,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 60 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9430,12 +10502,11 @@ const char* UNPARSED_CONFIGS[] = { " \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" " {\n" -" \"delegated-len\": 64,\n" " \"option-data\": [ ],\n" -" \"prefix\": \"2001:db8::\",\n" -" \"prefix-len\": 56,\n" +" \"pool\": \"2001:db8::/64\",\n" " \"user-context\": {\n" " \"lw4over6-bind-prefix-len\": 56,\n" " \"lw4over6-sharing-ratio\": 64,\n" @@ -9444,7 +10515,6 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " }\n" " ],\n" -" \"pools\": [ ],\n" " \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 2000,\n" @@ -9464,7 +10534,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 55 + // CONFIGURATION 61 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9506,20 +10576,6 @@ const char* UNPARSED_CONFIGS[] = { " \"host-reservation-identifiers\": [ \"hw-address\", \"duid\" ],\n" " \"hostname-char-replacement\": \"\",\n" " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" -" \"hosts-databases\": [\n" -" {\n" -" \"name\": \"keatest1\",\n" -" \"password\": \"keatest\",\n" -" \"type\": \"mysql\",\n" -" \"user\": \"keatest\"\n" -" },\n" -" {\n" -" \"name\": \"keatest2\",\n" -" \"password\": \"keatest\",\n" -" \"type\": \"mysql\",\n" -" \"user\": \"keatest\"\n" -" }\n" -" ],\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" " \"re-detect\": false\n" @@ -9563,44 +10619,49 @@ const char* UNPARSED_CONFIGS[] = { " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [ ],\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [\n" +" {\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [ ],\n" +" \"prefix\": \"2001:db8::\",\n" +" \"prefix-len\": 56\n" +" }\n" +" ],\n" +" \"pools\": [ ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8::/32\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 56 + // CONFIGURATION 62 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" -" \"client-classes\": [\n" -" {\n" -" \"name\": \"all\",\n" -" \"option-data\": [ ],\n" -" \"test\": \"'' == ''\",\n" -" \"user-context\": {\n" -" \"comment\": \"match all\"\n" -" }\n" -" },\n" -" {\n" -" \"name\": \"none\",\n" -" \"option-data\": [ ]\n" -" },\n" -" {\n" -" \"name\": \"both\",\n" -" \"option-data\": [ ],\n" -" \"user-context\": {\n" -" \"comment\": \"a comment\",\n" -" \"version\": 1\n" -" }\n" -" }\n" -" ],\n" -" \"control-socket\": {\n" -" \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n" -" \"socket-type\": \"unix\",\n" -" \"user-context\": {\n" -" \"comment\": \"Indirect comment\"\n" -" }\n" -" },\n" " \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n" " \"ddns-generated-prefix\": \"myhost\",\n" " \"ddns-override-client-update\": false,\n" @@ -9618,10 +10679,7 @@ const char* UNPARSED_CONFIGS[] = { " \"sender-ip\": \"0.0.0.0\",\n" " \"sender-port\": 0,\n" " \"server-ip\": \"127.0.0.1\",\n" -" \"server-port\": 53001,\n" -" \"user-context\": {\n" -" \"comment\": \"No dynamic DNS\"\n" -" }\n" +" \"server-port\": 53001\n" " },\n" " \"dhcp-queue-control\": {\n" " \"capacity\": 64,\n" @@ -9644,10 +10702,840 @@ const char* UNPARSED_CONFIGS[] = { " \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ],\n" -" \"re-detect\": false,\n" -" \"user-context\": {\n" -" \"comment\": \"Use wildcard\"\n" -" }\n" +" \"re-detect\": false\n" +" },\n" +" \"ip-reservations-unique\": true,\n" +" \"lease-database\": {\n" +" \"type\": \"memfile\"\n" +" },\n" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [\n" +" {\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [ ],\n" +" \"prefix\": \"2001:db8::\",\n" +" \"prefix-len\": 56,\n" +" \"user-context\": { }\n" +" }\n" +" ],\n" +" \"pools\": [ ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8::/32\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 63 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [\n" +" {\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [ ],\n" +" \"prefix\": \"2001:db8::\",\n" +" \"prefix-len\": 56,\n" +" \"user-context\": {\n" +" \"lw4over6-bind-prefix-len\": 56,\n" +" \"lw4over6-sharing-ratio\": 64,\n" +" \"lw4over6-sysports-exclude\": true,\n" +" \"lw4over6-v4-pool\": \"192.0.2.0/24\"\n" +" }\n" +" }\n" +" ],\n" +" \"pools\": [ ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8::/32\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 64 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\n" +" \"hostname-char-replacement\": \"\",\n" +" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" +" \"hosts-databases\": [\n" +" {\n" +" \"name\": \"keatest1\",\n" +" \"password\": \"keatest\",\n" +" \"type\": \"mysql\",\n" +" \"user\": \"keatest\"\n" +" },\n" +" {\n" +" \"name\": \"keatest2\",\n" +" \"password\": \"keatest\",\n" +" \"retry-on-startup\": true,\n" +" \"type\": \"mysql\",\n" +" \"user\": \"keatest\"\n" +" }\n" +" ],\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false\n" +" },\n" +" \"ip-reservations-unique\": true,\n" +" \"lease-database\": {\n" +" \"type\": \"memfile\"\n" +" },\n" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [ ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 65 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"client-classes\": [\n" +" {\n" +" \"name\": \"all\",\n" +" \"option-data\": [ ],\n" +" \"test\": \"'' == ''\",\n" +" \"user-context\": {\n" +" \"comment\": \"match all\"\n" +" }\n" +" },\n" +" {\n" +" \"name\": \"none\",\n" +" \"option-data\": [ ]\n" +" },\n" +" {\n" +" \"name\": \"both\",\n" +" \"option-data\": [ ],\n" +" \"user-context\": {\n" +" \"comment\": \"a comment\",\n" +" \"version\": 1\n" +" }\n" +" }\n" +" ],\n" +" \"control-socket\": {\n" +" \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n" +" \"socket-type\": \"unix\",\n" +" \"user-context\": {\n" +" \"comment\": \"Indirect comment\"\n" +" }\n" +" },\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-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" +" \"user-context\": {\n" +" \"comment\": \"No dynamic DNS\"\n" +" }\n" +" },\n" +" \"dhcp-queue-control\": {\n" +" \"capacity\": 64,\n" +" \"enable-queue\": false,\n" +" \"queue-type\": \"kea-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\n" +" \"hostname-char-replacement\": \"\",\n" +" \"hostname-char-set\": \"[^A-Za-z0-9.-]\",\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ],\n" +" \"re-detect\": false,\n" +" \"user-context\": {\n" +" \"comment\": \"Use wildcard\"\n" +" }\n" +" },\n" +" \"ip-reservations-unique\": true,\n" +" \"lease-database\": {\n" +" \"type\": \"memfile\"\n" +" },\n" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 38,\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"name\": \"subscriber-id\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\",\n" +" \"user-context\": {\n" +" \"comment\": \"Set option value\"\n" +" }\n" +" }\n" +" ],\n" +" \"option-def\": [\n" +" {\n" +" \"array\": false,\n" +" \"code\": 100,\n" +" \"encapsulate\": \"\",\n" +" \"name\": \"foo\",\n" +" \"record-types\": \"\",\n" +" \"space\": \"isc\",\n" +" \"type\": \"ipv6-address\",\n" +" \"user-context\": {\n" +" \"comment\": \"An option definition\"\n" +" }\n" +" }\n" +" ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"relay-supplied-options\": [ \"65\" ],\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LL\",\n" +" \"user-context\": {\n" +" \"comment\": \"DHCPv6 specific\"\n" +" }\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"max-valid-lifetime\": 7200,\n" +" \"min-valid-lifetime\": 7200,\n" +" \"name\": \"foo\",\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"rapid-commit\": false,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 100,\n" +" \"max-valid-lifetime\": 7200,\n" +" \"min-valid-lifetime\": 7200,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [\n" +" {\n" +" \"delegated-len\": 64,\n" +" \"option-data\": [ ],\n" +" \"prefix\": \"2001:db2::\",\n" +" \"prefix-len\": 48,\n" +" \"user-context\": {\n" +" \"comment\": \"A prefix pool\"\n" +" }\n" +" }\n" +" ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db1::/64\",\n" +" \"user-context\": {\n" +" \"comment\": \"A pool\"\n" +" }\n" +" }\n" +" ],\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [\n" +" {\n" +" \"client-classes\": [ ],\n" +" \"hostname\": \"foo.example.com\",\n" +" \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n" +" \"ip-addresses\": [ ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 24,\n" +" \"csv-format\": true,\n" +" \"data\": \"example.com\",\n" +" \"name\": \"domain-search\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\",\n" +" \"user-context\": {\n" +" \"comment\": \"An option in a reservation\"\n" +" }\n" +" }\n" +" ],\n" +" \"prefixes\": [ ],\n" +" \"user-context\": {\n" +" \"comment\": \"A host reservation\"\n" +" }\n" +" }\n" +" ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db1::/48\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"user-context\": {\n" +" \"comment\": \"A subnet\"\n" +" },\n" +" \"valid-lifetime\": 7200\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"user-context\": {\n" +" \"comment\": \"A shared network\"\n" +" },\n" +" \"valid-lifetime\": 7200\n" +" }\n" +" ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [ ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"user-context\": {\n" +" \"comment\": \"A DHCPv6 server\"\n" +" },\n" +" \"valid-lifetime\": 7200\n" +" }\n", + // CONFIGURATION 66 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" +" \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [\n" +" {\n" +" \"client-classes\": [ ],\n" +" \"hostname\": \"\",\n" +" \"hw-address\": \"01:02:03:04:05:06\",\n" +" \"ip-addresses\": [ \"2001:db8:2::abcd\" ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 23,\n" +" \"csv-format\": true,\n" +" \"data\": \"2001:db8:2::abbc\",\n" +" \"name\": \"dns-servers\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" },\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 7,\n" +" \"csv-format\": true,\n" +" \"data\": \"25\",\n" +" \"name\": \"preference\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"prefixes\": [ ]\n" +" },\n" +" {\n" +" \"client-classes\": [ ],\n" +" \"duid\": \"01:02:03:04:05:06:07:08:09:0a\",\n" +" \"hostname\": \"\",\n" +" \"ip-addresses\": [ \"2001:db8:2::1234\" ],\n" +" \"option-data\": [\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 23,\n" +" \"csv-format\": true,\n" +" \"data\": \"2001:db8:2::1111\",\n" +" \"name\": \"dns-servers\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" },\n" +" {\n" +" \"always-send\": false,\n" +" \"code\": 7,\n" +" \"csv-format\": true,\n" +" \"data\": \"11\",\n" +" \"name\": \"preference\",\n" +" \"never-send\": false,\n" +" \"space\": \"dhcp6\"\n" +" }\n" +" ],\n" +" \"prefixes\": [ ]\n" +" }\n" +" ],\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 123,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 234,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [ ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:2::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 542,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [ ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:3::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 67 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" @@ -9659,37 +11547,211 @@ const char* UNPARSED_CONFIGS[] = { " \"packet-queue-size\": 64,\n" " \"thread-pool-size\": 0\n" " },\n" -" \"option-data\": [\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"parked-packet-limit\": 256,\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"relay-supplied-options\": [ \"65\" ],\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-id\": {\n" +" \"enterprise-id\": 0,\n" +" \"htype\": 0,\n" +" \"identifier\": \"\",\n" +" \"persist\": true,\n" +" \"time\": 0,\n" +" \"type\": \"LLT\"\n" +" },\n" +" \"server-tag\": \"\",\n" +" \"shared-networks\": [\n" " {\n" -" \"always-send\": false,\n" -" \"code\": 38,\n" -" \"csv-format\": false,\n" -" \"data\": \"ABCDEF0105\",\n" -" \"name\": \"subscriber-id\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\",\n" -" \"user-context\": {\n" -" \"comment\": \"Set option value\"\n" -" }\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"name\": \"foo\",\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": false,\n" +" \"id\": 100,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.45,\n" +" \"t2-percent\": 0.65,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 200,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:2::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:2::/64\",\n" +" \"t1-percent\": 0.4,\n" +" \"t2-percent\": 0.75,\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ],\n" +" \"t1-percent\": 0.4,\n" +" \"t2-percent\": 0.75,\n" +" \"valid-lifetime\": 4000\n" " }\n" " ],\n" -" \"option-def\": [\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" " {\n" -" \"array\": false,\n" -" \"code\": 100,\n" -" \"encapsulate\": \"\",\n" -" \"name\": \"foo\",\n" -" \"record-types\": \"\",\n" -" \"space\": \"isc\",\n" -" \"type\": \"ipv6-address\",\n" -" \"user-context\": {\n" -" \"comment\": \"An option definition\"\n" -" }\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 300,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:3::/80\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": false,\n" +" \"subnet\": \"2001:db8:3::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" " }\n" " ],\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 68 +"{\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\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-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-ring6\"\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"early-global-reservations-lookup\": false,\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\" ],\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" +" \"mac-sources\": [ \"any\" ],\n" +" \"multi-threading\": {\n" +" \"enable-multi-threading\": true,\n" +" \"packet-queue-size\": 64,\n" +" \"thread-pool-size\": 0\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" " \"parked-packet-limit\": 256,\n" " \"pd-allocator\": \"iterative\",\n" +" \"preferred-lifetime\": 3000,\n" +" \"rebind-timer\": 2000,\n" " \"relay-supplied-options\": [ \"65\" ],\n" +" \"renew-timer\": 1000,\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -9704,114 +11766,82 @@ const char* UNPARSED_CONFIGS[] = { " \"identifier\": \"\",\n" " \"persist\": true,\n" " \"time\": 0,\n" -" \"type\": \"LL\",\n" -" \"user-context\": {\n" -" \"comment\": \"DHCPv6 specific\"\n" -" }\n" +" \"type\": \"LLT\"\n" " },\n" " \"server-tag\": \"\",\n" -" \"shared-networks\": [\n" +" \"shared-networks\": [ ],\n" +" \"statistic-default-sample-age\": 0,\n" +" \"statistic-default-sample-count\": 20,\n" +" \"store-extended-info\": false,\n" +" \"subnet6\": [\n" " {\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" -" \"max-valid-lifetime\": 7200,\n" -" \"min-valid-lifetime\": 7200,\n" -" \"name\": \"foo\",\n" +" \"id\": 1,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" +" }\n" +" ],\n" +" \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" " \"relay\": {\n" " \"ip-addresses\": [ ]\n" " },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" " \"store-extended-info\": false,\n" -" \"subnet6\": [\n" +" \"subnet\": \"2001:db8:1::/64\",\n" +" \"t1-percent\": 0.5,\n" +" \"t2-percent\": 0.8,\n" +" \"valid-lifetime\": 4000\n" +" },\n" +" {\n" +" \"allocator\": \"iterative\",\n" +" \"calculate-tee-times\": true,\n" +" \"id\": 2,\n" +" \"max-preferred-lifetime\": 3000,\n" +" \"max-valid-lifetime\": 4000,\n" +" \"min-preferred-lifetime\": 3000,\n" +" \"min-valid-lifetime\": 4000,\n" +" \"option-data\": [ ],\n" +" \"pd-allocator\": \"iterative\",\n" +" \"pd-pools\": [ ],\n" +" \"pools\": [\n" " {\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"id\": 100,\n" -" \"max-valid-lifetime\": 7200,\n" -" \"min-valid-lifetime\": 7200,\n" " \"option-data\": [ ],\n" -" \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [\n" -" {\n" -" \"delegated-len\": 64,\n" -" \"option-data\": [ ],\n" -" \"prefix\": \"2001:db2::\",\n" -" \"prefix-len\": 48,\n" -" \"user-context\": {\n" -" \"comment\": \"A prefix pool\"\n" -" }\n" -" }\n" -" ],\n" -" \"pools\": [\n" -" {\n" -" \"option-data\": [ ],\n" -" \"pool\": \"2001:db1::/64\",\n" -" \"user-context\": {\n" -" \"comment\": \"A pool\"\n" -" }\n" -" }\n" -" ],\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"reservations\": [\n" -" {\n" -" \"client-classes\": [ ],\n" -" \"hostname\": \"foo.example.com\",\n" -" \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n" -" \"ip-addresses\": [ ],\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 24,\n" -" \"csv-format\": true,\n" -" \"data\": \"example.com\",\n" -" \"name\": \"domain-search\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\",\n" -" \"user-context\": {\n" -" \"comment\": \"An option in a reservation\"\n" -" }\n" -" }\n" -" ],\n" -" \"prefixes\": [ ],\n" -" \"user-context\": {\n" -" \"comment\": \"A host reservation\"\n" -" }\n" -" }\n" -" ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db1::/48\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"user-context\": {\n" -" \"comment\": \"A subnet\"\n" -" },\n" -" \"valid-lifetime\": 7200\n" +" \"pool\": \"2001:db8:2::1-2001:db8:2::ffff\"\n" " }\n" " ],\n" +" \"preferred-lifetime\": 3000,\n" +" \"rapid-commit\": false,\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-addresses\": [ ]\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservations\": [ ],\n" +" \"store-extended-info\": true,\n" +" \"subnet\": \"2001:db8:2::/64\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"user-context\": {\n" -" \"comment\": \"A shared network\"\n" -" },\n" -" \"valid-lifetime\": 7200\n" +" \"valid-lifetime\": 4000\n" " }\n" " ],\n" -" \"statistic-default-sample-age\": 0,\n" -" \"statistic-default-sample-count\": 20,\n" -" \"store-extended-info\": false,\n" -" \"subnet6\": [ ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" -" \"user-context\": {\n" -" \"comment\": \"A DHCPv6 server\"\n" -" },\n" -" \"valid-lifetime\": 7200\n" +" \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 57 + // CONFIGURATION 69 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -9875,62 +11905,6 @@ const char* UNPARSED_CONFIGS[] = { " \"rebind-timer\": 2000,\n" " \"relay-supplied-options\": [ \"65\" ],\n" " \"renew-timer\": 1000,\n" -" \"reservations\": [\n" -" {\n" -" \"client-classes\": [ ],\n" -" \"hostname\": \"\",\n" -" \"hw-address\": \"01:02:03:04:05:06\",\n" -" \"ip-addresses\": [ \"2001:db8:2::abcd\" ],\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 23,\n" -" \"csv-format\": true,\n" -" \"data\": \"2001:db8:2::abbc\",\n" -" \"name\": \"dns-servers\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" },\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 7,\n" -" \"csv-format\": true,\n" -" \"data\": \"25\",\n" -" \"name\": \"preference\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"prefixes\": [ ]\n" -" },\n" -" {\n" -" \"client-classes\": [ ],\n" -" \"duid\": \"01:02:03:04:05:06:07:08:09:0a\",\n" -" \"hostname\": \"\",\n" -" \"ip-addresses\": [ \"2001:db8:2::1234\" ],\n" -" \"option-data\": [\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 23,\n" -" \"csv-format\": true,\n" -" \"data\": \"2001:db8:2::1111\",\n" -" \"name\": \"dns-servers\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" },\n" -" {\n" -" \"always-send\": false,\n" -" \"code\": 7,\n" -" \"csv-format\": true,\n" -" \"data\": \"11\",\n" -" \"name\": \"preference\",\n" -" \"never-send\": false,\n" -" \"space\": \"dhcp6\"\n" -" }\n" -" ],\n" -" \"prefixes\": [ ]\n" -" }\n" -" ],\n" " \"reservations-global\": false,\n" " \"reservations-in-subnet\": true,\n" " \"reservations-lookup-first\": false,\n" @@ -9951,12 +11925,12 @@ const char* UNPARSED_CONFIGS[] = { " \"shared-networks\": [ ],\n" " \"statistic-default-sample-age\": 0,\n" " \"statistic-default-sample-count\": 20,\n" -" \"store-extended-info\": false,\n" +" \"store-extended-info\": true,\n" " \"subnet6\": [\n" " {\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" -" \"id\": 123,\n" +" \"id\": 1,\n" " \"max-preferred-lifetime\": 3000,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-preferred-lifetime\": 3000,\n" @@ -9967,7 +11941,7 @@ const char* UNPARSED_CONFIGS[] = { " \"pools\": [\n" " {\n" " \"option-data\": [ ],\n" -" \"pool\": \"2001:db8:1::/80\"\n" +" \"pool\": \"2001:db8:1::1-2001:db8:1::ffff\"\n" " }\n" " ],\n" " \"preferred-lifetime\": 3000,\n" @@ -9987,7 +11961,7 @@ const char* UNPARSED_CONFIGS[] = { " {\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" -" \"id\": 234,\n" +" \"id\": 2,\n" " \"max-preferred-lifetime\": 3000,\n" " \"max-valid-lifetime\": 4000,\n" " \"min-preferred-lifetime\": 3000,\n" @@ -9995,7 +11969,12 @@ const char* UNPARSED_CONFIGS[] = { " \"option-data\": [ ],\n" " \"pd-allocator\": \"iterative\",\n" " \"pd-pools\": [ ],\n" -" \"pools\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [ ],\n" +" \"pool\": \"2001:db8:2::1-2001:db8:2::ffff\"\n" +" }\n" +" ],\n" " \"preferred-lifetime\": 3000,\n" " \"rapid-commit\": false,\n" " \"rebind-timer\": 2000,\n" @@ -10004,44 +11983,18 @@ const char* UNPARSED_CONFIGS[] = { " },\n" " \"renew-timer\": 1000,\n" " \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" +" \"store-extended-info\": true,\n" " \"subnet\": \"2001:db8:2::/64\",\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" -" },\n" -" {\n" -" \"allocator\": \"iterative\",\n" -" \"calculate-tee-times\": true,\n" -" \"id\": 542,\n" -" \"max-preferred-lifetime\": 3000,\n" -" \"max-valid-lifetime\": 4000,\n" -" \"min-preferred-lifetime\": 3000,\n" -" \"min-valid-lifetime\": 4000,\n" -" \"option-data\": [ ],\n" -" \"pd-allocator\": \"iterative\",\n" -" \"pd-pools\": [ ],\n" -" \"pools\": [ ],\n" -" \"preferred-lifetime\": 3000,\n" -" \"rapid-commit\": false,\n" -" \"rebind-timer\": 2000,\n" -" \"relay\": {\n" -" \"ip-addresses\": [ ]\n" -" },\n" -" \"renew-timer\": 1000,\n" -" \"reservations\": [ ],\n" -" \"store-extended-info\": false,\n" -" \"subnet\": \"2001:db8:3::/64\",\n" -" \"t1-percent\": 0.5,\n" -" \"t2-percent\": 0.8,\n" -" \"valid-lifetime\": 4000\n" " }\n" " ],\n" " \"t1-percent\": 0.5,\n" " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 58 + // CONFIGURATION 70 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -10131,7 +12084,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 59 + // CONFIGURATION 71 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -10218,7 +12171,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 60 + // CONFIGURATION 72 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -10305,7 +12258,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 61 + // CONFIGURATION 73 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -10435,7 +12388,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 62 + // CONFIGURATION 74 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" @@ -10567,7 +12520,7 @@ const char* UNPARSED_CONFIGS[] = { " \"t2-percent\": 0.8,\n" " \"valid-lifetime\": 7200\n" " }\n", - // CONFIGURATION 63 + // CONFIGURATION 75 "{\n" " \"allocator\": \"iterative\",\n" " \"calculate-tee-times\": true,\n" diff --git a/src/bin/dhcp6/tests/get_config_unittest.cc.skel b/src/bin/dhcp6/tests/get_config_unittest.cc.skel index b07abaa16d..1a619eaa91 100644 --- a/src/bin/dhcp6/tests/get_config_unittest.cc.skel +++ b/src/bin/dhcp6/tests/get_config_unittest.cc.skel @@ -9,25 +9,24 @@ #include #include #include -#include -#include #include -#include -#include -#include #include +#include #include #include #include +#include #include - -#include -#include +#include #include -#include -#include #include +#include +#include + +#include + +#include using namespace isc::config; using namespace isc::data; diff --git a/src/bin/dhcp6/tests/kea_controller_unittest.cc b/src/bin/dhcp6/tests/kea_controller_unittest.cc index 9ec596040e..0c1482e82c 100644 --- a/src/bin/dhcp6/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp6/tests/kea_controller_unittest.cc @@ -173,7 +173,7 @@ typedef boost::shared_ptr TestCBControlDHCPv6Ptr; /// /// Exposes internal fields and installs stub implementation of the /// @c CBControlDHCPv6 object. -class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv { +class NakedControlledDhcpv6Srv : public ControlledDhcpv6Srv { public: /// @brief Constructor. @@ -185,7 +185,12 @@ public: } }; - +/// @brief test class for Kea configuration backend. +/// +/// This class is used for testing Kea configuration backend. +/// It is very simple and currently focuses on reading +/// config file from disk. It is expected to be expanded in the +/// near future. class JSONFileBackendTest : public dhcp::test::BaseServerTest { public: JSONFileBackendTest() { @@ -286,7 +291,6 @@ public: EXPECT_EQ(0, cb_control->getDatabaseCurrentConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseStagingConfigFetchCalls()); - if (call_command) { // The case where there is no backend is tested in the // controlled server tests so we have only to verify @@ -796,7 +800,6 @@ TEST_F(JSONFileBackendTest, timers) { duid_expired, 1, 50, 60, SubnetID(1))); lease_expired->cltt_ = time(NULL) - 100; - // Create expired-reclaimed lease. The lease has expired 1000 - 60 seconds // ago. It should be removed from the lease database when the "flush" timer // goes off. @@ -1062,7 +1065,6 @@ testBackendReconfiguration(const std::string& backend_first, LeaseMgrFactory::instance().getType()); } - // This test verifies that backend specification can be added on // server reconfiguration. TEST_F(JSONFileBackendMySQLTest, reconfigureBackendUndefinedToMySQL) { diff --git a/src/bin/netconf/parser_context.cc b/src/bin/netconf/parser_context.cc index d0e20fc111..3e57c51e9f 100644 --- a/src/bin/netconf/parser_context.cc +++ b/src/bin/netconf/parser_context.cc @@ -57,15 +57,14 @@ ParserContext::parseCommon() { isc_throw(ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/lib/database/database_connection.cc b/src/lib/database/database_connection.cc index 6a79340f4a..7c7a355269 100644 --- a/src/lib/database/database_connection.cc +++ b/src/lib/database/database_connection.cc @@ -241,7 +241,8 @@ DatabaseConnection::toElement(const ParameterMap& params) { .arg(keyword).arg(value); } } else if ((keyword == "persist") || - (keyword == "readonly")) { + (keyword == "readonly") || + (keyword == "retry-on-startup")) { if (value == "true") { result->set(keyword, isc::data::Element::create(true)); } else if (value == "false") { @@ -256,7 +257,6 @@ DatabaseConnection::toElement(const ParameterMap& params) { (keyword == "host") || (keyword == "name") || (keyword == "on-fail") || - (keyword == "retry-on-startup") || (keyword == "trust-anchor") || (keyword == "cert-file") || (keyword == "key-file") || diff --git a/src/lib/database/tests/database_connection_unittest.cc b/src/lib/database/tests/database_connection_unittest.cc index d8fec9e659..070a5c6559 100644 --- a/src/lib/database/tests/database_connection_unittest.cc +++ b/src/lib/database/tests/database_connection_unittest.cc @@ -536,6 +536,7 @@ TEST(DatabaseConnection, toElementDbAccessStringValid) { "\"port\" : 300, \n" "\"readonly\" : false, \n" "\"reconnect-wait-time\": 99, \n" + "\"retry-on-startup\" : true, \n" "\"type\": \"memfile\", \n" "\"user\": \"user_str\", \n" "\"max-row-errors\": 50, \n" -- 2.47.2