for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
opt != requested_opts.end(); ++opt) {
if (!msg->getOption(*opt)) {
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp4", *opt);
if (desc.option && !msg->getOption(*opt)) {
msg->addOption(desc.option);
for (std::vector<uint8_t>::const_iterator code = requested_opts.begin();
code != requested_opts.end(); ++code) {
if (!vendor_rsp->getOption(*code)) {
- Subnet::OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id,
+ OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id,
*code);
if (desc.option) {
vendor_rsp->addOption(desc.option);
OptionPtr opt = msg->getOption(required_options[i]);
if (!opt) {
// Check whether option has been configured.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp4", required_options[i]);
if (desc.option) {
msg->addOption(desc.option);
// Now try to set up file field in DHCPv4 packet. We will just copy
// content of the boot-file option, which contains the same information.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp4", DHO_BOOT_FILE_NAME);
if (desc.option) {
/// @return Descriptor of the option. If the descriptor holds a
/// NULL option pointer, it means that there was no such option
/// in the subnet.
- Subnet::OptionDescriptor
+ OptionDescriptor
getOptionFromSubnet(const IOAddress& subnet_address,
const uint16_t option_code,
const uint16_t expected_options_count = 1) {
<< subnet_address.toText()
<< "does not exist in Config Manager";
}
- Subnet::OptionContainerPtr options =
+ OptionContainerPtr options =
subnet->getOptionDescriptors("dhcp4");
if (expected_options_count != options->size()) {
ADD_FAILURE() << "The number of options in the subnet '"
}
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(option_code);
if (std::distance(range.first, range.second) > 1) {
ADD_FAILURE() << "There is more than one option having the"
<< subnet_address.toText() << "'. Expected "
" at most one option";
} else if (std::distance(range.first, range.second) == 0) {
- return (Subnet::OptionDescriptor(OptionPtr(), false));
+ return (OptionDescriptor(OptionPtr(), false));
}
return (*range.first);
/// @param expected_data_len length of the reference data.
/// @param extra_data if true extra data is allowed in an option
/// after tested data.
- void testOption(const Subnet::OptionDescriptor& option_desc,
+ void testOption(const OptionDescriptor& option_desc,
uint16_t expected_code, const uint8_t* expected_data,
size_t expected_data_len,
bool extra_data = false) {
std::string config = createConfigWithOption(params);
ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
// The subnet should now hold one option with the specified option code.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
getOptionFromSubnet(IOAddress("192.0.2.24"), option_code);
ASSERT_TRUE(desc.option);
testOption(desc, option_code, expected_data, expected_data_len);
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(56);
// Expect single option with the code equal to 56.
ASSERT_EQ(1, std::distance(range.first, range.second));
classify_);
ASSERT_TRUE(subnet);
// Try to get the option from the space dhcp4.
- Subnet::OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp4", 56);
+ OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp4", 56);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(56, desc1.option->getType());
// Try to get the option from the space isc.
- Subnet::OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 56);
+ OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 56);
ASSERT_TRUE(desc2.option);
EXPECT_EQ(56, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 56);
+ OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 56);
ASSERT_FALSE(desc3.option);
}
ASSERT_TRUE(subnet);
// We should have one option available.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
- Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp4", 222);
+ OptionDescriptor desc = subnet->getOptionDescriptor("dhcp4", 222);
EXPECT_TRUE(desc.option);
EXPECT_EQ(222, desc.option->getType());
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.24"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(56);
// Expect single option with the code equal to 100.
ASSERT_EQ(1, std::distance(range.first, range.second));
" boolean value"));
// The subnet should now hold one option with the code 19.
- Subnet::OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"),
+ OptionDescriptor desc = getOptionFromSubnet(IOAddress("192.0.2.24"),
19);
ASSERT_TRUE(desc.option);
Subnet4Ptr subnet1 = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.100"),
classify_);
ASSERT_TRUE(subnet1);
- Subnet::OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp4");
ASSERT_EQ(1, options1->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx1 = options1->get<1>();
+ const OptionContainerTypeIndex& idx1 = options1->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range1 =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range1 =
idx1.equal_range(56);
// Expect single option with the code equal to 56.
ASSERT_EQ(1, std::distance(range1.first, range1.second));
Subnet4Ptr subnet2 = CfgMgr::instance().getSubnet4(IOAddress("192.0.3.102"),
classify_);
ASSERT_TRUE(subnet2);
- Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp4");
ASSERT_EQ(1, options2->size());
- const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range2 =
+ const OptionContainerTypeIndex& idx2 = options2->get<1>();
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range2 =
idx2.equal_range(23);
ASSERT_EQ(1, std::distance(range2.first, range2.second));
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
ASSERT_EQ(1, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(56);
// Expect single option with the code equal to 100.
ASSERT_EQ(1, std::distance(range.first, range.second));
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.5"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options =
+ OptionContainerPtr options =
subnet->getOptionDescriptors("dhcp4");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(DHO_NIS_SERVERS);
// Expect single option with the code equal to NIS_SERVERS option code.
ASSERT_EQ(1, std::distance(range.first, range.second));
ASSERT_TRUE(subnet);
// We should have one option available.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp4");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp4", DHO_VENDOR_ENCAPSULATED_OPTIONS);
EXPECT_TRUE(desc.option);
EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, desc.option->getType());
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
- Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
+ OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the option from the vendor space 1234
- Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
+ OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
ASSERT_TRUE(desc2.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 100);
+ OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 100);
ASSERT_FALSE(desc3.option);
}
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
- Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
+ OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(VENDOR_ID_CABLE_LABS, 100);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
+ OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
ASSERT_FALSE(desc2.option);
}
// Get the list of options that client requested.
const std::vector<uint16_t>& requested_opts = option_oro->getValues();
BOOST_FOREACH(uint16_t opt, requested_opts) {
- Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", opt);
+ OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", opt);
if (desc.option) {
answer->addOption(desc.option);
}
bool added = false;
const std::vector<uint16_t>& requested_opts = oro->getValues();
BOOST_FOREACH(uint16_t opt, requested_opts) {
- Subnet::OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id, opt);
+ OptionDescriptor desc = subnet->getVendorOptionDescriptor(vendor_id, opt);
if (desc.option) {
vendor_rsp->addOption(desc.option);
added = true;
/// @return Descriptor of the option. If the descriptor holds a
/// NULL option pointer, it means that there was no such option
/// in the subnet.
- Subnet::OptionDescriptor
+ OptionDescriptor
getOptionFromSubnet(const IOAddress& subnet_address,
const uint16_t option_code,
const uint16_t expected_options_count = 1) {
<< subnet_address.toText()
<< "does not exist in Config Manager";
}
- Subnet::OptionContainerPtr options =
+ OptionContainerPtr options =
subnet->getOptionDescriptors("dhcp6");
if (expected_options_count != options->size()) {
ADD_FAILURE() << "The number of options in the subnet '"
}
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(option_code);
if (std::distance(range.first, range.second) > 1) {
ADD_FAILURE() << "There is more than one option having the"
<< subnet_address.toText() << "'. Expected "
" at most one option";
} else if (std::distance(range.first, range.second) == 0) {
- return (Subnet::OptionDescriptor(OptionPtr(), false));
+ return (OptionDescriptor(OptionPtr(), false));
}
return (*range.first);
/// @param expected_data_len length of the reference data.
/// @param extra_data if true extra data is allowed in an option
/// after tested data.
- void testOption(const Subnet::OptionDescriptor& option_desc,
+ void testOption(const OptionDescriptor& option_desc,
uint16_t expected_code, const uint8_t* expected_data,
size_t expected_data_len,
bool extra_data = false) {
ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
// The subnet should now hold one option with the specified code.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
getOptionFromSubnet(IOAddress("2001:db8:1::5"), option_code);
ASSERT_TRUE(desc.option);
testOption(desc, option_code, expected_data, expected_data_len);
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(D6O_SUBSCRIBER_ID);
// Expect single option with the code equal to 38.
ASSERT_EQ(1, std::distance(range.first, range.second));
classify_);
ASSERT_TRUE(subnet);
// Try to get the option from the space dhcp6.
- Subnet::OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp6", 38);
+ OptionDescriptor desc1 = subnet->getOptionDescriptor("dhcp6", 38);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(38, desc1.option->getType());
// Try to get the option from the space isc.
- Subnet::OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 38);
+ OptionDescriptor desc2 = subnet->getOptionDescriptor("isc", 38);
ASSERT_TRUE(desc2.option);
EXPECT_EQ(38, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 38);
+ OptionDescriptor desc3 = subnet->getOptionDescriptor("non-existing", 38);
ASSERT_FALSE(desc3.option);
}
ASSERT_TRUE(subnet);
// We should have one option available.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
- Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", 100);
+ OptionDescriptor desc = subnet->getOptionDescriptor("dhcp6", 100);
EXPECT_TRUE(desc.option);
EXPECT_EQ(100, desc.option->getType());
Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
classify_);
ASSERT_TRUE(subnet1);
- Subnet::OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options1 = subnet1->getOptionDescriptors("dhcp6");
ASSERT_EQ(1, options1->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx1 = options1->get<1>();
+ const OptionContainerTypeIndex& idx1 = options1->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range1 =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range1 =
idx1.equal_range(D6O_SUBSCRIBER_ID);
// Expect single option with the code equal to 38.
ASSERT_EQ(1, std::distance(range1.first, range1.second));
Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"),
classify_);
ASSERT_TRUE(subnet2);
- Subnet::OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options2 = subnet2->getOptionDescriptors("dhcp6");
ASSERT_EQ(1, options2->size());
- const Subnet::OptionContainerTypeIndex& idx2 = options2->get<1>();
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range2 =
+ const OptionContainerTypeIndex& idx2 = options2->get<1>();
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range2 =
idx2.equal_range(D6O_USER_CLASS);
ASSERT_EQ(1, std::distance(range2.first, range2.second));
CfgMgr::instance().commit();
// The subnet should now hold one option with the code 1000.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000);
ASSERT_TRUE(desc.option);
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_EQ(1, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(D6O_SUBSCRIBER_ID);
// Expect single option with the code equal to 38.
ASSERT_EQ(1, std::distance(range.first, range.second));
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
classify_);
ASSERT_TRUE(subnet);
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_EQ(1, options->size());
// Get the search index. Index #1 is to search using option code.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeIndex& idx = options->get<1>();
// Get the options for specified index. Expecting one option to be
// returned but in theory we may have multiple options with the same
// code so we get the range.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(D6O_IA_NA);
// Expect single option with the code equal to IA_NA option code.
ASSERT_EQ(1, std::distance(range.first, range.second));
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
- Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
+ OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the option from the vendor space 1234
- Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
+ OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(1234, 100);
ASSERT_TRUE(desc2.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 38);
+ OptionDescriptor desc3 = subnet->getVendorOptionDescriptor(5678, 38);
ASSERT_FALSE(desc3.option);
}
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
- Subnet::OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
+ OptionDescriptor desc1 = subnet->getVendorOptionDescriptor(4491, 100);
ASSERT_TRUE(desc1.option);
EXPECT_EQ(100, desc1.option->getType());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
- Subnet::OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
+ OptionDescriptor desc2 = subnet->getVendorOptionDescriptor(5678, 100);
ASSERT_FALSE(desc2.option);
}
ASSERT_TRUE(subnet);
// We should have one option available.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
- Subnet::OptionDescriptor desc =
+ OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp6", D6O_VENDOR_OPTS);
EXPECT_TRUE(desc.option);
EXPECT_EQ(D6O_VENDOR_OPTS, desc.option->getType());
libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
+libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
--- /dev/null
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfg_option.h>
+#include <boost/lexical_cast.hpp>
+#include <limits>
+#include <string>
+
+namespace {
+
+uint32_t
+optionSpaceToVendorId(const std::string& option_space) {
+ if (option_space.size() < 8) {
+ // 8 is a minimal length of "vendor-X" format
+ return (0);
+ }
+ if (option_space.substr(0,7) != "vendor-") {
+ return (0);
+ }
+
+ // text after "vendor-", supposedly numbers only
+ std::string x = option_space.substr(7);
+
+ int64_t check;
+ try {
+ check = boost::lexical_cast<int64_t>(x);
+ } catch (const boost::bad_lexical_cast &) {
+ /// @todo: Should we throw here?
+ // isc_throw(BadValue, "Failed to parse vendor-X value (" << x
+ // << ") as unsigned 32-bit integer.");
+ return (0);
+ }
+ if (check > std::numeric_limits<uint32_t>::max()) {
+ /// @todo: Should we throw here?
+ //isc_throw(BadValue, "Value " << x << "is too large"
+ // << " for unsigned 32-bit integer.");
+ return (0);
+ }
+ if (check < 0) {
+ /// @todo: Should we throw here?
+ // isc_throw(BadValue, "Value " << x << "is negative."
+ // << " Only 0 or larger are allowed for unsigned 32-bit integer.");
+ return (0);
+ }
+
+ // value is small enough to fit
+ return (static_cast<uint32_t>(check));
+}
+
+}
+
+namespace isc {
+namespace dhcp {
+
+void
+CfgOption::add(const OptionPtr& option, const bool persistent,
+ const std::string& option_space) {
+ if (!option) {
+ isc_throw(isc::BadValue, "option being configured must not be NULL");
+
+ } else if (!OptionSpace::validateName(option_space)) {
+ isc_throw(isc::BadValue, "invalid option space name: '"
+ << option_space << "'");
+ }
+
+ const uint32_t vendor_id = optionSpaceToVendorId(option_space);
+ if (vendor_id) {
+ vendor_options_.addItem(OptionDescriptor(option, persistent),
+ vendor_id);
+ } else {
+ options_.addItem(OptionDescriptor(option, persistent), option_space);
+ }
+}
+
+OptionContainerPtr
+CfgOption::getAll(const std::string& option_space) const {
+ return (options_.getItems(option_space));
+}
+
+OptionContainerPtr
+CfgOption::getAll(const uint32_t vendor_id) const {
+ return (vendor_options_.getItems(vendor_id));
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CFG_OPTION_H
+#define CFG_OPTION_H
+
+#include <dhcp/option.h>
+#include <dhcpsrv/key_from_key.h>
+#include <dhcpsrv/option_space_container.h>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Option descriptor.
+///
+/// Option descriptor holds instance of an option and additional information
+/// for this option. This information comprises whether this option is sent
+/// to DHCP client only on request (persistent = false) or always
+/// (persistent = true).
+struct OptionDescriptor {
+ /// Option instance.
+ OptionPtr option;
+ /// Persistent flag, if true option is always sent to the client,
+ /// if false option is sent to the client on request.
+ bool persistent;
+
+ /// @brief Constructor.
+ ///
+ /// @param opt option
+ /// @param persist if true option is always sent.
+ OptionDescriptor(const OptionPtr& opt, bool persist)
+ : option(opt), persistent(persist) {};
+
+ /// @brief Constructor
+ ///
+ /// @param persist if true option is always sent.
+ OptionDescriptor(bool persist)
+ : option(OptionPtr()), persistent(persist) {};
+};
+
+/// A pointer to option descriptor.
+typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
+
+/// @brief Multi index container for DHCP option descriptors.
+///
+/// This container comprises three indexes to access option
+/// descriptors:
+/// - sequenced index: used to access elements in the order they
+/// have been added to the container,
+/// - option type index: used to search option descriptors containing
+/// options with specific option code (aka option type).
+/// - persistency flag index: used to search option descriptors with
+/// 'persistent' flag set to true.
+///
+/// This container is the equivalent of three separate STL containers:
+/// - std::list of all options,
+/// - std::multimap of options with option code used as a multimap key,
+/// - std::multimap of option descriptors with option persistency flag
+/// used as a multimap key.
+/// The major advantage of this container over 3 separate STL containers
+/// is automatic synchronization of all indexes when elements are added,
+/// removed or modified in the container. With separate containers,
+/// the synchronization would have to be guaranteed by the Subnet class
+/// code. This would increase code complexity and presumably it would
+/// be much harder to add new search criteria (indexes).
+///
+/// @todo we may want to search for options using option spaces when
+/// they are implemented.
+///
+/// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
+typedef boost::multi_index_container<
+ // Container comprises elements of OptionDescriptor type.
+ OptionDescriptor,
+ // Here we start enumerating various indexes.
+ boost::multi_index::indexed_by<
+ // Sequenced index allows accessing elements in the same way
+ // as elements in std::list.
+ // Sequenced is an index #0.
+ boost::multi_index::sequenced<>,
+ // Start definition of index #1.
+ boost::multi_index::hashed_non_unique<
+ // KeyFromKeyExtractor is the index key extractor that allows
+ // accessing option type being held by the OptionPtr through
+ // OptionDescriptor structure.
+ KeyFromKeyExtractor<
+ // Use option type as the index key. The type is held
+ // in OptionPtr object so we have to call Option::getType
+ // to retrieve this key for each element.
+ boost::multi_index::const_mem_fun<
+ Option,
+ uint16_t,
+ &Option::getType
+ >,
+ // Indicate that OptionPtr is a member of
+ // OptionDescriptor structure.
+ boost::multi_index::member<
+ OptionDescriptor,
+ OptionPtr,
+ &OptionDescriptor::option
+ >
+ >
+ >,
+ // Start definition of index #2.
+ // Use 'persistent' struct member as a key.
+ boost::multi_index::hashed_non_unique<
+ boost::multi_index::member<
+ OptionDescriptor,
+ bool,
+ &OptionDescriptor::persistent
+ >
+ >
+ >
+> OptionContainer;
+
+/// Pointer to the OptionContainer object.
+typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
+/// Type of the index #1 - option type.
+typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
+/// Pair of iterators to represent the range of options having the
+/// same option type value. The first element in this pair represents
+/// the beginning of the range, the second element represents the end.
+typedef std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
+/// Type of the index #2 - option persistency flag.
+typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
+
+/// @brief Represents option data configuration for the DHCP server.
+///
+/// This class holds a collection of options to be sent to a DHCP client.
+/// Options are grouped by the option space or vendor identifier (for
+/// vendor options).
+///
+/// The server configuration allows for specifying two distinct collections
+/// of options: global options and per-subnet options in which some options
+/// may overlap.
+///
+/// The collection of global options specify options being sent to the client
+/// belonging to any subnets, i.e. global options are "inherited" by all
+/// subnets.
+///
+/// The per-subnet options are configured for a particular subnet and are sent
+/// to clients which belong to this subnet. The values of the options specified
+/// for a particular subnet override the values of the global options.
+///
+/// This class represents a single collection of options (either global or
+/// per-subnet). Each subnet holds its own object of the @c CfgOption type. The
+/// @c CfgMgr holds a @c CfgOption object representing global options.
+///
+/// Note that having a separate copy of the @c CfgOption to represent global
+/// options is useful when the client requests stateless configuration from
+/// the DHCP server and no subnet is selected for this client. This client
+/// will only receive global options.
+class CfgOption {
+public:
+
+ /// @brief Adds instance of the option to the configuration.
+ ///
+ /// There are two types of options which may be passed to this method:
+ /// - vendor options
+ /// - non-vendor options
+ ///
+ /// The non-vendor options are grouped by the name of the option space
+ /// (specified in textual format). The vendor options are grouped by the
+ /// vendor identifier, which is a 32-bit unsigned integer value.
+ ///
+ /// In order to add new vendor option to the list the option space name
+ /// (last argument of this method) should be specified as "vendor-X" where
+ /// "X" is a 32-bit unsigned integer, e.g. "vendor-1234". Options for which
+ /// the @c option_space argument doesn't follow this format are added as
+ /// non-vendor options.
+ ///
+ /// @param option Pointer to the option being added.
+ /// @param persistent Boolean value which specifies if the option should
+ /// be sent to the client regardless if requested (true), or nor (false)
+ /// @param option_space Option space name.
+ ///
+ /// @throw isc::BadValue if the option space is invalid.
+ void add(const OptionPtr& option, const bool persistent,
+ const std::string& option_space);
+
+ /// @brief Returns all options for the specified option space.
+ ///
+ /// This method will not return vendor options, i.e. having option space
+ /// name in the format of "vendor-X" where X is 32-bit unsiged integer.
+ ///
+ /// @param option_space Name of the option space.
+ ///
+ /// @return Pointer to the container holding returned options. This
+ /// container is empty if no options have been found.
+ OptionContainerPtr getAll(const std::string& option_space) const;
+
+ /// @brief Returns vendor options for the specified vendor id.
+ ///
+ /// @param vendor_id Vendor id for which options are to be returned.
+ ///
+ /// @return Pointer to the container holding returned options. This
+ /// container is empty if no options have been found.
+ OptionContainerPtr getAll(const uint32_t vendor_id) const;
+
+ /// @brief Returns option for the specified key and option code.
+ ///
+ /// The key should be a string, in which case it specifies an option space
+ /// name, or an uint32_t value, in which case it specifies a vendor
+ /// identifier.
+ ///
+ /// @param key Option space name or vendor identifier.
+ /// @param option_code Code of the option to be returned.
+ /// @tparam T one of: @c std::string or @c uint32_t
+ ///
+ /// @return Descriptor of the option. If option hasn't been found, the
+ /// descriptor holds NULL option.
+ template<typename T>
+ OptionDescriptor get(const T& key, const uint16_t option_code) const {
+ OptionContainerPtr options = getAll(key);
+ if (!options || options->empty()) {
+ return (OptionDescriptor(false));
+ }
+
+ const OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeRange& range = idx.equal_range(option_code);
+ if (std::distance(range.first, range.second) == 0) {
+ return (OptionDescriptor(false));
+ }
+
+ return (*range.first);
+ }
+
+private:
+
+ /// @brief Type of the container holding options grouped by option space.
+ typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+ std::string> OptionSpaceCollection;
+ /// @brief Container holding options grouped by option space.
+ OptionSpaceCollection options_;
+
+ /// @brief Type of the container holding options grouped by vendor id.
+ typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+ uint32_t> VendorOptionSpaceCollection;
+ /// @brief Container holding options grouped by vendor id.
+ VendorOptionSpaceCollection vendor_options_;
+
+
+
+};
+
+}
+}
+
+#endif // CFG_OPTION_H
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/dhcp_parsers.h>
#include <hooks/hooks_manager.h>
#include <util/encode/hex.h>
}
uint16_t opt_type = option_descriptor_.option->getType();
- Subnet::OptionContainerPtr options = options_->getItems(option_space_);
+ OptionContainerPtr options = options_->getItems(option_space_);
// The getItems() should never return NULL pointer. If there are no
// options configured for the particular option space a pointer
// to an empty container should be returned.
assert(options);
- Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ OptionContainerTypeIndex& idx = options->get<1>();
// Try to find options with the particular option code in the main
// storage. If found, remove these options because they will be
// replaced with new one.
- Subnet::OptionContainerTypeRange range = idx.equal_range(opt_type);
+ OptionContainerTypeRange range = idx.equal_range(opt_type);
if (std::distance(range.first, range.second) > 0) {
idx.erase(range.first, range.second);
}
code, data_tokens) :
def->optionFactory(global_context_->universe_,
code, binary);
- Subnet::OptionDescriptor desc(option, false);
+ OptionDescriptor desc(option, false);
option_descriptor_.option = option;
option_descriptor_.persistent = false;
} catch (const isc::Exception& ex) {
if (!encapsulated_space.empty()) {
// Get the sub-options that belong to the encapsulated
// option space.
- const Subnet::OptionContainerPtr sub_opts =
+ const OptionContainerPtr sub_opts =
global_context_->options_->getItems(encapsulated_space);
// Append sub-options to the option.
- BOOST_FOREACH(Subnet::OptionDescriptor desc, *sub_opts) {
+ BOOST_FOREACH(OptionDescriptor desc, *sub_opts) {
if (desc.option) {
option->addOption(desc.option);
}
std::list<std::string> space_names = options_->getOptionSpaceNames();
BOOST_FOREACH(std::string option_space, space_names) {
// Get all options within a particular option space.
- BOOST_FOREACH(Subnet::OptionDescriptor desc,
+ BOOST_FOREACH(OptionDescriptor desc,
*options_->getItems(option_space)) {
// The pointer should be non-NULL. The validation is expected
// to be performed by the OptionDataParser before adding an
// We want to check whether an option with the particular
// option code has been already added. If so, we want
// to issue a warning.
- Subnet::OptionDescriptor existing_desc =
+ OptionDescriptor existing_desc =
subnet_->getOptionDescriptor("option_space",
desc.option->getType());
if (existing_desc.option) {
space_names = global_context_->options_->getOptionSpaceNames();
BOOST_FOREACH(std::string option_space, space_names) {
// Get all global options for the particular option space.
- BOOST_FOREACH(Subnet::OptionDescriptor desc,
+ BOOST_FOREACH(OptionDescriptor desc,
*(global_context_->options_->getItems(option_space))) {
// The pointer should be non-NULL. The validation is expected
// to be performed by the OptionDataParser before adding an
// subnet scope take precedence over globally configured
// values we don't add option from the global storage
// if there is one already.
- Subnet::OptionDescriptor existing_desc =
+ OptionDescriptor existing_desc =
subnet_->getOptionDescriptor(option_space,
desc.option->getType());
if (!existing_desc.option) {
#include <dhcpsrv/d2_client_cfg.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/cfg_iface.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/subnet.h>
#include <exceptions/exceptions.h>
/// Collection of containers holding option spaces. Each container within
/// a particular option space holds so-called option descriptors.
-typedef OptionSpaceContainer<Subnet::OptionContainer,
- Subnet::OptionDescriptor, std::string> OptionStorage;
+typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
+ std::string> OptionStorage;
/// @brief Shared pointer to option storage.
typedef boost::shared_ptr<OptionStorage> OptionStoragePtr;
OptionStoragePtr options_;
/// Option descriptor holds newly configured option.
- Subnet::OptionDescriptor option_descriptor_;
+ OptionDescriptor option_descriptor_;
/// Option space name where the option belongs to.
std::string option_space_;
option_spaces_.clearItems();
}
-Subnet::OptionContainerPtr
+OptionContainerPtr
Subnet::getOptionDescriptors(const std::string& option_space) const {
return (option_spaces_.getItems(option_space));
}
-Subnet::OptionDescriptor
+OptionDescriptor
Subnet::getOptionDescriptor(const std::string& option_space,
const uint16_t option_code) {
OptionContainerPtr options = getOptionDescriptors(option_space);
vendor_option_spaces_.addItem(OptionDescriptor(option, persistent), vendor_id);
}
-Subnet::OptionContainerPtr
+OptionContainerPtr
Subnet::getVendorOptionDescriptors(uint32_t vendor_id) const {
return (vendor_option_spaces_.getItems(vendor_id));
}
-Subnet::OptionDescriptor
+OptionDescriptor
Subnet::getVendorOptionDescriptor(uint32_t vendor_id, uint16_t option_code) {
OptionContainerPtr options = getVendorOptionDescriptors(vendor_id);
if (!options || options->empty()) {
#ifndef SUBNET_H
#define SUBNET_H
-#include <boost/shared_ptr.hpp>
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
-#include <boost/multi_index/mem_fun.hpp>
-#include <boost/multi_index/member.hpp>
-
#include <asiolink/io_address.h>
#include <dhcp/option.h>
#include <dhcp/classify.h>
-#include <dhcpsrv/key_from_key.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/triplet.h>
#include <dhcpsrv/lease.h>
+#include <boost/shared_ptr.hpp>
+
namespace isc {
namespace dhcp {
class Subnet {
public:
- /// @brief Option descriptor.
- ///
- /// Option descriptor holds information about option configured for
- /// a particular subnet. This information comprises the actual option
- /// instance and information whether this option is sent to DHCP client
- /// only on request (persistent = false) or always (persistent = true).
- struct OptionDescriptor {
- /// Option instance.
- OptionPtr option;
- /// Persistent flag, if true option is always sent to the client,
- /// if false option is sent to the client on request.
- bool persistent;
-
- /// @brief Constructor.
- ///
- /// @param opt option
- /// @param persist if true option is always sent.
- OptionDescriptor(const OptionPtr& opt, bool persist)
- : option(opt), persistent(persist) {};
-
- /// @brief Constructor
- ///
- /// @param persist if true option is always sent.
- OptionDescriptor(bool persist)
- : option(OptionPtr()), persistent(persist) {};
- };
-
- /// A pointer to option descriptor.
- typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
-
- /// @brief Multi index container for DHCP option descriptors.
- ///
- /// This container comprises three indexes to access option
- /// descriptors:
- /// - sequenced index: used to access elements in the order they
- /// have been added to the container,
- /// - option type index: used to search option descriptors containing
- /// options with specific option code (aka option type).
- /// - persistency flag index: used to search option descriptors with
- /// 'persistent' flag set to true.
- ///
- /// This container is the equivalent of three separate STL containers:
- /// - std::list of all options,
- /// - std::multimap of options with option code used as a multimap key,
- /// - std::multimap of option descriptors with option persistency flag
- /// used as a multimap key.
- /// The major advantage of this container over 3 separate STL containers
- /// is automatic synchronization of all indexes when elements are added,
- /// removed or modified in the container. With separate containers,
- /// the synchronization would have to be guaranteed by the Subnet class
- /// code. This would increase code complexity and presumably it would
- /// be much harder to add new search criteria (indexes).
- ///
- /// @todo we may want to search for options using option spaces when
- /// they are implemented.
- ///
- /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
- typedef boost::multi_index_container<
- // Container comprises elements of OptionDescriptor type.
- OptionDescriptor,
- // Here we start enumerating various indexes.
- boost::multi_index::indexed_by<
- // Sequenced index allows accessing elements in the same way
- // as elements in std::list.
- // Sequenced is an index #0.
- boost::multi_index::sequenced<>,
- // Start definition of index #1.
- boost::multi_index::hashed_non_unique<
- // KeyFromKeyExtractor is the index key extractor that allows
- // accessing option type being held by the OptionPtr through
- // OptionDescriptor structure.
- KeyFromKeyExtractor<
- // Use option type as the index key. The type is held
- // in OptionPtr object so we have to call Option::getType
- // to retrieve this key for each element.
- boost::multi_index::const_mem_fun<
- Option,
- uint16_t,
- &Option::getType
- >,
- // Indicate that OptionPtr is a member of
- // OptionDescriptor structure.
- boost::multi_index::member<
- OptionDescriptor,
- OptionPtr,
- &OptionDescriptor::option
- >
- >
- >,
- // Start definition of index #2.
- // Use 'persistent' struct member as a key.
- boost::multi_index::hashed_non_unique<
- boost::multi_index::member<
- OptionDescriptor,
- bool,
- &OptionDescriptor::persistent
- >
- >
- >
- > OptionContainer;
-
- /// Pointer to the OptionContainer object.
- typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
- /// Type of the index #1 - option type.
- typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
- /// Pair of iterators to represent the range of options having the
- /// same option type value. The first element in this pair represents
- /// the beginning of the range, the second element represents the end.
- typedef std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
- /// Type of the index #2 - option persistency flag.
- typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
-
/// @brief Holds optional information about relay.
///
/// In some cases it is beneficial to have additional information about
libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc
libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc
libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
libdhcpsrv_unittests_SOURCES += csv_lease_file4_unittest.cc
--- /dev/null
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/cfg_option.h>
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+// This test verifies that multiple options can be added to the configuration
+// and that they can be retrieved using the option space name.
+TEST(CfgOptionTest, add) {
+ CfgOption cfg;
+
+ // Differentiate options by their codes (100-109)
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "dhcp6"));
+ }
+
+ // Add 7 options to another option space. The option codes partially overlap
+ // with option codes that we have added to dhcp6 option space.
+ for (uint16_t code = 105; code < 112; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "isc"));
+ }
+
+ // Get options from the Subnet and check if all 10 are there.
+ OptionContainerPtr options = cfg.getAll("dhcp6");
+ ASSERT_TRUE(options);
+ ASSERT_EQ(10, options->size());
+
+ // Validate codes of options added to dhcp6 option space.
+ uint16_t expected_code = 100;
+ for (OptionContainer::const_iterator option_desc = options->begin();
+ option_desc != options->end(); ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(expected_code, option_desc->option->getType());
+ ++expected_code;
+ }
+
+ options = cfg.getAll("isc");
+ ASSERT_TRUE(options);
+ ASSERT_EQ(7, options->size());
+
+ // Validate codes of options added to isc option space.
+ expected_code = 105;
+ for (OptionContainer::const_iterator option_desc = options->begin();
+ option_desc != options->end(); ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(expected_code, option_desc->option->getType());
+ ++expected_code;
+ }
+
+ // Try to get options from a non-existing option space.
+ options = cfg.getAll("abcd");
+ ASSERT_TRUE(options);
+ EXPECT_TRUE(options->empty());
+}
+
+// This test verifies that single option can be retrieved from the configuration
+// using option code and option space.
+TEST(CfgOption, get) {
+ CfgOption cfg;
+
+ // Add 10 options to a "dhcp6" option space in the subnet.
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "dhcp6"));
+ }
+
+ // Check that we can get each added option descriptor using
+ // individually.
+ for (uint16_t code = 100; code < 110; ++code) {
+ std::ostringstream stream;
+ // First, try the invalid option space name.
+ OptionDescriptor desc = cfg.get("isc", code);
+ // Returned descriptor should contain NULL option ptr.
+ EXPECT_FALSE(desc.option);
+ // Now, try the valid option space.
+ desc = cfg.get("dhcp6", code);
+ // Test that the option code matches the expected code.
+ ASSERT_TRUE(desc.option);
+ EXPECT_EQ(code, desc.option->getType());
+ }
+}
+
+// This test verifies that the same options can be added to the configuration
+// under different option space.
+TEST(CfgOptionTest, addNonUniqueOptions) {
+ CfgOption cfg;
+
+ // Create a set of options with non-unique codes.
+ for (int i = 0; i < 2; ++i) {
+ // In the inner loop we create options with unique codes (100-109).
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "dhcp6"));
+ }
+ }
+
+ // Sanity check that all options are there.
+ OptionContainerPtr options = cfg.getAll("dhcp6");
+ ASSERT_EQ(20, options->size());
+
+ // Use container index #1 to get the options by their codes.
+ OptionContainerTypeIndex& idx = options->get<1>();
+ // Look for the codes 100-109.
+ for (uint16_t code = 100; code < 110; ++ code) {
+ // For each code we should get two instances of options->
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
+ idx.equal_range(code);
+ // Distance between iterators indicates how many options
+ // have been retured for the particular code.
+ ASSERT_EQ(2, distance(range.first, range.second));
+ // Check that returned options actually have the expected option code.
+ for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
+ option_desc != range.second; ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(code, option_desc->option->getType());
+ }
+ }
+
+ // Let's try to find some non-exiting option.
+ const uint16_t non_existing_code = 150;
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
+ idx.equal_range(non_existing_code);
+ // Empty set is expected.
+ EXPECT_EQ(0, distance(range.first, range.second));
+}
+
+// This test verifies that the option with the persistency flag can be
+// added to the configuration and that options with the persistency flags
+// can be retrieved.
+TEST(Subnet6Test, addPersistentOption) {
+ CfgOption cfg;
+
+ // Add 10 options to the subnet with option codes 100 - 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ // We create 10 options and want some of them to be flagged
+ // persistent and some non-persistent. Persistent options are
+ // those that server sends to clients regardless if they ask
+ // for them or not. We pick 3 out of 10 options and mark them
+ // non-persistent and 7 other options persistent.
+ // Code values: 102, 105 and 108 are divisible by 3
+ // and options with these codes will be flagged non-persistent.
+ // Options with other codes will be flagged persistent.
+ bool persistent = (code % 3) ? true : false;
+ ASSERT_NO_THROW(cfg.add(option, persistent, "dhcp6"));
+ }
+
+ // Get added options from the subnet.
+ OptionContainerPtr options = cfg.getAll("dhcp6");
+
+ // options->get<2> returns reference to container index #2. This
+ // index is used to access options by the 'persistent' flag.
+ OptionContainerPersistIndex& idx = options->get<2>();
+
+ // Get all persistent options->
+ std::pair<OptionContainerPersistIndex::const_iterator,
+ OptionContainerPersistIndex::const_iterator> range_persistent =
+ idx.equal_range(true);
+ // 3 out of 10 options have been flagged persistent.
+ ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
+
+ // Get all non-persistent options->
+ std::pair<OptionContainerPersistIndex::const_iterator,
+ OptionContainerPersistIndex::const_iterator> range_non_persistent =
+ idx.equal_range(false);
+ // 7 out of 10 options have been flagged persistent.
+ ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
+}
+
+// This test verifies that the vendor option can be added to the configuration.
+TEST(CfgOptionTest, addVendorOptions) {
+ CfgOption cfg;
+
+ // Differentiate options by their codes (100-109)
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "vendor-12345678"));
+ }
+
+ // Add 7 options to another option space. The option codes partially overlap
+ // with option codes that we have added to dhcp6 option space.
+ for (uint16_t code = 105; code < 112; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(cfg.add(option, false, "vendor-87654321"));
+ }
+
+ // Get options from the Subnet and check if all 10 are there.
+ OptionContainerPtr options = cfg.getAll(12345678);
+ ASSERT_TRUE(options);
+ ASSERT_EQ(10, options->size());
+
+ // Validate codes of options added to dhcp6 option space.
+ uint16_t expected_code = 100;
+ for (OptionContainer::const_iterator option_desc = options->begin();
+ option_desc != options->end(); ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(expected_code, option_desc->option->getType());
+ ++expected_code;
+ }
+
+ options = cfg.getAll(87654321);
+ ASSERT_TRUE(options);
+ ASSERT_EQ(7, options->size());
+
+ // Validate codes of options added to isc option space.
+ expected_code = 105;
+ for (OptionContainer::const_iterator option_desc = options->begin();
+ option_desc != options->end(); ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(expected_code, option_desc->option->getType());
+ ++expected_code;
+ }
+
+ // Try to get options from a non-existing option space.
+ options = cfg.getAll(1111111);
+ ASSERT_TRUE(options);
+ EXPECT_TRUE(options->empty());
+}
+
+
+} // end of anonymous namespace
OptionPtr getOptionPtr(std::string space, uint32_t code)
{
OptionPtr option_ptr;
- Subnet::OptionContainerPtr options =
+ OptionContainerPtr options =
parser_context_->options_->getItems(space);
// Should always be able to get options list even if it is empty.
EXPECT_TRUE(options);
if (options) {
// Attempt to find desired option.
- const Subnet::OptionContainerTypeIndex& idx = options->get<1>();
- const Subnet::OptionContainerTypeRange& range =
+ const OptionContainerTypeIndex& idx = options->get<1>();
+ const OptionContainerTypeRange& range =
idx.equal_range(code);
int cnt = std::distance(range.first, range.second);
EXPECT_EQ(1, cnt);
if (cnt == 1) {
- Subnet::OptionDescriptor desc = *(idx.begin());
+ OptionDescriptor desc = *(idx.begin());
option_ptr = desc.option;
EXPECT_TRUE(option_ptr);
}
/// @param ctx A pointer to a context.
/// @param opt_type Expected option type.
void checkOptionType(const ParserContext& ctx, const uint16_t opt_type) {
- Subnet::OptionContainerPtr options =
+ OptionContainerPtr options =
ctx.options_->getItems("option-space");
ASSERT_TRUE(options);
- Subnet::OptionContainerTypeIndex& idx = options->get<1>();
- Subnet::OptionContainerTypeRange range = idx.equal_range(opt_type);
+ OptionContainerTypeIndex& idx = options->get<1>();
+ OptionContainerTypeRange range = idx.equal_range(opt_type);
ASSERT_EQ(1, std::distance(range.first, range.second));
}
// Add new option, with option code 10, to the context.
ASSERT_TRUE(ctx.options_);
OptionPtr opt1(new Option(Option::V6, 10));
- Subnet::OptionDescriptor desc1(opt1, false);
+ OptionDescriptor desc1(opt1, false);
std::string option_space = "option-space";
ASSERT_TRUE(desc1.option);
ctx.options_->addItem(desc1, option_space);
SCOPED_TRACE("Check that option remains the same in the new context"
" when the option in the original context is changed");
ctx.options_->clearItems();
- Subnet::OptionDescriptor desc(OptionPtr(new Option(Option::V6,
+ OptionDescriptor desc(OptionPtr(new Option(Option::V6,
100)),
false);
}
// Get options from the Subnet and check if all 10 are there.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_TRUE(options);
ASSERT_EQ(10, options->size());
// Validate codes of options added to dhcp6 option space.
uint16_t expected_code = 100;
- for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+ for (OptionContainer::const_iterator option_desc = options->begin();
option_desc != options->end(); ++option_desc) {
ASSERT_TRUE(option_desc->option);
EXPECT_EQ(expected_code, option_desc->option->getType());
// Validate codes of options added to isc option space.
expected_code = 105;
- for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+ for (OptionContainer::const_iterator option_desc = options->begin();
option_desc != options->end(); ++option_desc) {
ASSERT_TRUE(option_desc->option);
EXPECT_EQ(expected_code, option_desc->option->getType());
}
// Sanity check that all options are there.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
ASSERT_EQ(20, options->size());
// Use container index #1 to get the options by their codes.
- Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+ OptionContainerTypeIndex& idx = options->get<1>();
// Look for the codes 100-109.
for (uint16_t code = 100; code < 110; ++ code) {
// For each code we should get two instances of options->
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(code);
// Distance between iterators indicates how many options
// have been retured for the particular code.
ASSERT_EQ(2, distance(range.first, range.second));
// Check that returned options actually have the expected option code.
- for (Subnet::OptionContainerTypeIndex::const_iterator option_desc = range.first;
+ for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
option_desc != range.second; ++option_desc) {
ASSERT_TRUE(option_desc->option);
EXPECT_EQ(code, option_desc->option->getType());
// Let's try to find some non-exiting option.
const uint16_t non_existing_code = 150;
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
+ std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> range =
idx.equal_range(non_existing_code);
// Empty set is expected.
EXPECT_EQ(0, distance(range.first, range.second));
}
// Get added options from the subnet.
- Subnet::OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
+ OptionContainerPtr options = subnet->getOptionDescriptors("dhcp6");
// options->get<2> returns reference to container index #2. This
// index is used to access options by the 'persistent' flag.
- Subnet::OptionContainerPersistIndex& idx = options->get<2>();
+ OptionContainerPersistIndex& idx = options->get<2>();
// Get all persistent options->
- std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
- Subnet::OptionContainerPersistIndex::const_iterator> range_persistent =
+ std::pair<OptionContainerPersistIndex::const_iterator,
+ OptionContainerPersistIndex::const_iterator> range_persistent =
idx.equal_range(true);
// 3 out of 10 options have been flagged persistent.
ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
// Get all non-persistent options->
- std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
- Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
+ std::pair<OptionContainerPersistIndex::const_iterator,
+ OptionContainerPersistIndex::const_iterator> range_non_persistent =
idx.equal_range(false);
// 7 out of 10 options have been flagged persistent.
ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
for (uint16_t code = 100; code < 110; ++code) {
std::ostringstream stream;
// First, try the invalid option space name.
- Subnet::OptionDescriptor desc = subnet->getOptionDescriptor("isc", code);
+ OptionDescriptor desc = subnet->getOptionDescriptor("isc", code);
// Returned descriptor should contain NULL option ptr.
EXPECT_FALSE(desc.option);
// Now, try the valid option space.
}
// Get options from the Subnet and check if all 10 are there.
- Subnet::OptionContainerPtr options = subnet->getVendorOptionDescriptors(vendor_id1);
+ OptionContainerPtr options = subnet->getVendorOptionDescriptors(vendor_id1);
ASSERT_TRUE(options);
ASSERT_EQ(10, options->size());
// Validate codes of options added to dhcp6 option space.
uint16_t expected_code = 100;
- for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+ for (OptionContainer::const_iterator option_desc = options->begin();
option_desc != options->end(); ++option_desc) {
ASSERT_TRUE(option_desc->option);
EXPECT_EQ(expected_code, option_desc->option->getType());
// Validate codes of options added to isc option space.
expected_code = 105;
- for (Subnet::OptionContainer::const_iterator option_desc = options->begin();
+ for (OptionContainer::const_iterator option_desc = options->begin();
option_desc != options->end(); ++option_desc) {
ASSERT_TRUE(option_desc->option);
EXPECT_EQ(expected_code, option_desc->option->getType());