// Class options also need to be created when returned from the config backend.
client_classes.createOptions(external_cfg->getCfgOptionDef());
+ client_classes.encapsulateOptions();
external_cfg->setClientClassDictionary(boost::make_shared<ClientClassDictionary>(client_classes));
}
// Class options also need to be created when returned from the config backend.
client_classes.createOptions(external_cfg->getCfgOptionDef());
+ client_classes.encapsulateOptions();
external_cfg->setClientClassDictionary(boost::make_shared<ClientClassDictionary>(client_classes));
}
other.options_.clearItems();
other.vendor_options_.clearItems();
mergeTo(other);
+ other.encapsulated_ = isEncapsulated();
}
void
// Create the network's options based on the given definitions.
other_network->getCfgOption()->createOptions(cfg_def);
- // Add the new/updated nework.
+ // Encapsulate options, so that the DHCP server can effectively return
+ // them to the clients without having to encapsulate them for each request.
+ other_network->getCfgOption()->encapsulate();
+
+ // Add the new/updated network.
static_cast<void>(networks_.push_back(other_network));
}
}
// Create the subnet's options based on the given definitions.
other_subnet->getCfgOption()->createOptions(cfg_def);
+ // Encapsulate options, so that the DHCP server can effectively return
+ // them to the clients without having to encapsulate them for each request.
+ other_subnet->getCfgOption()->encapsulate();
+
// Create the options for pool based on the given definitions.
for (auto const& pool : other_subnet->getPoolsWritable(Lease::TYPE_V4)) {
pool->getCfgOption()->createOptions(cfg_def);
+ pool->getCfgOption()->encapsulate();
}
// Add the "other" subnet to the our collection of subnets.
// Create the subnet's options based on the given definitions.
other_subnet->getCfgOption()->createOptions(cfg_def);
+ // Encapsulate options, so that the DHCP server can effectively return
+ // them to the clients without having to encapsulate them for each request.
+ other_subnet->getCfgOption()->encapsulate();
+
// Create the options for pool based on the given definitions.
for (auto const& pool : other_subnet->getPoolsWritable(Lease::TYPE_NA)) {
pool->getCfgOption()->createOptions(cfg_def);
+ pool->getCfgOption()->encapsulate();
}
// Create the options for pd pool based on the given definitions.
for (auto const& pool : other_subnet->getPoolsWritable(Lease::TYPE_PD)) {
pool->getCfgOption()->createOptions(cfg_def);
+ pool->getCfgOption()->encapsulate();
}
// Add the "other" subnet to the our collection of subnets.
// First we need to remove statistics.
getCurrentCfg()->removeStatistics();
mergeIntoCfg(getCurrentCfg(), seq);
+ LibDHCP::setRuntimeOptionDefs(getCurrentCfg()->getCfgOptionDef()->getContainer());
} catch (...) {
// Make sure the statistics is updated even if the merge failed.
}
}
+void
+ClientClassDictionary::encapsulateOptions() const {
+ for (auto const& c : *list_) {
+ CfgOptionPtr class_options = c->getCfgOption();
+ if (class_options) {
+ class_options->encapsulate();
+ }
+ }
+}
+
ElementPtr
ClientClassDictionary::toElement() const {
ElementPtr result = Element::createList();
/// @param cfg_option_def set of option definitions to use.
void createOptions(const CfgOptionDefPtr& cfg_option_def);
+ /// @brief Iterates over the classes in the dictionary and encapsulates
+ /// suboptions.
+ void encapsulateOptions() const;
+
/// @brief Equality operator.
///
/// @param other Other client class dictionary to compare to.
(getTimestamp("dhcp4_options") > lb_modification_time)) {
ASSERT_TRUE(found_opt.option_);
EXPECT_EQ("new.example.com", found_opt.option_->toString());
+ EXPECT_TRUE(options->isEncapsulated());
} else {
EXPECT_FALSE(found_opt.option_);
(getTimestamp("dhcp4_shared_network") > lb_modification_time)) {
ASSERT_TRUE(found_network);
EXPECT_TRUE(found_network->hasFetchGlobalsFn());
+ EXPECT_TRUE(found_network->getCfgOption()->isEncapsulated());
} else {
EXPECT_FALSE(found_network);
EXPECT_TRUE(found_subnet->hasFetchGlobalsFn());
EXPECT_TRUE(boost::dynamic_pointer_cast<RandomAllocator>
(found_subnet->getAllocator(Lease::TYPE_V4)));
+ EXPECT_TRUE(found_subnet->getCfgOption()->isEncapsulated());
} else {
EXPECT_FALSE(found_subnet);
EXPECT_EQ(OptionBuffer(option_desc.formatted_value_.begin(),
option_desc.formatted_value_.end()),
option->getData());
+
+ // Make sure that the options have been encapsulated.
+ EXPECT_TRUE(cfg_option_desc->isEncapsulated());
} else {
EXPECT_FALSE(found_class);
}
(getTimestamp("dhcp6_options") > lb_modification_time)) {
ASSERT_TRUE(found_opt.option_);
EXPECT_EQ("some.bootfile", found_opt.option_->toString());
+ EXPECT_TRUE(options->isEncapsulated());
} else {
EXPECT_FALSE(found_opt.option_);
(getTimestamp("dhcp6_shared_network") > lb_modification_time)) {
ASSERT_TRUE(found_network);
EXPECT_TRUE(found_network->hasFetchGlobalsFn());
+ EXPECT_TRUE(found_network->getCfgOption()->isEncapsulated());
} else {
EXPECT_FALSE(found_network);
EXPECT_TRUE(boost::dynamic_pointer_cast<RandomAllocator>
(found_subnet->getAllocator(Lease::TYPE_PD)));
EXPECT_TRUE(found_subnet->hasFetchGlobalsFn());
+ EXPECT_TRUE(found_subnet->getCfgOption()->isEncapsulated());
} else {
EXPECT_FALSE(found_subnet);
EXPECT_EQ(OptionBuffer(option_desc.formatted_value_.begin(),
option_desc.formatted_value_.end()),
option->getData());
+ EXPECT_TRUE(found_class->getCfgOption()->isEncapsulated());
+
} else {
EXPECT_FALSE(found_class);
}
container = cfg_dst.getAll("foo");
ASSERT_TRUE(container);
EXPECT_EQ(10, container->size());
+
+ // Source config wasn't encapsulated, so the destination shouldn't be too.
+ EXPECT_FALSE(cfg_dst.isEncapsulated());
+
+ // Now let's make sure that the encapsulation flag is correctly set.
+ cfg_src.encapsulate();
+ ASSERT_NO_THROW(cfg_src.copyTo(cfg_dst));
+ EXPECT_TRUE(cfg_dst.isEncapsulated());
}
// This test verifies that DHCP options from one configuration
OptionStringPtr opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("Yay!", opstr->getValue());
+ EXPECT_TRUE(network->getCfgOption()->isEncapsulated());
// No changes to network2.
ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network2", Triplet<uint32_t>(200),
OptionStringPtr opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("Yay!", opstr->getValue());
+ EXPECT_TRUE(network->getCfgOption()->isEncapsulated());
// No changes to network2.
ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network2", Triplet<uint32_t>(200),
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("Team!", opstr->getValue());
+ EXPECT_TRUE(subnet->getCfgOption()->isEncapsulated());
// subnet4 should be replaced by subnet4b and moved to network1.
ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, "192.0.4.0/26",
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("POOLS", opstr->getValue());
+ EXPECT_TRUE(merged_pool->getCfgOption()->isEncapsulated());
const PoolPtr merged_pool2 = subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.5.30"));
ASSERT_TRUE(merged_pool2);
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("RULE!", opstr->getValue());
+ EXPECT_TRUE(merged_pool2->getCfgOption()->isEncapsulated());
}
// This test verifies that it is possible to retrieve a subnet using an
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
+
#include <dhcpsrv/subnet_selector.h>
#include <dhcpsrv/cfg_hosts.h>
#include <stats/stats_mgr.h>
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("Team!", opstr->getValue());
+ EXPECT_TRUE(subnet->getCfgOption()->isEncapsulated());
// subnet4 should be replaced by subnet4b and moved to network1.
ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, "2001:4::/64",
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("POOLS", opstr->getValue());
+ EXPECT_TRUE(merged_pool->getCfgOption()->isEncapsulated());
const PoolPtr merged_pool2 = subnet->getPool(Lease::TYPE_PD, IOAddress("2001:1::"));
ASSERT_TRUE(merged_pool2);
opstr = boost::dynamic_pointer_cast<OptionString>(desc.option_);
ASSERT_TRUE(opstr);
EXPECT_EQ("RULE!", opstr->getValue());
+ EXPECT_TRUE(merged_pool2->getCfgOption()->isEncapsulated());
}
// This test verifies the Subnet6 parser's validation logic for id parameter.
#include <exceptions/exceptions.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
#include <dhcp/testutils/iface_mgr_test_config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
// Those must be two separate instances.
ASSERT_FALSE(ext_cfg1 == ext_cfg2);
+ // Add an option definition.
+ ext_cfg1->getCfgOptionDef()->add(OptionDefinition::create("option-foo",
+ 1,
+ "isc",
+ OPT_EMPTY_TYPE,
+ ""));
+
// Add a subnet which will be merged from first configuration.
Subnet4Ptr subnet1(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3, 123));
ext_cfg1->getCfgSubnets4()->add(subnet1);
ASSERT_TRUE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(123));
ASSERT_FALSE(cfg_mgr.getCurrentCfg()->getCfgSubnets4()->getBySubnetId(124));
+ // Ensure that the runtime option definitions have been updated.
+ auto runtime_def = LibDHCP::getRuntimeOptionDef("isc", "option-foo");
+ ASSERT_TRUE(runtime_def);
+
// Create another configuration instance to check what sequence it would
// pick. It should pick the first available one.
SrvConfigPtr ext_cfg3;