From: Tomek Mrugalski Date: Fri, 27 Jan 2017 14:16:48 +0000 (+0100) Subject: [5122] initSubnet migrated to SimpleParser X-Git-Tag: trac5126_base~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22c37c19257b6dc3f87caf60fb98d61b15a816af;p=thirdparty%2Fkea.git [5122] initSubnet migrated to SimpleParser --- diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index 5b60f5be23..fdae34ccec 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/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 t1 = getOptionalParam("renew-timer"); - Triplet t2 = getOptionalParam("rebind-timer"); + Triplet t1 = getInteger(params, "renew-timer"); + Triplet 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 valid = getParam("valid-lifetime"); + Triplet 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 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. - } } }; diff --git a/src/bin/dhcp4/simple_parser4.cc b/src/bin/dhcp4/simple_parser4.cc index 3ed99e2aed..a02b2a8c04 100644 --- a/src/bin/dhcp4/simple_parser4.cc +++ b/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. diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 406325e20d..842cdd5291 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/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 t1 = getParam("renew-timer"); - Triplet t2 = getParam("rebind-timer"); - Triplet pref = getParam("preferred-lifetime"); - Triplet valid = getParam("valid-lifetime"); + Triplet t1 = getInteger(params, "renew-timer"); + Triplet t2 = getInteger(params, "rebind-timer"); + Triplet pref = getInteger(params, "preferred-lifetime"); + Triplet 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(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); } diff --git a/src/bin/dhcp6/simple_parser6.cc b/src/bin/dhcp6/simple_parser6.cc index 957bd5842c..a3e53fa552 100644 --- a/src/bin/dhcp6/simple_parser6.cc +++ b/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. diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index e68af3ff21..34aff43bb4 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/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 diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index af11df151e..ef56466c56 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/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: