Browse Source

[5019] subnet defaults implemented, id, rapid-commit params migrated

Tomek Mrugalski 8 years ago
parent
commit
5189956f77

+ 6 - 4
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<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: ";

+ 15 - 5
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);
 }
 

+ 2 - 1
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;
 };
 

+ 115 - 1
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);
+}
 
 };
 };

+ 7 - 5
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<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)

+ 15 - 2
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);
 }
 

+ 2 - 1
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;
 };
 

+ 120 - 1
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);
+}
+
+
+};

+ 4 - 5
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<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;

+ 5 - 2
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: