Browse Source

[5122] initSubnet migrated to SimpleParser

Tomek Mrugalski 8 years ago
parent
commit
22c37c1925

+ 27 - 57
src/bin/dhcp4/json_config_parser.cc

@@ -206,12 +206,13 @@ protected:
         // 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.
-        Triplet<uint32_t> t1 = getOptionalParam("renew-timer");
-        Triplet<uint32_t> t2 = getOptionalParam("rebind-timer");
+        Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
+        Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
+
         // The valid-lifetime is mandatory. It may be specified for a
         // 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");
+        Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
 
         // Subnet ID is optional. If it is not supplied the value of 0 is used,
         // which means autogenerate. The value was inserted earlier by calling
@@ -234,64 +235,41 @@ protected:
         Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
         subnet_ = subnet4;
 
-        // match-client-id
-        isc::util::OptionalValue<bool> match_client_id;
-        try {
-            match_client_id = boolean_values_->getParam("match-client-id");
-
-        } catch (...) {
-            // Ignore because this parameter is optional and it may be specified
-            // in the global scope.
-        }
-
-        // If the match-client-id wasn't specified as a subnet specific parameter
-        // check if there is global value specified.
-        if (!match_client_id.isSpecified()) {
-            // If not specified, use false.
-            match_client_id.specify(globalContext()->boolean_values_->
-                                    getOptionalParam("match-client-id", true));
-        }
-
-        // Set the match-client-id value for the subnet.
-        subnet4->setMatchClientId(match_client_id.get());
-
-        // next-server
-        try {
-            string next_server = globalContext()->string_values_->getParam("next-server");
-            if (!next_server.empty()) {
-                subnet4->setSiaddr(IOAddress(next_server));
-            }
-        } catch (const DhcpConfigError&) {
-            // Don't care. next_server is optional. We can live without it
-        } catch (...) {
-            isc_throw(DhcpConfigError, "invalid parameter next-server ("
-                      << globalContext()->string_values_->getPosition("next-server")
-                      << ")");
-        }
+        // Set the match-client-id value for the subnet. It is always present.
+        // If not explicitly specified, the default value was filed in when
+        // SimpleParser4::setAllDefaults was called.
+        bool match_client_id = getBoolean(params, "match-client-id");
+        subnet4->setMatchClientId(match_client_id);
 
-        // Try subnet specific value if it's available
+        // Set next-server. The default value is 0.0.0.0. Nevertheless, the
+        // user could have messed that up by specifying incorrect value.
+        // To avoid using 0.0.0.0, user can specify "".
+        string next_server;
         try {
-            string next_server = string_values_->getParam("next-server");
+            next_server = getString(params, "next-server");
             if (!next_server.empty()) {
                 subnet4->setSiaddr(IOAddress(next_server));
             }
-        } catch (const DhcpConfigError&) {
-            // Don't care. next_server is optional. We can live without it
         } catch (...) {
-            isc_throw(DhcpConfigError, "invalid parameter next-server ("
-                      << string_values_->getPosition("next-server")
-                      << ")");
+            ConstElementPtr next = params->find("next-server");
+            string pos("(missing)");
+            if (next)
+                pos = next->getPosition().str();
+            isc_throw(DhcpConfigError, "invalid parameter next-server : "
+                      << next_server << "(" << pos << ")");
         }
 
-        // Try 4o6 specific parameter: 4o6-interface
-        string iface4o6 = string_values_->getOptionalParam("4o6-interface", "");
+        // 4o6 specific parameter: 4o6-interface. If not explicitly specified,
+        // it will have the default value of "".
+        string iface4o6 = getString(params, "4o6-interface");
         if (!iface4o6.empty()) {
             subnet4->get4o6().setIface4o6(iface4o6);
             subnet4->get4o6().enabled(true);
         }
 
-        // Try 4o6 specific parameter: 4o6-subnet
-        string subnet4o6 = string_values_->getOptionalParam("4o6-subnet", "");
+        // 4o6 specific parameter: 4o6-subnet. If not explicitly specified, it
+        // will have the default value of "".
+        string subnet4o6 = getString(params, "4o6-subnet");
         if (!subnet4o6.empty()) {
             size_t slash = subnet4o6.find("/");
             if (slash == std::string::npos) {
@@ -313,21 +291,13 @@ protected:
         }
 
         // Try 4o6 specific parameter: 4o6-interface-id
-        std::string ifaceid = string_values_->getOptionalParam("4o6-interface-id", "");
+        std::string ifaceid = getString(params, "4o6-interface-id");
         if (!ifaceid.empty()) {
             OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
             OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
             subnet4->get4o6().setInterfaceId(opt);
             subnet4->get4o6().enabled(true);
         }
-
-        // Try setting up client class (if specified)
-        try {
-            string client_class = string_values_->getParam("client-class");
-            subnet4->allowClientClass(client_class);
-        } catch (const DhcpConfigError&) {
-            // That's ok if it fails. client-class is optional.
-        }
     }
 };
 

+ 8 - 2
src/bin/dhcp4/simple_parser4.cc

@@ -62,12 +62,18 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
     { "dhcp4o6-port",             Element::integer, "0" },
     { "echo-client-id",           Element::boolean, "true" },
     { "match-client-id",          Element::boolean, "true" },
-    { "next-server",              Element::string, "0.0.0.0" }
+    { "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
+    { "id",               Element::integer, "0" }, // 0 means autogenerate
+    { "interface",        Element::string,  "" },
+    { "client-class",     Element::string,  "" },
+    { "reservation-mode", Element::string,  "all" },
+    { "4o6-interface",    Element::string,  "" },
+    { "4o6-interface-id", Element::string,  "" },
+    { "4o6-subnet",       Element::string,  "" },
 };
 
 /// @brief List of parameters that can be inherited from the global to subnet4 scope.

+ 20 - 42
src/bin/dhcp6/json_config_parser.cc

@@ -416,46 +416,16 @@ protected:
         // use the global value. The global value must always be
         // present. If it is not, it is an internal error and exception
         // is thrown.
-        Triplet<uint32_t> t1 = getParam("renew-timer");
-        Triplet<uint32_t> t2 = getParam("rebind-timer");
-        Triplet<uint32_t> pref = getParam("preferred-lifetime");
-        Triplet<uint32_t> valid = getParam("valid-lifetime");
+        Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
+        Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
+        Triplet<uint32_t> pref = getInteger(params, "preferred-lifetime");
+        Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
 
         // Subnet ID is optional. If it is not supplied the value of 0 is used,
         // 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
-        std::string ifaceid;
-        try {
-            ifaceid = string_values_->getParam("interface-id");
-        } catch (const DhcpConfigError &) {
-            // interface-id is not mandatory
-        }
-
-        // Specifying both interface for locally reachable subnets and
-        // interface id for relays is mutually exclusive. Need to test for
-        // this condition.
-        if (!ifaceid.empty()) {
-            std::string iface;
-            try {
-                iface = string_values_->getParam("interface");
-            } catch (const DhcpConfigError &) {
-                // iface not mandatory
-            }
-
-            if (!iface.empty()) {
-                isc_throw(isc::dhcp::DhcpConfigError,
-                      "parser error: interface (defined for locally reachable "
-                      "subnets) and interface-id (defined for subnets reachable"
-                      " via relays) cannot be defined at the same time for "
-                      "subnet " << addr << "/" << (int)len);
-            }
-        }
-
-        // Gather boolean parameters values.
         bool rapid_commit = getBoolean(params, "rapid-commit");
 
         std::ostringstream output;
@@ -472,6 +442,22 @@ protected:
         Subnet6* subnet6 = new Subnet6(addr, len, t1, t2, pref, valid,
                                        subnet_id);
 
+        // Get interface-id option content. For now we support string
+        // representation only
+        std::string ifaceid = getString(params, "interface-id");
+        std::string iface = getString(params, "interface");
+
+        // Specifying both interface for locally reachable subnets and
+        // interface id for relays is mutually exclusive. Need to test for
+        // this condition.
+        if (!ifaceid.empty() && !iface.empty()) {
+            isc_throw(isc::dhcp::DhcpConfigError,
+                      "parser error: interface (defined for locally reachable "
+                      "subnets) and interface-id (defined for subnets reachable"
+                      " via relays) cannot be defined at the same time for "
+                      "subnet " << addr << "/" << (int)len);
+        }
+
         // Configure interface-id for remote interfaces, if defined
         if (!ifaceid.empty()) {
             OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
@@ -482,14 +468,6 @@ protected:
         // Enable or disable Rapid Commit option support for the subnet.
         subnet6->setRapidCommit(rapid_commit);
 
-        // Try setting up client class (if specified)
-        try {
-            string client_class = string_values_->getParam("client-class");
-            subnet6->allowClientClass(client_class);
-        } catch (const DhcpConfigError&) {
-            // That's ok if it fails. client-class is optional.
-        }
-
         subnet_.reset(subnet6);
     }
 

+ 6 - 2
src/bin/dhcp6/simple_parser6.cc

@@ -65,8 +65,12 @@ const SimpleDefaults SimpleParser6::GLOBAL6_DEFAULTS = {
 
 /// @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
+    { "id",               Element::integer, "0" }, // 0 means autogenerate
+    { "interface",        Element::string,  "" },
+    { "client-class",     Element::string,  "" },
+    { "reservation-mode", Element::string,  "all" },
+    { "rapid-commit",     Element::boolean, "false" }, // rapid-commit disabled by default
+    { "interface-id",     Element::string,  "" },
 };
 
 /// @brief List of parameters that can be inherited from the global to subnet6 scope.

+ 23 - 19
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -1129,38 +1129,42 @@ SubnetConfigParser::createSubnet(ConstElementPtr params) {
         subnet_->addPool(*it);
     }
 
-    // Configure interface, if defined
+    // Now configure parameters that are common for v4 and v6:
 
     // Get interface name. If it is defined, then the subnet is available
     // directly over specified network interface.
-    std::string iface;
-    try {
-        iface = string_values_->getParam("interface");
-    } catch (const DhcpConfigError &) {
-        // iface not mandatory so swallow the exception
+    std::string iface = getString(params, "interface");
+    if (!iface.empty()) {
+        if (!IfaceMgr::instance().getIface(iface)) {
+            isc_throw(DhcpConfigError, "Specified network interface name " << iface
+                      << " for subnet " << subnet_->toText()
+                      << " is not present" << " in the system ("
+                      << string_values_->getPosition("interface") << ")");
+        }
+
+        subnet_->setIface(iface);
     }
 
     // Let's set host reservation mode. If not specified, the default value of
     // all will be used.
-    std::string hr_mode;
     try {
-        hr_mode = string_values_->getOptionalParam("reservation-mode", "all");
+        std::string hr_mode = getString(params, "reservation-mode");
         subnet_->setHostReservationMode(hrModeFromText(hr_mode));
     } catch (const BadValue& ex) {
+        ConstElementPtr mode = params->find("reservation-mode");
+        string pos("[missing]");
+        if (mode) {
+            pos = mode->getPosition().str();
+        }
         isc_throw(DhcpConfigError, "Failed to process specified value "
                   " of reservation-mode parameter: " << ex.what()
-                  << string_values_->getPosition("reservation-mode"));
+                  << "(" << pos << ")");
     }
 
-    if (!iface.empty()) {
-        if (!IfaceMgr::instance().getIface(iface)) {
-            isc_throw(DhcpConfigError, "Specified interface name " << iface
-                      << " for subnet " << subnet_->toText()
-                      << " is not present" << " in the system ("
-                      << string_values_->getPosition("interface") << ")");
-        }
-
-        subnet_->setIface(iface);
+    // Try setting up client class.
+    string client_class = getString(params, "client-class");
+    if (!client_class.empty()) {
+        subnet_->allowClientClass(client_class);
     }
 
     // Here globally defined options were merged to the subnet specific
@@ -1254,7 +1258,7 @@ D2ClientConfigParser::getMode(const std::string& name,
 D2ClientConfigPtr
 D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     D2ClientConfigPtr new_config;
-    
+
     if (isShortCutDisabled(client_config)) {
       // If enable-updates is the only parameter and it is false then
       // we're done.  This allows for an abbreviated configuration entry

+ 19 - 2
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -806,8 +806,25 @@ protected:
 
 /// @brief this class parses a single subnet
 ///
-/// This class parses the whole subnet definition. It creates parsers
-/// for received configuration parameters as needed.
+/// There are dedicated @ref Subnet4ConfigParser and @ref Subnet6ConfigParser
+/// classes. They provide specialized parse() methods that return Subnet4Ptr
+/// or Subnet6Ptr.
+///
+/// This class parses the whole subnet definition. This class attempts to
+/// unify the code between v4 and v6 as much as possible. As a result, the flow
+/// is somewhat complex and it looks as follows:
+///
+///     ------- Base class
+///    /
+///    | /----- Derived class
+/// 1.   * SubnetXConfigParser::parse() is called.
+/// 2. *   SubnetConfigParser::parse() is called.
+/// 3. *   SubnetConfigParser::createSubnet() is called.
+/// 4.   * SubnetXConfigParser::initSubnet() is called (Subnet4 or Subnet6 is
+///        instantiated here and family specific parameters are set)
+/// 5.     Control returns to createSubnet() (step 3) and common parameters
+///        are set.
+
 class SubnetConfigParser : public isc::data::SimpleParser {
 public: