Commit c50a482e authored by Francis Dupont's avatar Francis Dupont
Browse files

[4097a] Finished the DHCPv6 part

parent db7f698d
......@@ -1826,10 +1826,8 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
}
// Goal of this test is to verify that global option
// data is configured for the subnet if the subnet
// configuration does not include options configuration.
TEST_F(Dhcp4ParserTest, optionDataDefaults) {
// Goal of this test is to verify that global option data is configured
TEST_F(Dhcp4ParserTest, optionDataDefaultsGlobal) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000,"
......@@ -1855,10 +1853,78 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
checkResult(x, 0);
// These options are global
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
ASSERT_EQ(0, options->size());
options = CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll("dhcp4");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
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<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));
const uint8_t foo_expected[] = {
0xAB, 0xCD, 0xEF, 0x01, 0x05
};
// Check if option is valid in terms of code and carried data.
testOption(*range.first, 56, foo_expected, sizeof(foo_expected));
range = idx.equal_range(23);
ASSERT_EQ(1, std::distance(range.first, range.second));
// Do another round of testing with second option.
const uint8_t foo2_expected[] = {
0x01
};
testOption(*range.first, 23, foo2_expected, sizeof(foo2_expected));
}
// Goal of this test is to verify that subnet option data is configured
TEST_F(Dhcp4ParserTest, optionDataDefaultsSubnet) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\","
" \"option-data\": [ {"
" \"name\": \"dhcp-message\","
" \"data\": \"ABCDEF0105\","
" \"csv-format\": False"
" },"
" {"
" \"name\": \"default-ip-ttl\","
" \"data\": \"01\","
" \"csv-format\": False"
" } ]"
" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
checkResult(x, 0);
// These options are subnet options
OptionContainerPtr options =
CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll("dhcp4");
ASSERT_EQ(0, options->size());
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
options = subnet->getCfgOption()->getAll("dhcp4");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
......@@ -1933,21 +1999,21 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
ASSERT_TRUE(status);
checkResult(status, 0);
// Options should be now available for the subnet.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
// Options should be now available
// Try to get the option from the space dhcp4.
OptionDescriptor desc1 = subnet->getCfgOption()->get("dhcp4", 56);
OptionDescriptor desc1 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get("dhcp4", 56);
ASSERT_TRUE(desc1.option_);
EXPECT_EQ(56, desc1.option_->getType());
// Try to get the option from the space isc.
OptionDescriptor desc2 = subnet->getCfgOption()->get("isc", 56);
OptionDescriptor desc2 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get("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.
OptionDescriptor desc3 = subnet->getCfgOption()->get("non-existing", 56);
OptionDescriptor desc3 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get("non-existing", 56);
ASSERT_FALSE(desc3.option_);
}
......@@ -1960,8 +2026,8 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
// @todo DHCP configurations has many dependencies between
// parameters. First of all, configuration for subnet is
// inherited from the global values. Thus subnet has to be
// parameters. First of all, configuration for subnet was
// inherited from the global values. Thus subnet had to be
// configured when all global values have been configured.
// Also, an option can encapsulate another option only
// if the latter has been configured. For this reason in this
......@@ -2011,7 +2077,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
CfgMgr::instance().clear();
// Stage 2. Configure base option and a subnet. Please note that
// the configuration from the stage 2 is repeated because BIND
// the configuration from the stage 2 is repeated because Kea
// configuration manager sends whole configuration for the lists
// where at least one element is being modified or added.
config = "{ " + genIfaceConfig() + "," +
......@@ -2063,18 +2129,15 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
ASSERT_TRUE(status);
checkResult(status, 0);
// Get the subnet.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
// We should have one option available.
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
OptionContainerPtr options =
CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll("dhcp4");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
OptionDescriptor desc = subnet->getCfgOption()->get("dhcp4", 222);
OptionDescriptor desc =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get("dhcp4", 222);
EXPECT_TRUE(desc.option_);
EXPECT_EQ(222, desc.option_->getType());
......@@ -2605,19 +2668,15 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
ASSERT_TRUE(status);
checkResult(status, 0);
// Get the subnet.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
// We should have one option available.
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp4");
OptionContainerPtr options =
CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll("dhcp4");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
// Get the option.
OptionDescriptor desc =
subnet->getCfgOption()->get("dhcp4", DHO_VENDOR_ENCAPSULATED_OPTIONS);
OptionDescriptor desc = CfgMgr::instance().getStagingCfg()->
getCfgOption()->get("dhcp4", DHO_VENDOR_ENCAPSULATED_OPTIONS);
EXPECT_TRUE(desc.option_);
EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, desc.option_->getType());
......@@ -2651,7 +2710,7 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
}
// This test checks if vendor options can be specified in the config file
// (in hex format), and later retrieved from configured subnet
// (in hex format), and later retrieved
TEST_F(Dhcp4ParserTest, vendorOptionsHex) {
// This configuration string is to configure two options
......@@ -2689,28 +2748,26 @@ TEST_F(Dhcp4ParserTest, vendorOptionsHex) {
ASSERT_TRUE(status);
checkResult(status, 0);
// Options should be now available for the subnet.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
OptionDescriptor desc1 = subnet->getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100);
OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()->
getCfgOption()->get(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
OptionDescriptor desc2 = subnet->getCfgOption()->get(1234, 100);
OptionDescriptor desc2 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get(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.
OptionDescriptor desc3 = subnet->getCfgOption()->get(5678, 100);
OptionDescriptor desc3 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 100);
ASSERT_FALSE(desc3.option_);
}
// This test checks if vendor options can be specified in the config file,
// (in csv format), and later retrieved from configured subnet
// (in csv format), and later retrieved
TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
// This configuration string is to configure two options
......@@ -2746,19 +2803,16 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
ASSERT_TRUE(status);
checkResult(status, 0);
// Options should be now available for the subnet.
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.5"));
ASSERT_TRUE(subnet);
// Try to get the option from the vendor space 4491
OptionDescriptor desc1 = subnet->getCfgOption()->get(VENDOR_ID_CABLE_LABS, 100);
OptionDescriptor desc1 = CfgMgr::instance().getStagingCfg()->
getCfgOption()->get(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.
OptionDescriptor desc2 = subnet->getCfgOption()->get(5678, 100);
OptionDescriptor desc2 =
CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 100);
ASSERT_FALSE(desc2.option_);
}
......
......@@ -1844,8 +1844,10 @@ TEST_F(Dhcpv4SrvTest, subnetClassPriority) {
}
// Checks class options have the priority over global options
// Note it is not currently the case, cf #4205
TEST_F(Dhcpv4SrvTest, classGlobalPriority) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
NakedDhcpv4Srv srv(0);
// A global ip-forwarding option is set in the response.
......@@ -1914,13 +1916,13 @@ TEST_F(Dhcpv4SrvTest, classGlobalPriority) {
ASSERT_TRUE(opt);
ASSERT_GT(opt->len(), opt->getHeaderLen());
// Classification sets the value to true/1, global to false/0
// Here class should have the priority but hasn't, cf #4205
EXPECT_EQ(0, opt->getUint8());
// Here class has the priority
EXPECT_NE(0, opt->getUint8());
}
// Checks if the client-class field is indeed used for subnet selection.
// Note that packet classification is already checked in Dhcpv4SrvTest
// .*clientClassification above.
// .*Classification above.
TEST_F(Dhcpv4SrvTest, clientClassify) {
// This test configures 2 subnets. We actually only need the
......
......@@ -884,16 +884,16 @@ Dhcpv6Srv::copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
void
Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr&, Pkt6Ptr& answer) {
Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr&, Pkt6Ptr& answer,
const CfgOptionList&) {
// add server-id
answer->addOption(getServerID());
}
void
Dhcpv6Srv::buildCfgOptionList(const Pkt6Ptr& question,
AllocEngine::ClientContext6& ctx) {
CfgOptionList& co_list = getCfgOptionList();
AllocEngine::ClientContext6& ctx,
CfgOptionList& co_list) {
// First subnet configured options
if (ctx.subnet_) {
co_list.push_back(ctx.subnet_->getCfgOption());
......@@ -921,7 +921,8 @@ Dhcpv6Srv::buildCfgOptionList(const Pkt6Ptr& question,
void
Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx) {
AllocEngine::ClientContext6& ctx,
const CfgOptionList& co_list) {
// Client requests some options using ORO option. Try to
// get this option from client's message.
......@@ -938,7 +939,6 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
const std::vector<uint16_t>& requested_opts = option_oro->getValues();
BOOST_FOREACH(uint16_t opt, requested_opts) {
// Iterate on the configured option list
const CfgOptionList& co_list = getCfgOptionList();
for (CfgOptionList::const_iterator copts = co_list.begin();
copts != co_list.end(); ++copts) {
OptionDescriptor desc = (*copts)->get("dhcp6", opt);
......@@ -952,8 +952,10 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
}
void
Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx) {
Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question,
Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const CfgOptionList& co_list) {
// Leave if there is no subnet matching the incoming packet.
// There is no need to log the error message here because
......@@ -990,7 +992,6 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer
bool added = false;
const std::vector<uint16_t>& requested_opts = oro->getValues();
BOOST_FOREACH(uint16_t opt, requested_opts) {
const CfgOptionList& co_list = getCfgOptionList();
for (CfgOptionList::const_iterator copts = co_list.begin();
copts != co_list.end(); ++copts) {
OptionDescriptor desc = (*copts)->get(vendor_id, opt);
......@@ -2320,10 +2321,11 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
}
copyClientOptions(solicit, response);
buildCfgOptionList(solicit, ctx);
appendDefaultOptions(solicit, response);
appendRequestedOptions(solicit, response, ctx);
appendRequestedVendorOptions(solicit, response, ctx);
CfgOptionList co_list;
buildCfgOptionList(solicit, ctx, co_list);
appendDefaultOptions(solicit, response, co_list);
appendRequestedOptions(solicit, response, ctx, co_list);
appendRequestedVendorOptions(solicit, response, ctx, co_list);
processClientFqdn(solicit, response, ctx);
assignLeases(solicit, response, ctx);
......@@ -2348,10 +2350,11 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
copyClientOptions(request, reply);
buildCfgOptionList(request, ctx);
appendDefaultOptions(request, reply);
appendRequestedOptions(request, reply, ctx);
appendRequestedVendorOptions(request, reply, ctx);
CfgOptionList co_list;
buildCfgOptionList(request, ctx, co_list);
appendDefaultOptions(request, reply, co_list);
appendRequestedOptions(request, reply, ctx, co_list);
appendRequestedVendorOptions(request, reply, ctx, co_list);
processClientFqdn(request, reply, ctx);
assignLeases(request, reply, ctx);
......@@ -2372,9 +2375,10 @@ Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
copyClientOptions(renew, reply);
buildCfgOptionList(renew, ctx);
appendDefaultOptions(renew, reply);
appendRequestedOptions(renew, reply, ctx);
CfgOptionList co_list;
buildCfgOptionList(renew, ctx, co_list);
appendDefaultOptions(renew, reply, co_list);
appendRequestedOptions(renew, reply, ctx, co_list);
processClientFqdn(renew, reply, ctx);
extendLeases(renew, reply, ctx);
......@@ -2395,9 +2399,10 @@ Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
copyClientOptions(rebind, reply);
buildCfgOptionList(rebind, ctx);
appendDefaultOptions(rebind, reply);
appendRequestedOptions(rebind, reply, ctx);
CfgOptionList co_list;
buildCfgOptionList(rebind, ctx, co_list);
appendDefaultOptions(rebind, reply, co_list);
appendRequestedOptions(rebind, reply, ctx, co_list);
processClientFqdn(rebind, reply, ctx);
extendLeases(rebind, reply, ctx);
......@@ -2426,9 +2431,10 @@ Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
// Make sure that the necessary options are included.
copyClientOptions(confirm, reply);
buildCfgOptionList(confirm, ctx);
appendDefaultOptions(confirm, reply);
appendRequestedOptions(confirm, reply, ctx);
CfgOptionList co_list;
buildCfgOptionList(confirm, ctx, co_list);
appendDefaultOptions(confirm, reply, co_list);
appendRequestedOptions(confirm, reply, ctx, co_list);
// Indicates if at least one address has been verified. If no addresses
// are verified it means that the client has sent no IA_NA options
// or no IAAddr options and that client's message has to be discarded.
......@@ -2507,7 +2513,9 @@ Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
copyClientOptions(release, reply);
appendDefaultOptions(release, reply);
CfgOptionList co_list;
// buildCfgOptionList(release, ctx, co_list);
appendDefaultOptions(release, reply, co_list);
releaseLeases(release, reply, ctx);
......@@ -2532,8 +2540,12 @@ Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
// Copy client options (client-id, also relay information if present)
copyClientOptions(decline, reply);
// Get the configured option list
CfgOptionList co_list;
buildCfgOptionList(decline, ctx, co_list);
// Include server-id
appendDefaultOptions(decline, reply);
appendDefaultOptions(decline, reply, co_list);
if (declineLeases(decline, reply, ctx)) {
return (reply);
......@@ -2808,15 +2820,16 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& inf_request) {
copyClientOptions(inf_request, reply);
// Build the configured option list for append methods
buildCfgOptionList(inf_request, ctx);
CfgOptionList co_list;
buildCfgOptionList(inf_request, ctx, co_list);
// Append default options, i.e. options that the server is supposed
// to put in all messages it sends (server-id for now, but possibly other
// options once we start supporting authentication)
appendDefaultOptions(inf_request, reply);
appendDefaultOptions(inf_request, reply, co_list);
// Try to assign options that were requested by the client.
appendRequestedOptions(inf_request, reply, ctx);
appendRequestedOptions(inf_request, reply, ctx, co_list);
return (reply);
}
......
......@@ -429,24 +429,17 @@ protected:
/// @param answer server's message (options will be copied here)
void copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @brief Returns the configured option list
CfgOptionList& getCfgOptionList() {
return (cfg_option_list_);
}
/// @brief Returns the configured option list
const CfgOptionList& getCfgOptionList() const {
return (cfg_option_list_);
}
/// @brief Build the configured option list
///
/// @note The configured option list is an *ordered* list of
/// @c CfgOption objects used to append options to the response.
///
/// @param ex The exchange where the configured option list is cached
/// @param question client's message
/// @param ctx client context (for the subnet)
/// @param co_list configured option list to build
void buildCfgOptionList(const Pkt6Ptr& question,
AllocEngine::ClientContext6& ctx);
AllocEngine::ClientContext6& ctx,
CfgOptionList& co_list);
/// @brief Appends default options to server's answer.
///
......@@ -456,7 +449,9 @@ protected:
///
/// @param question client's message
/// @param answer server's message (options will be added here)
void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @param co_list configured option list (currently unused)
void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
const CfgOptionList& co_list);
/// @brief Appends requested options to server's answer.
///
......@@ -465,8 +460,10 @@ protected:
/// @param question client's message
/// @param answer server's message (options will be added here)
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param co_list configured option list
void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
AllocEngine::ClientContext6& ctx,
const CfgOptionList& co_list);
/// @brief Appends requested vendor options to server's answer.
///
......@@ -476,8 +473,10 @@ protected:
/// @param question client's message
/// @param answer server's message (vendor options will be added here)
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param co_list configured option list
void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
AllocEngine::ClientContext6& ctx,
const CfgOptionList& co_list);
/// @brief Assigns leases.
///
......@@ -825,9 +824,6 @@ private:
/// UDP port number on which server listens.
uint16_t port_;
/// @brief Configured option list for appending otions.
CfgOptionList cfg_option_list_;
protected:
/// Indicates if shutdown is in progress. Setting it to true will
......
......@@ -2057,10 +2057,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
EXPECT_FALSE(def->getArrayType());
}
// Goal of this test is to verify that global option
// data is configured for the subnet if the subnet
// configuration does not include options configuration.
TEST_F(Dhcp6ParserTest, optionDataDefaults) {
// Goal of this test is to verify that global option data is configured
TEST_F(Dhcp6ParserTest, optionDataDefaultsGlobal) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + ","
"\"preferred-lifetime\": 3000,"
......@@ -2086,10 +2084,86 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
checkResult(x, 0);
// These options are global
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
ASSERT_TRUE(subnet);
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
ASSERT_EQ(0, options->size());
options = CfgMgr::instance().getStagingCfg()->getCfgOption()->getAll("dhcp6");
ASSERT_EQ(2, options->size());
// Get the search index. Index #1 is to search using option code.
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<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));
const uint8_t subid_expected[] = {
0xAB, 0xCD, 0xEF, 0x01, 0x05
};
// Check if option is valid in terms of code and carried data.
testOption(*range.first, D6O_SUBSCRIBER_ID, subid_expected,
sizeof(subid_expected));
range = idx.equal_range(D6O_PREFERENCE);
ASSERT_EQ(1, std::distance(range.first, range.second));
// Do another round of testing with second option.
const uint8_t pref_expected[] = {
0x01
};
testOption(*range.first, D6O_PREFERENCE, pref_expected,
sizeof(pref_expected));
// Check that options with other option codes are not returned.
for (uint16_t code = 47; code < 57; ++code) {
range = idx.equal_range(code);
EXPECT_EQ(0, std::distance(range.first, range.second));
}
}
// Goal of this test is to verify that subnet option data is configured
TEST_F(Dhcp6ParserTest, optionDataDefaultsSubnet) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + ","
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
" \"subnet\": \"2001:db8:1::/64\","
" \"option-data\": [ {"
" \"name\": \"subscriber-id\","
" \"data\": \"ABCDEF0105\","
"