mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[5315] Moved Subnet parsers from DHCP binaries to libdhcpsrv.
This commit is contained in:
committed by
Tomek Mrugalski
parent
433313ef4c
commit
0a61518acf
@@ -21,6 +21,7 @@
|
||||
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
||||
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
||||
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
||||
#include <dhcpsrv/parsers/option_data_parser.h>
|
||||
#include <dhcpsrv/timer_mgr.h>
|
||||
#include <hooks/hooks_parser.h>
|
||||
#include <config/command_mgr.h>
|
||||
@@ -46,273 +47,6 @@ using namespace isc::hooks;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Parser for IPv4 pool definitions.
|
||||
///
|
||||
/// This is the IPv4 derivation of the PoolParser class and handles pool
|
||||
/// definitions, i.e. a list of entries of one of two syntaxes: min-max and
|
||||
/// prefix/len for IPv4 pools. Pool4 objects are created and stored in chosen
|
||||
/// PoolStorage container.
|
||||
///
|
||||
/// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
|
||||
class Pool4Parser : public PoolParser {
|
||||
protected:
|
||||
/// @brief Creates a Pool4 object given a IPv4 prefix and the prefix length.
|
||||
///
|
||||
/// @param addr is the IPv4 prefix of the pool.
|
||||
/// @param len is the prefix length.
|
||||
/// @param ignored dummy parameter to provide symmetry between the
|
||||
/// PoolParser derivations. The V6 derivation requires a third value.
|
||||
/// @return returns a PoolPtr to the new Pool4 object.
|
||||
PoolPtr poolMaker (IOAddress &addr, uint32_t len, int32_t) {
|
||||
return (PoolPtr(new Pool4(addr, len)));
|
||||
}
|
||||
|
||||
/// @brief Creates a Pool4 object given starting and ending IPv4 addresses.
|
||||
///
|
||||
/// @param min is the first IPv4 address in the pool.
|
||||
/// @param max is the last IPv4 address in the pool.
|
||||
/// @param ignored dummy parameter to provide symmetry between the
|
||||
/// PoolParser derivations. The V6 derivation requires a third value.
|
||||
/// @return returns a PoolPtr to the new Pool4 object.
|
||||
PoolPtr poolMaker (IOAddress &min, IOAddress &max, int32_t) {
|
||||
return (PoolPtr(new Pool4(min, max)));
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Specialization of the pool list parser for DHCPv4
|
||||
class Pools4ListParser : PoolsListParser {
|
||||
public:
|
||||
|
||||
/// @brief parses the actual structure
|
||||
///
|
||||
/// This method parses the actual list of pools.
|
||||
///
|
||||
/// @param pools storage container in which to store the parsed pool.
|
||||
/// @param pools_list a list of pool structures
|
||||
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
|
||||
void parse(PoolStoragePtr pools,
|
||||
isc::data::ConstElementPtr pools_list) {
|
||||
BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
|
||||
Pool4Parser parser;
|
||||
parser.parse(pools, pool, AF_INET);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// @anchor Subnet4ConfigParser
|
||||
/// @brief This class parses a single IPv4 subnet.
|
||||
///
|
||||
/// This is the IPv4 derivation of the SubnetConfigParser class and it parses
|
||||
/// the whole subnet definition. It creates parsersfor received configuration
|
||||
/// parameters as needed.
|
||||
class Subnet4ConfigParser : public SubnetConfigParser {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// stores global scope parameters, options, option definitions.
|
||||
Subnet4ConfigParser()
|
||||
:SubnetConfigParser(AF_INET) {
|
||||
}
|
||||
|
||||
/// @brief Parses a single IPv4 subnet configuration and adds to the
|
||||
/// Configuration Manager.
|
||||
///
|
||||
/// @param subnet A new subnet being configured.
|
||||
/// @return a pointer to created Subnet4 object
|
||||
Subnet4Ptr parse(ConstElementPtr subnet) {
|
||||
/// Parse Pools first.
|
||||
ConstElementPtr pools = subnet->get("pools");
|
||||
if (pools) {
|
||||
Pools4ListParser parser;
|
||||
parser.parse(pools_, pools);
|
||||
}
|
||||
|
||||
SubnetPtr generic = SubnetConfigParser::parse(subnet);
|
||||
|
||||
if (!generic) {
|
||||
isc_throw(DhcpConfigError,
|
||||
"Failed to create an IPv4 subnet (" <<
|
||||
subnet->getPosition() << ")");
|
||||
}
|
||||
|
||||
Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
|
||||
if (!sn4ptr) {
|
||||
// If we hit this, it is a programming error.
|
||||
isc_throw(Unexpected,
|
||||
"Invalid Subnet4 cast in Subnet4ConfigParser::parse");
|
||||
}
|
||||
|
||||
// Set relay information if it was parsed
|
||||
if (relay_info_) {
|
||||
sn4ptr->setRelayInfo(*relay_info_);
|
||||
}
|
||||
|
||||
// Parse Host Reservations for this subnet if any.
|
||||
ConstElementPtr reservations = subnet->get("reservations");
|
||||
if (reservations) {
|
||||
HostCollection hosts;
|
||||
HostReservationsListParser<HostReservationParser4> parser;
|
||||
parser.parse(subnet_->getID(), reservations, hosts);
|
||||
for (auto h = hosts.begin(); h != hosts.end(); ++h) {
|
||||
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
|
||||
}
|
||||
}
|
||||
|
||||
return (sn4ptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Instantiates the IPv4 Subnet based on a given IPv4 address
|
||||
/// and prefix length.
|
||||
///
|
||||
/// @param addr is IPv4 address of the subnet.
|
||||
/// @param len is the prefix length
|
||||
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.
|
||||
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 = 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
|
||||
// SimpleParser4::setAllDefaults.
|
||||
SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
|
||||
|
||||
stringstream s;
|
||||
s << addr << "/" << static_cast<int>(len) << " with params: ";
|
||||
// t1 and t2 are optional may be not specified.
|
||||
if (!t1.unspecified()) {
|
||||
s << "t1=" << t1 << ", ";
|
||||
}
|
||||
if (!t2.unspecified()) {
|
||||
s << "t2=" << t2 << ", ";
|
||||
}
|
||||
s <<"valid-lifetime=" << valid;
|
||||
|
||||
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(s.str());
|
||||
|
||||
Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
|
||||
subnet_ = subnet4;
|
||||
|
||||
// Set the match-client-id value for the subnet. It is always present.
|
||||
// If not explicitly specified, the default value was filled in when
|
||||
// SimpleParser4::setAllDefaults was called.
|
||||
bool match_client_id = getBoolean(params, "match-client-id");
|
||||
subnet4->setMatchClientId(match_client_id);
|
||||
|
||||
// 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 {
|
||||
next_server = getString(params, "next-server");
|
||||
if (!next_server.empty()) {
|
||||
subnet4->setSiaddr(IOAddress(next_server));
|
||||
}
|
||||
} catch (...) {
|
||||
ConstElementPtr next = params->get("next-server");
|
||||
string pos;
|
||||
if (next)
|
||||
pos = next->getPosition().str();
|
||||
else
|
||||
pos = params->getPosition().str();
|
||||
isc_throw(DhcpConfigError, "invalid parameter next-server : "
|
||||
<< next_server << "(" << pos << ")");
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
|
||||
<< subnet4o6 << ", expected format: prefix6/length");
|
||||
}
|
||||
string prefix = subnet4o6.substr(0, slash);
|
||||
string lenstr = subnet4o6.substr(slash + 1);
|
||||
|
||||
uint8_t len = 128;
|
||||
try {
|
||||
len = boost::lexical_cast<unsigned int>(lenstr.c_str());
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
isc_throw(DhcpConfigError, "Invalid prefix length specified in "
|
||||
"4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
|
||||
}
|
||||
subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
|
||||
subnet4->get4o6().enabled(true);
|
||||
}
|
||||
|
||||
// Try 4o6 specific parameter: 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);
|
||||
}
|
||||
|
||||
/// client-class processing is now generic and handled in the common
|
||||
/// code (see @ref isc::data::SubnetConfigParser::createSubnet)
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief this class parses list of DHCP4 subnets
|
||||
///
|
||||
/// This is a wrapper parser that handles the whole list of Subnet4
|
||||
/// definitions. It iterates over all entries and creates Subnet4ConfigParser
|
||||
/// for each entry.
|
||||
class Subnets4ListConfigParser : public isc::data::SimpleParser {
|
||||
public:
|
||||
|
||||
/// @brief parses contents of the list
|
||||
///
|
||||
/// Iterates over all entries on the list, parses its content
|
||||
/// (by instantiating Subnet6ConfigParser) and adds to specified
|
||||
/// configuration.
|
||||
///
|
||||
/// @param subnets_list pointer to a list of IPv4 subnets
|
||||
/// @return number of subnets created
|
||||
size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
|
||||
size_t cnt = 0;
|
||||
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
|
||||
|
||||
Subnet4ConfigParser parser;
|
||||
Subnet4Ptr subnet = parser.parse(subnet_json);
|
||||
if (subnet) {
|
||||
|
||||
// Adding a subnet to the Configuration Manager may fail if the
|
||||
// subnet id is invalid (duplicate). Thus, we catch exceptions
|
||||
// here to append a position in the configuration string.
|
||||
try {
|
||||
cfg->getCfgSubnets4()->add(subnet);
|
||||
cnt++;
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< subnet_json->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Parser that takes care of global DHCPv4 parameters.
|
||||
///
|
||||
/// See @ref parse method for a list of supported parameters.
|
||||
|
Reference in New Issue
Block a user