// done here.
subnet = subnet->getNextSubnet(ctx.subnet_, classes);
}
+
+ // The hosts can be used by the server to return reserved options to
+ // the DHCP client. Such options must be encapsulated (i.e., they must
+ // include suboptions).
+ for (auto host : ctx.hosts_) {
+ host.second->encapsulateOptions();
+ }
}
ConstHostPtr
// done here.
subnet = subnet->getNextSubnet(ctx.subnet_, classes);
}
+
+ // The hosts can be used by the server to return reserved options to
+ // the DHCP client. Such options must be encapsulated (i.e., they must
+ // include suboptions).
+ for (auto host : ctx.hosts_) {
+ host.second->encapsulateOptions();
+ }
}
ConstHostPtr
option_->equals(other.option_));
}
-CfgOption::CfgOption() {
+CfgOption::CfgOption()
+ : encapsulated_(false) {
}
bool
encapsulateInternal(DHCP4_OPTION_SPACE);
// Append sub-options to the top level "dhcp6" option space.
encapsulateInternal(DHCP6_OPTION_SPACE);
+ encapsulated_ = true;
}
void
/// options from this option space are appended to top-level options.
void encapsulate();
+ /// @brief Checks if options have been encapsulated.
+ ///
+ /// @return true if options have been encapsulated, false otherwise.
+ bool isEncapsulated() const {
+ return (encapsulated_);
+ }
+
/// @brief Returns all options for the specified option space.
///
/// This method will not return vendor options, i.e. having option space
OptionSpaceContainer<OptionContainer,
OptionDescriptor, Selector>& dest_container) const;
+ /// @brief A flag indicating if options have been encapsulated.
+ bool encapsulated_;
+
/// @brief Type of the container holding options grouped by option space.
typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
std::string> OptionSpaceCollection;
return (map);
}
+void
+Host::encapsulateOptions() const {
+ if (!cfg_option4_->isEncapsulated()) {
+ cfg_option4_->encapsulate();
+ }
+ if (!cfg_option6_->isEncapsulated()) {
+ cfg_option6_->encapsulate();
+ }
+}
+
std::string
Host::toText() const {
std::ostringstream s;
return (cfg_option6_);
}
+ /// @brief Encapsulates host-specific options with their suboptions.
+ ///
+ /// This function must be called before the server returns host-specific
+ /// DHCP options to the client.
+ void encapsulateOptions() const;
+
/// @brief Returns information about the host in the textual format.
std::string toText() const;
def = LibDHCP::getRuntimeOptionDef(space, code_);
}
+ // Finish with a last resort option definition.
+ if (!def) {
+ def = LibDHCP::getLastResortOptionDef(space, code_);
+ }
+
OptionPtr option;
+ // If no definition found, we use generic option type.
if (!def) {
- // If no definition found, we use generic option type.
- OptionBuffer buf(value_, value_ + value_length_);
- option.reset(new Option(universe_, code_, buf.begin(),
- buf.end()));
+ // We have to pay attention if the value is NULL. If it is,
+ // we must create an empty option instance. We can't rely on
+ // the value_length_ because it may contain garbage for the
+ // null values. Thus we check explicitly whether or not the
+ // NULL flag is set.
+ if (value_null_ == MLM_FALSE) {
+ OptionBuffer buf(value_, value_ + value_length_);
+ option.reset(new Option(universe_, code_, buf.begin(),
+ buf.end()));
+ } else {
+ option.reset(new Option(universe_, code_));
+ }
} else {
// The option value may be specified in textual or binary format
// in the database. If formatted_value is empty, the binary
// variant of the optionFactory function.
if (formatted_value.empty()) {
OptionBuffer buf(value_, value_ + value_length_);
+ // Again, check if the value is null before submitting the
+ // buffer to the factory function.
option = def->optionFactory(universe_, code_, buf.begin(),
- buf.end());
- } else {
+ value_null_ == MLM_FALSE ? buf.end() :
+ buf.begin());
+ } else {
// Spit the value specified in comma separated values
// format.
std::vector<std::string> split_vec;
void
PoolParser::parse(PoolStoragePtr pools,
ConstElementPtr pool_structure,
- const uint16_t address_family) {
+ const uint16_t address_family,
+ bool encapsulate_options) {
if (address_family == AF_INET) {
checkKeywords(SimpleParser4::POOL4_PARAMETERS, pool_structure);
try {
CfgOptionPtr cfg = pool->getCfgOption();
auto option_parser = createOptionDataListParser(address_family);
- option_parser->parse(cfg, option_data);
+ option_parser->parse(cfg, option_data, encapsulate_options);
} catch (const std::exception& ex) {
isc_throw(isc::dhcp::DhcpConfigError, ex.what()
<< " (" << option_data->getPosition() << ")");
//****************************** Pools4ListParser *************************
void
-Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) {
+Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list,
+ bool encapsulate_options) {
BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
auto parser = createPoolConfigParser();
- parser->parse(pools, pool, AF_INET);
+ parser->parse(pools, pool, AF_INET, encapsulate_options);
}
}
SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface)
: pools_(new PoolStorage()),
address_family_(family),
- options_(new CfgOption()),
check_iface_(check_iface) {
relay_info_.reset(new isc::dhcp::Network::RelayInfo());
}
SubnetPtr
-SubnetConfigParser::parse(ConstElementPtr subnet) {
-
- ConstElementPtr options_params = subnet->get("option-data");
- if (options_params) {
- auto opt_parser = createOptionDataListParser();
- opt_parser->parse(options_, options_params);
- }
+SubnetConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
ConstElementPtr relay_params = subnet->get("relay");
if (relay_params) {
"subnet configuration failed: " << ex.what());
}
+ ConstElementPtr options_params = subnet->get("option-data");
+ if (options_params) {
+ auto opt_parser = createOptionDataListParser();
+ opt_parser->parse(subnet_->getCfgOption(), options_params, encapsulate_options);
+ }
+
return (subnet_);
}
}
Subnet4Ptr
-Subnet4ConfigParser::parse(ConstElementPtr subnet) {
+Subnet4ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
// Check parameters.
checkKeywords(SimpleParser4::SUBNET4_PARAMETERS, subnet);
ConstElementPtr pools = subnet->get("pools");
if (pools) {
auto parser = createPoolsListParser();
- parser->parse(pools_, pools);
+ parser->parse(pools_, pools, encapsulate_options);
}
- SubnetPtr generic = SubnetConfigParser::parse(subnet);
+ SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
if (!generic) {
// Sanity check: not supposed to fail.
// options but this is no longer the case (they have a different
// and not consecutive priority).
- // Copy options to the subnet configuration.
- options_->copyTo(*subnet4->getCfgOption());
-
// Parse t1-percent and t2-percent
parseTeePercents(params, network);
size_t
Subnets4ListConfigParser::parse(SrvConfigPtr cfg,
- ConstElementPtr subnets_list) {
+ ConstElementPtr subnets_list,
+ bool encapsulate_options) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
auto parser = createSubnetConfigParser();
- Subnet4Ptr subnet = parser->parse(subnet_json);
+ Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
if (subnet) {
// Adding a subnet to the Configuration Manager may fail if the
size_t
Subnets4ListConfigParser::parse(Subnet4Collection& subnets,
- data::ConstElementPtr subnets_list) {
+ data::ConstElementPtr subnets_list,
+ bool encapsulate_options) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
auto parser = createSubnetConfigParser();
- Subnet4Ptr subnet = parser->parse(subnet_json);
+ Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
if (subnet) {
try {
auto ret = subnets.insert(subnet);
//**************************** Pool6ListParser ***************************
void
-Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) {
+Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list,
+ bool encapsulate_options) {
BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
auto parser = createPoolConfigParser();
- parser->parse(pools, pool, AF_INET6);
+ parser->parse(pools, pool, AF_INET6, encapsulate_options);
}
}
//**************************** PdPoolParser ******************************
-PdPoolParser::PdPoolParser() : options_(new CfgOption()) {
+PdPoolParser::PdPoolParser() {
}
void
-PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
+PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_,
+ bool encapsulate_options) {
checkKeywords(SimpleParser6::PD_POOL6_PARAMETERS, pd_pool_);
std::string addr_str = getString(pd_pool_, "prefix");
excluded_prefix_len = getUint8(pd_pool_, "excluded-prefix-len");
}
- ConstElementPtr option_data = pd_pool_->get("option-data");
- if (option_data) {
- auto opts_parser = createOptionDataListParser();
- opts_parser->parse(options_, option_data);
- }
-
ConstElementPtr user_context = pd_pool_->get("user-context");
if (user_context) {
user_context_ = user_context;
delegated_len,
IOAddress(excluded_prefix_str),
excluded_prefix_len));
- // Merge options specified for a pool into pool configuration.
- options_->copyTo(*pool_->getCfgOption());
} catch (const std::exception& ex) {
// Some parameters don't exist or are invalid. Since we are not
// aware whether they don't exist or are invalid, let's append
<< " (" << pd_pool_->getPosition() << ")");
}
+ ConstElementPtr option_data = pd_pool_->get("option-data");
+ if (option_data) {
+ auto opts_parser = createOptionDataListParser();
+ opts_parser->parse(pool_->getCfgOption(), option_data, encapsulate_options);
+ }
+
if (user_context_) {
pool_->setContext(user_context_);
}
}
Subnet6Ptr
-Subnet6ConfigParser::parse(ConstElementPtr subnet) {
+Subnet6ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
// Check parameters.
checkKeywords(SimpleParser6::SUBNET6_PARAMETERS, subnet);
ConstElementPtr pools = subnet->get("pools");
if (pools) {
auto parser = createPoolsListParser();
- parser->parse(pools_, pools);
+ parser->parse(pools_, pools, encapsulate_options);
}
ConstElementPtr pd_pools = subnet->get("pd-pools");
if (pd_pools) {
parser->parse(pools_, pd_pools);
}
- SubnetPtr generic = SubnetConfigParser::parse(subnet);
+ SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
if (!generic) {
// Sanity check: not supposed to fail.
/// client-class processing is now generic and handled in the common
/// code (see isc::data::SubnetConfigParser::createSubnet)
- // Copy options to the subnet configuration.
- options_->copyTo(*subnet6->getCfgOption());
-
// Parse t1-percent and t2-percent
parseTeePercents(params, network);
size_t
Subnets6ListConfigParser::parse(SrvConfigPtr cfg,
- ConstElementPtr subnets_list) {
+ ConstElementPtr subnets_list,
+ bool encapsulate_options) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
auto parser = createSubnetConfigParser();
- Subnet6Ptr subnet = parser->parse(subnet_json);
+ Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
// Adding a subnet to the Configuration Manager may fail if the
// subnet id is invalid (duplicate). Thus, we catch exceptions
size_t
Subnets6ListConfigParser::parse(Subnet6Collection& subnets,
- ConstElementPtr subnets_list) {
+ ConstElementPtr subnets_list,
+ bool encapsulate_options) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
auto parser = createSubnetConfigParser();
- Subnet6Ptr subnet = parser->parse(subnet_json);
+ Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
if (subnet) {
try {
auto ret = subnets.insert(subnet);
/// @param pools is the storage in which to store the parsed pool
/// @param pool_structure a single entry on a list of pools
/// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6).
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
virtual void parse(PoolStoragePtr pools,
isc::data::ConstElementPtr pool_structure,
- const uint16_t address_family);
+ const uint16_t address_family,
+ bool encapsulate_options = true);
protected:
/// @brief Creates a Pool object given a IPv4 prefix and the prefix length.
///
/// @param pools is the storage in which to store the parsed pools.
/// @param pools_list a list of pool structures
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
virtual void parse(PoolStoragePtr pools,
- isc::data::ConstElementPtr pools_list) = 0;
+ isc::data::ConstElementPtr pools_list,
+ bool encapsulate_options) = 0;
protected:
///
/// @param pools storage container in which to store the parsed pool.
/// @param pools_list a list of pool structures
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
- void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list);
+ void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list,
+ bool encapsulate_options = true);
protected:
/// Subnet6ConfigParser) classes.
///
/// @param subnet pointer to the content of subnet definition
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @return a pointer to newly created subnet
///
/// @throw isc::DhcpConfigError if subnet configuration parsing failed.
- SubnetPtr parse(isc::data::ConstElementPtr subnet);
+ SubnetPtr parse(isc::data::ConstElementPtr subnet,
+ bool encapsulate_options);
/// @brief Instantiates the subnet based on a given IP prefix and prefix
/// length.
/// Pointer to relay information
isc::dhcp::Network::RelayInfoPtr relay_info_;
- /// Pointer to the options configuration.
- CfgOptionPtr options_;
-
/// Check if the specified interface exists in the system.
bool check_iface_;
};
/// Configuration Manager.
///
/// @param subnet A new subnet being configured.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @return a pointer to created Subnet4 object
- Subnet4Ptr parse(data::ConstElementPtr subnet);
+ Subnet4Ptr parse(data::ConstElementPtr subnet,
+ bool encapsulate_options = true);
protected:
///
/// @param cfg Pointer to server configuration.
/// @param subnets_list pointer to a list of IPv4 subnets
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @return number of subnets created
- size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list);
+ size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list,
+ bool encapsulate_options = true);
/// @brief Parses contents of the subnet4 list.
///
/// @param [out] subnets Container where parsed subnets will be stored.
/// @param subnets_list pointer to a list of IPv4 subnets
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @return Number of subnets created.
size_t parse(Subnet4Collection& subnets,
- data::ConstElementPtr subnets_list);
+ data::ConstElementPtr subnets_list,
+ bool encapsulate_options = true);
protected:
///
/// @param pools storage container in which to store the parsed pool.
/// @param pools_list a list of pool structures
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
- void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list);
+ void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list,
+ bool encapsulate_options = true);
protected:
/// @param pools storage container in which to store the parsed pool.
/// @param pd_pool_ pointer to an element that holds configuration entries
/// that define a prefix delegation pool.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @throw DhcpConfigError if configuration parsing fails.
- void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_);
+ void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_,
+ bool encapsulate_options = true);
protected:
/// Pointer to the created pool object.
isc::dhcp::Pool6Ptr pool_;
- /// A storage for pool specific option values.
- CfgOptionPtr options_;
-
/// @brief User context (optional, may be null)
///
/// User context is arbitrary user data, to be used by hooks.
/// Configuration Manager.
///
/// @param subnet A new subnet being configured.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @return a pointer to created Subnet6 object
- Subnet6Ptr parse(data::ConstElementPtr subnet);
+ Subnet6Ptr parse(data::ConstElementPtr subnet,
+ bool encapsulate_options = true);
protected:
/// @brief Issues a DHCP6 server specific warning regarding duplicate subnet
///
/// @param cfg configuration (parsed subnets will be stored here)
/// @param subnets_list pointer to a list of IPv6 subnets
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
/// @throw DhcpConfigError if CfgMgr rejects the subnet (e.g. subnet-id is a duplicate)
- size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list);
+ size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list,
+ bool encapsulate_options = true);
/// @brief Parses contents of the subnet6 list.
///
/// @param subnets_list pointer to a list of IPv6 subnets
/// @return Number of subnets created.
size_t parse(Subnet6Collection& subnets,
- data::ConstElementPtr subnets_list);
+ data::ConstElementPtr subnets_list,
+ bool encapsulate_options = true);
protected:
HostPtr
HostReservationParser::parse(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data) {
- return (parseInternal(subnet_id, reservation_data));
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options) {
+ return (parseInternal(subnet_id, reservation_data, encapsulate_options));
}
HostPtr
HostReservationParser::parseInternal(const SubnetID&,
- isc::data::ConstElementPtr reservation_data) {
+ isc::data::ConstElementPtr reservation_data,
+ bool) {
std::string identifier;
std::string identifier_name;
std::string hostname;
HostPtr
HostReservationParser4::parseInternal(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data) {
- HostPtr host = HostReservationParser::parseInternal(subnet_id, reservation_data);
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options) {
+ HostPtr host = HostReservationParser::parseInternal(subnet_id, reservation_data,
+ encapsulate_options);
host->setIPv4SubnetID(subnet_id);
// parses the Element structure immediately, there's no need
// to go through build/commit phases.
OptionDataListParser parser(AF_INET);
- parser.parse(cfg_option, element.second);
+ parser.parse(cfg_option, element.second, encapsulate_options);
// Everything else should be surrounded with try-catch to append
// position.
HostPtr
HostReservationParser6::parseInternal(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data) {
- HostPtr host = HostReservationParser::parseInternal(subnet_id, reservation_data);
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options) {
+ HostPtr host = HostReservationParser::parseInternal(subnet_id, reservation_data,
+ encapsulate_options);
host->setIPv6SubnetID(subnet_id);
// parses the Element structure immediately, there's no need
// to go through build/commit phases.
OptionDataListParser parser(AF_INET6);
- parser.parse(cfg_option, element.second);
+ parser.parse(cfg_option, element.second, encapsulate_options);
} else if (element.first == "ip-addresses" || element.first == "prefixes") {
BOOST_FOREACH(ConstElementPtr prefix_element,
/// connected to.
/// @param reservation_data Data element holding map with a host
/// reservation configuration.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to the object representing parsed host.
/// @throw DhcpConfigError If the configuration is invalid.
virtual HostPtr
parse(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data) final;
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options = true) final;
protected:
/// connected to.
/// @param reservation_data Data element holding map with a host
/// reservation configuration.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to the object representing parsed host.
/// @throw DhcpConfigError If the configuration is invalid.
virtual HostPtr parseInternal(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data);
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options);
/// @brief Checks if the specified parameter is a host identifier.
///
/// connected to.
/// @param reservation_data Data element holding map with a host
/// reservation configuration.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to the object representing parsed host.
/// @throw DhcpConfigError If the configuration is invalid.
virtual HostPtr parseInternal(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data);
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options);
/// @brief Returns set of the supported parameters for DHCPv4.
///
/// connected to.
/// @param reservation_data Data element holding map with a host
/// reservation configuration.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to the object representing parsed host.
/// @throw DhcpConfigError If the configuration is invalid.
virtual HostPtr parseInternal(const SubnetID& subnet_id,
- isc::data::ConstElementPtr reservation_data);
+ isc::data::ConstElementPtr reservation_data,
+ bool encapsulate_options);
/// @brief Returns set of the supported parameters for DHCPv6.
///
void OptionDataListParser::parse(const CfgOptionPtr& cfg,
- isc::data::ConstElementPtr option_data_list) {
+ isc::data::ConstElementPtr option_data_list,
+ bool encapsulate) {
auto option_parser = createOptionDataParser();
BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) {
std::pair<OptionDescriptor, std::string> option =
option_parser->parse(data);
// Use the option description to keep the formatted value
cfg->add(option.first, option.second);
- cfg->encapsulate();
+ if (encapsulate) {
+ cfg->encapsulate();
+ }
}
}
///
/// @param cfg created options will be stored here
/// @param option_data_list configuration that describes the options
+ /// @param encapsulate a boolean value indicating whether or not the
+ /// parser should encapsulate options with suboptions. The default
+ /// value is true (encapsulate).
void parse(const CfgOptionPtr& cfg,
- isc::data::ConstElementPtr option_data_list);
+ isc::data::ConstElementPtr option_data_list,
+ bool encapsulate = true);
protected:
/// @brief Returns an instance of the @c OptionDataListParser to
}
SharedNetwork4Ptr
-SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) {
+SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data,
+ bool encapsulate_options) {
SharedNetwork4Ptr shared_network;
try {
// Create parser instance for option-data.
CfgOptionPtr cfg_option = shared_network->getCfgOption();
auto parser = createOptionDataListParser();
- parser->parse(cfg_option, json);
+ parser->parse(cfg_option, json, encapsulate_options);
}
if (shared_network_data->contains("subnet4")) {
}
SharedNetwork6Ptr
-SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) {
+SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data,
+ bool encapsulate_options) {
SharedNetwork6Ptr shared_network;
std::string name;
try {
// Create parser instance for option-data.
CfgOptionPtr cfg_option = shared_network->getCfgOption();
auto parser = createOptionDataListParser();
- parser->parse(cfg_option, json);
+ parser->parse(cfg_option, json, encapsulate_options);
}
if (shared_network_data->contains("client-class")) {
///
/// @param shared_network_data Data element holding shared network
/// configuration to be parsed.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to an object representing shared network.
/// @throw DhcpConfigError when shared network configuration is invalid.
SharedNetwork4Ptr
- parse(const data::ConstElementPtr& shared_network_data);
+ parse(const data::ConstElementPtr& shared_network_data,
+ bool encapsulate_options = true);
protected:
///
/// @param shared_network_data Data element holding shared network
/// configuration to be parsed.
+ /// @param encapsulate_options a boolean parameter indicating if the
+ /// parsed options should be encapsulated with suboptions.
///
/// @return Pointer to an object representing shared network.
/// @throw DhcpConfigError when shared network configuration is invalid.
SharedNetwork6Ptr
- parse(const data::ConstElementPtr& shared_network_data);
+ parse(const data::ConstElementPtr& shared_network_data,
+ bool encapsulate_options = true);
protected:
def = LibDHCP::getRuntimeOptionDef(space, code);
}
+ // Finish with a last resort option definition.
+ if (!def) {
+ def = LibDHCP::getLastResortOptionDef(space, code);
+ }
+
OptionPtr option;
if (!def) {
generateEncapsulatedOptions(cfg);
+ EXPECT_FALSE(cfg.isEncapsulated());
+
// Append options from "foo" and "bar" space as sub-options and options
// from "foo-subs" and "bar-subs" as sub-options of "foo" and "bar"
// options.
ASSERT_NO_THROW(cfg.encapsulate());
+ EXPECT_TRUE(cfg.isEncapsulated());
+
// Verify that we have 40 top-level options.
OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
ASSERT_EQ(40, options->size());
EXPECT_TRUE(options->empty());
}
+// This test checks that host-specific DHCPv4 options can be encapsulated.
+TEST_F(HostTest, encapsulateOptions4) {
+ Host host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2),
+ IOAddress("192.0.2.3"));
+
+ OptionPtr option43(new Option(Option::V4, DHO_VENDOR_ENCAPSULATED_OPTIONS));
+ option43->setEncapsulatedSpace(VENDOR_ENCAPSULATED_OPTION_SPACE);
+ ASSERT_NO_THROW(host.getCfgOption4()->add(option43, false, false, DHCP4_OPTION_SPACE));
+
+ OptionPtr option1(new Option(Option::V4, 1));
+ ASSERT_NO_THROW(host.getCfgOption4()->add(option1, false, false,
+ VENDOR_ENCAPSULATED_OPTION_SPACE));
+
+ ASSERT_NO_THROW(host.encapsulateOptions());
+
+ auto returned_option43 = host.getCfgOption4()->get(DHCP4_OPTION_SPACE,
+ DHO_VENDOR_ENCAPSULATED_OPTIONS);
+ ASSERT_TRUE(returned_option43.option_);
+
+ auto returned_option1 = returned_option43.option_->getOption(1);
+ ASSERT_TRUE(returned_option1);
+}
+
// This test checks that it is possible to add DHCPv6 options for a host.
TEST_F(HostTest, addOptions6) {
Host host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2),
EXPECT_TRUE(options->empty());
}
+// This test checks that it is possible to add DHCPv6 options for a host.
+TEST_F(HostTest, encapsulateOptions6) {
+ Host host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2),
+ IOAddress("192.0.2.3"));
+
+ OptionPtr option94(new Option(Option::V6, D6O_S46_CONT_MAPE));
+ option94->setEncapsulatedSpace(MAPE_V6_OPTION_SPACE);
+ ASSERT_NO_THROW(host.getCfgOption6()->add(option94, false, false, DHCP6_OPTION_SPACE));
+
+ OptionPtr option1(new Option(Option::V6, 1));
+ ASSERT_NO_THROW(host.getCfgOption6()->add(option1, false, false,
+ MAPE_V6_OPTION_SPACE));
+
+ ASSERT_NO_THROW(host.encapsulateOptions());
+
+ auto returned_option94 = host.getCfgOption6()->get(DHCP6_OPTION_SPACE,
+ D6O_S46_CONT_MAPE);
+ ASSERT_TRUE(returned_option94.option_);
+
+ auto returned_option1 = returned_option94.option_->getOption(1);
+ ASSERT_TRUE(returned_option1);
+}
+
// This test verifies that it is possible to retrieve a textual
// representation of the host identifier.
TEST_F(HostTest, getIdentifierAsText) {
DHCP4_OPTION_SPACE);
opts->add(createOption<OptionUint32>(Option::V4, 1, false, false,
formatted, 312131),
- "vendor-encapsulated-options");
+ "vendor-encapsulated-options-space");
opts->add(createAddressOption<Option4AddrLst>(254, false, false,
formatted, "192.0.2.3"),
DHCP4_OPTION_SPACE);
formatted, "10.0.0.5",
"10.0.0.3", "10.0.3.4"),
"isc");
+ auto def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE,
+ DHO_VENDOR_ENCAPSULATED_OPTIONS);
+ opts->add(OptionDescriptor(def->optionFactory(Option::V4,
+ DHO_VENDOR_ENCAPSULATED_OPTIONS,
+ OptionBuffer()),
+ true, false), DHCP4_OPTION_SPACE);
// Add definitions for DHCPv4 non-standard options.
defs.addItem(OptionDefinitionPtr(new OptionDefinition(
"vendor-encapsulated-1", 1,
- "vendor-encapsulated-options", "uint32")));
+ "vendor-encapsulated-options-space", "uint32")));
defs.addItem(OptionDefinitionPtr(new OptionDefinition(
"option-254", 254, DHCP4_OPTION_SPACE,
"ipv4-address", true)));
ASSERT_EQ(1, hosts_by_subnet.size());
ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_subnet.begin()));
+ auto returned_host = *hosts_by_subnet.begin();
+ ASSERT_NO_THROW(returned_host->encapsulateOptions());
+ auto cfg_option = returned_host->getCfgOption4();
+
+ auto option43 = cfg_option->get(DHCP4_OPTION_SPACE, DHO_VENDOR_ENCAPSULATED_OPTIONS);
+ ASSERT_TRUE(option43.option_);
+
+ EXPECT_TRUE(cfg_option->get("vendor-encapsulated-options-space", 1).option_);
+
+ auto option43_1 = option43.option_->getOption(1);
+ EXPECT_TRUE(option43_1);
+
// getAll4(address)
ConstHostCollection hosts_by_addr =
hdsptr_->getAll4(host->getIPv4Reservation());