]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5019] subnet defaults implemented, id, rapid-commit params migrated
authorTomek Mrugalski <tomasz@isc.org>
Wed, 25 Jan 2017 13:51:11 +0000 (14:51 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Thu, 26 Jan 2017 12:49:54 +0000 (13:49 +0100)
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp4/simple_parser4.cc
src/bin/dhcp4/simple_parser4.h
src/bin/dhcp4/tests/simple_parser4_unittest.cc
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/simple_parser6.cc
src/bin/dhcp6/simple_parser6.h
src/bin/dhcp6/tests/simple_parser6_unittest.cc
src/lib/dhcpsrv/parsers/dhcp_parsers.cc
src/lib/dhcpsrv/parsers/dhcp_parsers.h

index 2b4a2c3e3f099d668257144e2d9b0c9efdaea333..35b9ab1014576ccbb386ad2eaafcb613540ba2ae 100644 (file)
@@ -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<uint32_t> 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<SubnetID>(uint32_values_->getOptionalParam("id", 0));
+        // which means autogenerate. The value was inserted earlier by calling
+        // SimpleParser4::setAllDefaults.
+        SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
 
         stringstream s;
         s << addr << "/" << static_cast<int>(len) << " with params: ";
index 63febebfd0538e4538e6cca1b1068cec55cb4428..3ed99e2aedebcfc6e99af383291b19c2799d67b9 100644 (file)
@@ -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);
 }
 
index c442f300b0fa357f491398ad53a0490a972e275f..ac612e9c5bde53e9f6537452462b2395a5529766 100644 (file)
@@ -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;
 };
 
index fd00f6ca697611becf09cc15cd5ebe19a61f7297..72957c47e8edc4ab4e75f4d14988b8dc5d46c1f2 100644 (file)
@@ -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);
+}
 
 };
 };
index 56de44122645e86e80e3c9b5bda6ce6746fc0777..0b1546d40e6ab84c52bfd49c148f12dfe834dd1a 100644 (file)
@@ -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<uint32_t> t2 = getParam("rebind-timer");
         Triplet<uint32_t> pref = getParam("preferred-lifetime");
         Triplet<uint32_t> 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<SubnetID>(uint32_values_->getOptionalParam("id", 0));
+        // which means autogenerate. The value was inserted earlier by calling
+        // SimpleParser6::setAllDefaults.
+        SubnetID subnet_id = static_cast<SubnetID>(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<int>(len)
index f30c19741fb4adf50d8de5e36c280edfb8e8f566..957bd5842c17af79488b371c07612d65f0f46c80 100644 (file)
@@ -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);
 }
 
index 8a760f6ac4fabcdaa4744e4ca6d3753436b5d0f6..590e11a5d259bd9ce8c432b2238d983ef1540cc8 100644 (file)
@@ -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;
 };
 
index c7a991d86e4103a868eb0d76bedb0b0efbfcf225..2f09c46d3a9e5485a13781d4d3be9fde2273377d 100644 (file)
@@ -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);
+}
+
+
+};
index c35bf1a3477df6e02f4f244af887bd8cda1c582b..e349794eed29ea5f2e0cd93a8fee1a7251db2316 100644 (file)
@@ -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<unsigned int>(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;
index 34b2e322b8a1ce67e964ae4c281d550b9ae3e715..add82f16283a790d596133cc15a732513f99b634 100644 (file)
@@ -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: