From: Tomek Mrugalski Date: Wed, 25 Jan 2017 13:51:11 +0000 (+0100) Subject: [5019] subnet defaults implemented, id, rapid-commit params migrated X-Git-Tag: trac3389_base~10 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=5189956f77aa2d06e68ae6e21073c2fb3a67a133;p=thirdparty%2Fkea.git [5019] subnet defaults implemented, id, rapid-commit params migrated --- diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index 2b4a2c3e3f..35b9ab1014 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -208,7 +208,8 @@ protected: /// /// @param addr is IPv4 address of the subnet. /// @param len is the prefix length - void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) { + void initSubnet(isc::data::ConstElementPtr params, + isc::asiolink::IOAddress addr, uint8_t len) { // The renew-timer and rebind-timer are optional. If not set, the // option 58 and 59 will not be sent to a client. In this case the // client will use default values based on the valid-lifetime. @@ -218,10 +219,11 @@ protected: // particular subnet. If not, the global value should be present. // If there is no global value, exception is thrown. Triplet valid = getParam("valid-lifetime"); + // Subnet ID is optional. If it is not supplied the value of 0 is used, - // which means autogenerate. - SubnetID subnet_id = - static_cast(uint32_values_->getOptionalParam("id", 0)); + // which means autogenerate. The value was inserted earlier by calling + // SimpleParser4::setAllDefaults. + SubnetID subnet_id = static_cast(getInteger(params, "id")); stringstream s; s << addr << "/" << static_cast(len) << " with params: "; diff --git a/src/bin/dhcp4/simple_parser4.cc b/src/bin/dhcp4/simple_parser4.cc index 63febebfd0..3ed99e2aed 100644 --- a/src/bin/dhcp4/simple_parser4.cc +++ b/src/bin/dhcp4/simple_parser4.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -65,6 +65,11 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = { { "next-server", Element::string, "0.0.0.0" } }; +/// @brief This table defines default values for each IPv4 subnet. +const SimpleDefaults SimpleParser4::SUBNET4_DEFAULTS = { + { "id", Element::integer, "0" } // 0 means autogenerate +}; + /// @brief List of parameters that can be inherited from the global to subnet4 scope. /// /// Some parameters may be defined on both global (directly in Dhcp4) and @@ -98,13 +103,18 @@ size_t SimpleParser4::setAllDefaults(isc::data::ElementPtr global) { } } - // Finally, set the defaults for option data + // Set the defaults for option data ConstElementPtr options = global->get("option-data"); if (options) { - BOOST_FOREACH(ElementPtr single_option, options->listValue()) { - cnt += SimpleParser::setDefaults(single_option, OPTION4_DEFAULTS); - } + cnt += setListDefaults(options, OPTION4_DEFAULTS); + } + + // Now set the defaults for defined subnets + ConstElementPtr subnets = global->get("subnet4"); + if (subnets) { + cnt += setListDefaults(subnets, SUBNET4_DEFAULTS); } + return (cnt); } diff --git a/src/bin/dhcp4/simple_parser4.h b/src/bin/dhcp4/simple_parser4.h index c442f300b0..ac612e9c5b 100644 --- a/src/bin/dhcp4/simple_parser4.h +++ b/src/bin/dhcp4/simple_parser4.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -40,6 +40,7 @@ public: static const isc::data::SimpleDefaults OPTION4_DEF_DEFAULTS; static const isc::data::SimpleDefaults OPTION4_DEFAULTS; static const isc::data::SimpleDefaults GLOBAL4_DEFAULTS; + static const isc::data::SimpleDefaults SUBNET4_DEFAULTS; static const isc::data::ParamsList INHERIT_GLOBAL_TO_SUBNET4; }; diff --git a/src/bin/dhcp4/tests/simple_parser4_unittest.cc b/src/bin/dhcp4/tests/simple_parser4_unittest.cc index fd00f6ca69..72957c47e8 100644 --- a/src/bin/dhcp4/tests/simple_parser4_unittest.cc +++ b/src/bin/dhcp4/tests/simple_parser4_unittest.cc @@ -40,6 +40,50 @@ public: // Finally, check if its value meets expectation. EXPECT_EQ(exp_value, elem->intValue()); } + + /// @brief Checks if specified map has a string parameter with expected value + /// + /// @param map map to be checked + /// @param param_name name of the parameter to be checked + /// @param exp_value expected value of the parameter. + void checkStringValue(const ConstElementPtr& map, const std::string& param_name, + std::string exp_value) { + + // First check if the passed element is a map. + ASSERT_EQ(Element::map, map->getType()); + + // Now try to get the element being checked + ConstElementPtr elem = map->get(param_name); + ASSERT_TRUE(elem); + + // Now check if it's indeed integer + ASSERT_EQ(Element::string, elem->getType()); + + // Finally, check if its value meets expectation. + EXPECT_EQ(exp_value, elem->stringValue()); + } + + /// @brief Checks if specified map has a boolean parameter with expected value + /// + /// @param map map to be checked + /// @param param_name name of the parameter to be checked + /// @param exp_value expected value of the parameter. + void checkBoolValue(const ConstElementPtr& map, const std::string& param_name, + bool exp_value) { + + // First check if the passed element is a map. + ASSERT_EQ(Element::map, map->getType()); + + // Now try to get the element being checked + ConstElementPtr elem = map->get(param_name); + ASSERT_TRUE(elem); + + // Now check if it's indeed integer + ASSERT_EQ(Element::boolean, elem->getType()); + + // Finally, check if its value meets expectation. + EXPECT_EQ(exp_value, elem->boolValue()); + } }; // This test checks if global defaults are properly set for DHCPv4. @@ -68,7 +112,6 @@ TEST_F(SimpleParser4Test, globalDefaults4) { TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) { ElementPtr global = parseJSON("{ \"renew-timer\": 1," " \"rebind-timer\": 2," - " \"preferred-lifetime\": 3," " \"valid-lifetime\": 4," " \"subnet4\": [ { \"renew-timer\": 100 } ] " "}"); @@ -90,6 +133,77 @@ TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) { checkIntegerValue(subnet, "valid-lifetime", 4); } +// This test checks if the parameters in "subnet4" are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser4Test, subnetDefaults4) { + ElementPtr global = parseJSON("{ \"renew-timer\": 1," + " \"rebind-timer\": 2," + " \"valid-lifetime\": 4," + " \"subnet4\": [ { } ] " + "}"); + + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser4::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr subnets = global->find("subnet4"); + ASSERT_TRUE(subnets); + ConstElementPtr subnet = subnets->get(0); + ASSERT_TRUE(subnet); + + // we should have "id" parameter with the default value of 0 added for us. + checkIntegerValue(subnet, "id", 0); +} + +// This test checks if the parameters in option-data are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser4Test, optionDataDefaults4) { + ElementPtr global = parseJSON("{ \"renew-timer\": 1," + " \"rebind-timer\": 2," + " \"valid-lifetime\": 4," + " \"option-data\": [ { } ] " + "}"); + + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser4::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr options = global->find("option-data"); + ASSERT_TRUE(options); + ConstElementPtr option = options->get(0); + ASSERT_TRUE(option); + + // we should have appropriate default value set. See + // SimpleParser4::OPTION4_DEFAULTS for a list of default values. + checkStringValue(option, "space", "dhcp4"); + checkStringValue(option, "encapsulate", ""); + checkBoolValue(option, "csv-format", true); +} + +// This test checks if the parameters in option-data are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser4Test, optionDefDefaults4) { + ElementPtr global = parseJSON("{ " + " \"option-def\": [ { } ] " + "}"); + + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser4::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr defs = global->find("option-def"); + ASSERT_TRUE(defs); + ASSERT_EQ(1, defs->size()); + ConstElementPtr def = defs->get(0); + ASSERT_TRUE(def); + + // we should have appropriate default value set. See + // SimpleParser4::OPTION4_DEFAULTS for a list of default values. + checkStringValue(def, "record-types", ""); + checkStringValue(def, "space", "dhcp4"); + checkStringValue(def, "encapsulate", ""); + checkBoolValue(def, "array", false); +} }; }; diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 56de441226..0b1546d40e 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -409,7 +409,8 @@ protected: /// /// @param addr is IPv6 prefix of the subnet. /// @param len is the prefix length - void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) { + void initSubnet(isc::data::ConstElementPtr params, + isc::asiolink::IOAddress addr, uint8_t len) { // Get all 'time' parameters using inheritance. // If the subnet-specific value is defined then use it, else // use the global value. The global value must always be @@ -419,10 +420,11 @@ protected: Triplet t2 = getParam("rebind-timer"); Triplet pref = getParam("preferred-lifetime"); Triplet valid = getParam("valid-lifetime"); + // Subnet ID is optional. If it is not supplied the value of 0 is used, - // which means autogenerate. - SubnetID subnet_id = - static_cast(uint32_values_->getOptionalParam("id", 0)); + // which means autogenerate. The value was inserted earlier by calling + // SimpleParser6::setAllDefaults. + SubnetID subnet_id = static_cast(getInteger(params, "id")); // Get interface-id option content. For now we support string // representation only @@ -454,7 +456,7 @@ protected: } // Gather boolean parameters values. - bool rapid_commit = boolean_values_->getOptionalParam("rapid-commit", false); + bool rapid_commit = getBoolean(params, "rapid-commit"); std::ostringstream output; output << addr << "/" << static_cast(len) diff --git a/src/bin/dhcp6/simple_parser6.cc b/src/bin/dhcp6/simple_parser6.cc index f30c19741f..957bd5842c 100644 --- a/src/bin/dhcp6/simple_parser6.cc +++ b/src/bin/dhcp6/simple_parser6.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -63,6 +63,12 @@ const SimpleDefaults SimpleParser6::GLOBAL6_DEFAULTS = { { "dhcp4o6-port", Element::integer, "0" } }; +/// @brief This table defines default values for each IPv6 subnet. +const SimpleDefaults SimpleParser6::SUBNET6_DEFAULTS = { + { "id", Element::integer, "0" }, // 0 means autogenerate + { "rapid-commit", Element::boolean, "false" } // rapid-commit disabled by default +}; + /// @brief List of parameters that can be inherited from the global to subnet6 scope. /// /// Some parameters may be defined on both global (directly in Dhcp6) and @@ -95,7 +101,7 @@ size_t SimpleParser6::setAllDefaults(isc::data::ElementPtr global) { } } - // Finally, set the defaults for option data + // Set the defaults for option data ConstElementPtr options = global->get("option-data"); if (options) { BOOST_FOREACH(ElementPtr single_option, options->listValue()) { @@ -103,6 +109,13 @@ size_t SimpleParser6::setAllDefaults(isc::data::ElementPtr global) { } } + // Now set the defaults for defined subnets + // Now set the defaults for defined subnets + ConstElementPtr subnets = global->get("subnet6"); + if (subnets) { + cnt += setListDefaults(subnets, SUBNET6_DEFAULTS); + } + return (cnt); } diff --git a/src/bin/dhcp6/simple_parser6.h b/src/bin/dhcp6/simple_parser6.h index 8a760f6ac4..590e11a5d2 100644 --- a/src/bin/dhcp6/simple_parser6.h +++ b/src/bin/dhcp6/simple_parser6.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -41,6 +41,7 @@ public: static const isc::data::SimpleDefaults OPTION6_DEF_DEFAULTS; static const isc::data::SimpleDefaults OPTION6_DEFAULTS; static const isc::data::SimpleDefaults GLOBAL6_DEFAULTS; + static const isc::data::SimpleDefaults SUBNET6_DEFAULTS; static const isc::data::ParamsList INHERIT_GLOBAL_TO_SUBNET6; }; diff --git a/src/bin/dhcp6/tests/simple_parser6_unittest.cc b/src/bin/dhcp6/tests/simple_parser6_unittest.cc index c7a991d86e..2f09c46d3a 100644 --- a/src/bin/dhcp6/tests/simple_parser6_unittest.cc +++ b/src/bin/dhcp6/tests/simple_parser6_unittest.cc @@ -41,6 +41,51 @@ public: // Finally, check if its value meets expectation. EXPECT_EQ(exp_value, elem->intValue()); } + + /// @brief Checks if specified map has a string parameter with expected value + /// + /// @param map map to be checked + /// @param param_name name of the parameter to be checked + /// @param exp_value expected value of the parameter. + void checkStringValue(const ConstElementPtr& map, const std::string& param_name, + std::string exp_value) { + + // First check if the passed element is a map. + ASSERT_EQ(Element::map, map->getType()); + + // Now try to get the element being checked + ConstElementPtr elem = map->get(param_name); + ASSERT_TRUE(elem); + + // Now check if it's indeed integer + ASSERT_EQ(Element::string, elem->getType()); + + // Finally, check if its value meets expectation. + EXPECT_EQ(exp_value, elem->stringValue()); + } + + /// @brief Checks if specified map has a boolean parameter with expected value + /// + /// @param map map to be checked + /// @param param_name name of the parameter to be checked + /// @param exp_value expected value of the parameter. + void checkBoolValue(const ConstElementPtr& map, const std::string& param_name, + bool exp_value) { + + // First check if the passed element is a map. + ASSERT_EQ(Element::map, map->getType()); + + // Now try to get the element being checked + ConstElementPtr elem = map->get(param_name); + ASSERT_TRUE(elem); + + // Now check if it's indeed integer + ASSERT_EQ(Element::boolean, elem->getType()); + + // Finally, check if its value meets expectation. + EXPECT_EQ(exp_value, elem->boolValue()); + } + }; // This test checks if global defaults are properly set for DHCPv6. @@ -89,5 +134,79 @@ TEST_F(SimpleParser6Test, inheritGlobalToSubnet6) { checkIntegerValue(subnet, "valid-lifetime", 4); } -}; +// This test checks if the parameters in "subnet6" are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser6Test, subnetDefaults6) { + ElementPtr global = parseJSON("{ \"renew-timer\": 1," + " \"rebind-timer\": 2," + " \"preferred-lifetime\": 3," + " \"valid-lifetime\": 4," + " \"subnet6\": [ { } ] " + "}"); + + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser6::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr subnets = global->find("subnet6"); + ASSERT_TRUE(subnets); + ConstElementPtr subnet = subnets->get(0); + ASSERT_TRUE(subnet); + + // we should have "id" parameter with the default value of 0 added for us. + checkIntegerValue(subnet, "id", 0); +} + +// This test checks if the parameters in option-data are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser6Test, optionDataDefaults4) { + ElementPtr global = parseJSON("{ \"renew-timer\": 1," + " \"rebind-timer\": 2," + " \"preferred-lifetime\": 3," + " \"valid-lifetime\": 4," + " \"option-data\": [ { } ] " + "}"); + + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser6::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr options = global->find("option-data"); + ASSERT_TRUE(options); + ConstElementPtr option = options->get(0); + ASSERT_TRUE(option); + + // we should have appropriate default value set. See + // SimpleParser4::OPTION4_DEFAULTS for a list of default values. + checkStringValue(option, "space", "dhcp6"); + checkStringValue(option, "encapsulate", ""); + checkBoolValue(option, "csv-format", true); +} + +// This test checks if the parameters in option-data are assigned default values +// if not explicitly specified. +TEST_F(SimpleParser6Test, optionDefDefaults6) { + ElementPtr global = parseJSON("{ " + " \"option-def\": [ { } ] " + "}"); + size_t num = 0; + EXPECT_NO_THROW(num = SimpleParser6::setAllDefaults(global)); + EXPECT_LE(1, num); // at least 1 parameter has to be modified + + ConstElementPtr defs = global->find("option-def"); + ASSERT_TRUE(defs); + ASSERT_EQ(1, defs->size()); + ConstElementPtr def = defs->get(0); + ASSERT_TRUE(def); + + // we should have appropriate default value set. See + // SimpleParser4::OPTION4_DEFAULTS for a list of default values. + checkStringValue(def, "record-types", ""); + checkStringValue(def, "space", "dhcp6"); + checkStringValue(def, "encapsulate", ""); + checkBoolValue(def, "array", false); +} + + +}; diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index c35bf1a347..e349794eed 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -1062,7 +1062,7 @@ SubnetConfigParser::build(ConstElementPtr subnet) { // Create a subnet. try { - createSubnet(); + createSubnet(subnet); } catch (const std::exception& ex) { isc_throw(DhcpConfigError, "subnet configuration failed (" << subnet->getPosition() @@ -1088,10 +1088,10 @@ SubnetConfigParser::hrModeFromText(const std::string& txt) { } void -SubnetConfigParser::createSubnet() { +SubnetConfigParser::createSubnet(ConstElementPtr params) { std::string subnet_txt; try { - subnet_txt = string_values_->getParam("subnet"); + subnet_txt = getString(params, "subnet"); } catch (const DhcpConfigError &) { // rethrow with precise error isc_throw(DhcpConfigError, @@ -1121,7 +1121,7 @@ SubnetConfigParser::createSubnet() { uint8_t len = boost::lexical_cast(subnet_txt.substr(pos + 1)); // Call the subclass's method to instantiate the subnet - initSubnet(addr, len); + initSubnet(params, addr, len); // Add pools to it. for (PoolStorage::iterator it = pools_->begin(); it != pools_->end(); @@ -1140,7 +1140,6 @@ SubnetConfigParser::createSubnet() { // iface not mandatory so swallow the exception } - // Let's set host reservation mode. If not specified, the default value of // all will be used. std::string hr_mode; diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index 34b2e322b8..add82f1628 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h @@ -856,9 +856,11 @@ protected: /// @brief Instantiates the subnet based on a given IP prefix and prefix /// length. /// + /// @param params configuration parameters for that subnet /// @param addr is the IP prefix of the subnet. /// @param len is the prefix length - virtual void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) = 0; + virtual void initSubnet(isc::data::ConstElementPtr params, + isc::asiolink::IOAddress addr, uint8_t len) = 0; /// @brief Returns value for a given parameter (after using inheritance) /// @@ -899,9 +901,10 @@ private: /// @brief Create a new subnet using a data from child parsers. /// + /// @param data Element map that describes the subnet /// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing /// failed. - void createSubnet(); + void createSubnet(isc::data::ConstElementPtr data); protected: