Commit 90fe9ca2 authored by Thomas Markwalder's avatar Thomas Markwalder

[master] Infrastructure for global host reserverations

- Internal representation of unused subnets is now SunbetID == SUBNET_ID_UNUSED
- Host Reservations with a subnet id value of SUBNET_ID_GLOBAL are global
- kea-dhcp4/6 servers can now parser reservations at the global level
parents 628200e4 dcbbfbfa
This diff is collapsed.
......@@ -938,6 +938,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"reservations\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
case isc::dhcp::Parser4Context::SUBNET4:
return isc::dhcp::Dhcp4Parser::make_RESERVATIONS(driver.loc_);
default:
......
This diff is collapsed.
......@@ -1481,7 +1481,7 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 970, ///< Last index in yytable_.
yylast_ = 964, ///< Last index in yytable_.
yynnts_ = 363, ///< Number of nonterminal symbols.
yyfinal_ = 28, ///< Termination state number.
yyterror_ = 1,
......
......@@ -453,6 +453,7 @@ global_param: valid_lifetime
| user_context
| comment
| sanity_checks
| reservations
| unknown_map_entry
;
......
......@@ -477,6 +477,17 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "reservations") {
HostCollection hosts;
HostReservationsListParser<HostReservationParser4> parser;
parser.parse(SUBNET_ID_GLOBAL, config_pair.second, hosts);
for (auto h = hosts.begin(); h != hosts.end(); ++h) {
srv_cfg->getCfgHosts()->add(*h);
}
continue;
}
// Timers are not used in the global scope. Their values are derived
// to specific subnets (see SimpleParser6::deriveParameters).
// decline-probation-period, dhcp4o6-port, echo-client-id,
......
......@@ -6052,7 +6052,7 @@ TEST_F(Dhcp4ParserTest, comments) {
EXPECT_EQ("aa:bb:cc:dd:ee:ff", host->getHWAddress()->toText(false));
EXPECT_FALSE(host->getDuid());
EXPECT_EQ(100, host->getIPv4SubnetID());
EXPECT_EQ(0, host->getIPv6SubnetID());
EXPECT_EQ(SUBNET_ID_UNUSED, host->getIPv6SubnetID());
EXPECT_EQ("foo.example.com", host->getHostname());
// Check host user context.
......@@ -6103,4 +6103,134 @@ TEST_F(Dhcp4ParserTest, comments) {
#endif
}
// This test verifies that the global host reservations can be specified
TEST_F(Dhcp4ParserTest, globalReservations) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, \n"
"\"renew-timer\": 1000, \n"
"\"reservations\": [\n"
" {\n"
" \"duid\": \"01:02:03:04:05:06:07:08:09:0A\",\n"
" \"ip-address\": \"192.0.200.1\",\n"
" \"hostname\": \"global1\",\n"
" \"option-data\": [\n"
" {\n"
" \"name\": \"name-servers\",\n"
" \"data\": \"192.0.3.15\"\n"
" },\n"
" {\n"
" \"name\": \"default-ip-ttl\",\n"
" \"data\": \"32\"\n"
" }\n"
" ]\n"
" },\n"
" {\n"
" \"hw-address\": \"01:02:03:04:05:06\",\n"
" \"hostname\": \"global2\",\n"
" \"option-data\": [\n"
" {\n"
" \"name\": \"name-servers\",\n"
" \"data\": \"192.0.3.95\"\n"
" },\n"
" {\n"
" \"name\": \"default-ip-ttl\",\n"
" \"data\": \"11\"\n"
" }\n"
" ]\n"
" }],\n"
"\"subnet4\": [ \n"
" { \n"
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],\n"
" \"subnet\": \"192.0.2.0/24\", \n"
" \"id\": 123,\n"
" \"reservations\": [\n"
" ]\n"
" },\n"
" {\n"
" \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ],\n"
" \"subnet\": \"192.0.4.0/24\",\n"
" \"id\": 542\n"
" } ],\n"
"\"valid-lifetime\": 4000"
"}\n";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
checkResult(x, 0);
// Make sure all subnets have been successfully configured. There is no
// need to sanity check the subnet properties because it should have
// been already tested by other tests.
const Subnet4Collection* subnets =
CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll();
ASSERT_TRUE(subnets);
ASSERT_EQ(2, subnets->size());
// Hosts configuration must be available.
CfgHostsPtr hosts_cfg = CfgMgr::instance().getStagingCfg()->getCfgHosts();
ASSERT_TRUE(hosts_cfg);
// Let's create a hardware address of the host named "global2"
std::vector<uint8_t> hwaddr;
for (unsigned int i = 1; i < 7; ++i) {
hwaddr.push_back(static_cast<uint8_t>(i));
}
// Retrieve the global reservation and sanity check the hostname reserved.
ConstHostPtr host = hosts_cfg->get4(SUBNET_ID_GLOBAL, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size());
ASSERT_TRUE(host);
EXPECT_EQ("global2", host->getHostname());
// Check that options are stored correctly.
Option4AddrLstPtr opt_dns =
retrieveOption<Option4AddrLstPtr>(*host, DHO_NAME_SERVERS);
ASSERT_TRUE(opt_dns);
Option4AddrLst::AddressContainer dns_addrs = opt_dns->getAddresses();
ASSERT_EQ(1, dns_addrs.size());
EXPECT_EQ("192.0.3.95", dns_addrs[0].toText());
OptionUint8Ptr opt_ttl =
retrieveOption<OptionUint8Ptr>(*host, DHO_DEFAULT_IP_TTL);
ASSERT_TRUE(opt_ttl);
EXPECT_EQ(11, static_cast<int>(opt_ttl->getValue()));
// This reservation should be global solely and not assigned to
// either subnet
EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size()));
EXPECT_FALSE(hosts_cfg->get4(542, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size()));
// Do the same test for the DUID based reservation.
std::vector<uint8_t> duid;
for (unsigned int i = 1; i < 0xb; ++i) {
duid.push_back(static_cast<uint8_t>(i));
}
// Retrieve the global reservation and sanity check the hostname reserved.
host = hosts_cfg->get4(SUBNET_ID_GLOBAL, Host::IDENT_DUID, &duid[0], duid.size());
ASSERT_TRUE(host);
EXPECT_EQ("global1", host->getHostname());
// Check that options are assigned correctly.
opt_dns = retrieveOption<Option4AddrLstPtr>(*host, DHO_NAME_SERVERS);
ASSERT_TRUE(opt_dns);
dns_addrs = opt_dns->getAddresses();
ASSERT_EQ(1, dns_addrs.size());
EXPECT_EQ("192.0.3.15", dns_addrs[0].toText());
opt_ttl = retrieveOption<OptionUint8Ptr>(*host, DHO_DEFAULT_IP_TTL);
ASSERT_TRUE(opt_ttl);
EXPECT_EQ(32, static_cast<int>(opt_ttl->getValue()));
// This reservation should be global solely and not assigned to
// either subnet
EXPECT_FALSE(hosts_cfg->get4(123, Host::IDENT_DUID, &duid[0], duid.size()));
EXPECT_FALSE(hosts_cfg->get4(542, Host::IDENT_DUID, &duid[0], duid.size()));
}
}
......@@ -1361,7 +1361,7 @@ TEST_F(DORATest, reservationsWithConflicts) {
HostPtr host(new Host(&client.getHWAddress()->hwaddr_[0],
client.getHWAddress()->hwaddr_.size(),
Host::IDENT_HWADDR, SubnetID(1),
SubnetID(0), IOAddress("10.0.0.9")));
SUBNET_ID_UNUSED, IOAddress("10.0.0.9")));
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
CfgMgr::instance().commit();
......@@ -1440,7 +1440,7 @@ TEST_F(DORATest, reservationsWithConflicts) {
host.reset(new Host(&clientB.getHWAddress()->hwaddr_[0],
clientB.getHWAddress()->hwaddr_.size(),
Host::IDENT_HWADDR, SubnetID(1),
SubnetID(0), in_pool_addr));
SUBNET_ID_UNUSED, in_pool_addr));
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
CfgMgr::instance().commit();
......
......@@ -68,8 +68,6 @@ namespace {
///@{
/// @brief extracted configurations
const char* EXTRACTED_CONFIGS[] = {
/// put this after const char* EXTRACTED_CONFIGS[] = {
// CONFIGURATION 0
"{\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
......@@ -1854,13 +1852,73 @@ const char* EXTRACTED_CONFIGS[] = {
" ]\n"
" }\n"
" ]\n"
" }\n",
// CONFIGURATION 63
"{\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"rebind-timer\": 2000,\n"
" \"renew-timer\": 1000,\n"
" \"reservations\": [\n"
" {\n"
" \"duid\": \"01:02:03:04:05:06:07:08:09:0A\",\n"
" \"hostname\": \"global1\",\n"
" \"ip-address\": \"192.0.200.1\",\n"
" \"option-data\": [\n"
" {\n"
" \"data\": \"192.0.3.15\",\n"
" \"name\": \"name-servers\"\n"
" },\n"
" {\n"
" \"data\": \"32\",\n"
" \"name\": \"default-ip-ttl\"\n"
" }\n"
" ]\n"
" },\n"
" {\n"
" \"hostname\": \"global2\",\n"
" \"hw-address\": \"01:02:03:04:05:06\",\n"
" \"option-data\": [\n"
" {\n"
" \"data\": \"192.0.3.95\",\n"
" \"name\": \"name-servers\"\n"
" },\n"
" {\n"
" \"data\": \"11\",\n"
" \"name\": \"default-ip-ttl\"\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"subnet4\": [\n"
" {\n"
" \"id\": 123,\n"
" \"pools\": [\n"
" {\n"
" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n"
" }\n"
" ],\n"
" \"reservations\": [ ],\n"
" \"subnet\": \"192.0.2.0/24\"\n"
" },\n"
" {\n"
" \"id\": 542,\n"
" \"pools\": [\n"
" {\n"
" \"pool\": \"192.0.4.101 - 192.0.4.150\"\n"
" }\n"
" ],\n"
" \"subnet\": \"192.0.4.0/24\"\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n"
};
/// @brief unparsed configurations
const char* UNPARSED_CONFIGS[] = {
///put this after const char* UNPARSED_CONFIGS[] = {
// CONFIGURATION 0
"{\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
......@@ -7496,6 +7554,165 @@ const char* UNPARSED_CONFIGS[] = {
" }\n"
" ],\n"
" \"subnet4\": [ ]\n"
" }\n",
// CONFIGURATION 63
"{\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
" \"enable-updates\": false,\n"
" \"generated-prefix\": \"myhost\",\n"
" \"hostname-char-replacement\": \"\",\n"
" \"hostname-char-set\": \"\",\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"override-client-update\": false,\n"
" \"override-no-update\": false,\n"
" \"qualifying-suffix\": \"\",\n"
" \"replace-client-name\": \"never\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"rebind-timer\": 2000,\n"
" \"renew-timer\": 1000,\n"
" \"reservations\": [\n"
" {\n"
" \"boot-file-name\": \"\",\n"
" \"client-classes\": [ ],\n"
" \"hostname\": \"global2\",\n"
" \"hw-address\": \"01:02:03:04:05:06\",\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [\n"
" {\n"
" \"always-send\": false,\n"
" \"code\": 5,\n"
" \"csv-format\": true,\n"
" \"data\": \"192.0.3.95\",\n"
" \"name\": \"name-servers\",\n"
" \"space\": \"dhcp4\"\n"
" },\n"
" {\n"
" \"always-send\": false,\n"
" \"code\": 23,\n"
" \"csv-format\": true,\n"
" \"data\": \"11\",\n"
" \"name\": \"default-ip-ttl\",\n"
" \"space\": \"dhcp4\"\n"
" }\n"
" ],\n"
" \"server-hostname\": \"\"\n"
" },\n"
" {\n"
" \"boot-file-name\": \"\",\n"
" \"client-classes\": [ ],\n"
" \"duid\": \"01:02:03:04:05:06:07:08:09:0a\",\n"
" \"hostname\": \"global1\",\n"
" \"ip-address\": \"192.0.200.1\",\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [\n"
" {\n"
" \"always-send\": false,\n"
" \"code\": 5,\n"
" \"csv-format\": true,\n"
" \"data\": \"192.0.3.15\",\n"
" \"name\": \"name-servers\",\n"
" \"space\": \"dhcp4\"\n"
" },\n"
" {\n"
" \"always-send\": false,\n"
" \"code\": 23,\n"
" \"csv-format\": true,\n"
" \"data\": \"32\",\n"
" \"name\": \"default-ip-ttl\",\n"
" \"space\": \"dhcp4\"\n"
" }\n"
" ],\n"
" \"server-hostname\": \"\"\n"
" }\n"
" ],\n"
" \"sanity-checks\": {\n"
" \"lease-checks\": \"warn\"\n"
" },\n"
" \"shared-networks\": [ ],\n"
" \"subnet4\": [\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"id\": 123,\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"pools\": [\n"
" {\n"
" \"option-data\": [ ],\n"
" \"pool\": \"192.0.2.1-192.0.2.100\"\n"
" }\n"
" ],\n"
" \"rebind-timer\": 2000,\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"renew-timer\": 1000,\n"
" \"reservation-mode\": \"all\",\n"
" \"reservations\": [ ],\n"
" \"server-hostname\": \"\",\n"
" \"subnet\": \"192.0.2.0/24\",\n"
" \"valid-lifetime\": 4000\n"
" },\n"
" {\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
" \"4o6-subnet\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"id\": 542,\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"pools\": [\n"
" {\n"
" \"option-data\": [ ],\n"
" \"pool\": \"192.0.4.101-192.0.4.150\"\n"
" }\n"
" ],\n"
" \"rebind-timer\": 2000,\n"
" \"relay\": {\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"renew-timer\": 1000,\n"
" \"reservation-mode\": \"all\",\n"
" \"reservations\": [ ],\n"
" \"server-hostname\": \"\",\n"
" \"subnet\": \"192.0.4.0/24\",\n"
" \"valid-lifetime\": 4000\n"
" }\n"
" ],\n"
" \"valid-lifetime\": 4000\n"
" }\n"
};
......
This diff is collapsed.
......@@ -1222,6 +1222,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"reservations\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
case isc::dhcp::Parser6Context::SUBNET6:
return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(driver.loc_);
default:
......
This diff is collapsed.
......@@ -1500,7 +1500,7 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 991, ///< Last index in yytable_.
yylast_ = 987, ///< Last index in yytable_.
yynnts_ = 377, ///< Number of nonterminal symbols.
yyfinal_ = 30, ///< Termination state number.
yyterror_ = 1,
......
......@@ -454,6 +454,7 @@ global_param: preferred_lifetime
| user_context
| comment
| sanity_checks
| reservations
| unknown_map_entry
;
......
......@@ -589,6 +589,17 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "reservations") {
HostCollection hosts;
HostReservationsListParser<HostReservationParser6> parser;
parser.parse(SUBNET_ID_GLOBAL, config_pair.second, hosts);
for (auto h = hosts.begin(); h != hosts.end(); ++h) {
srv_config->getCfgHosts()->add(*h);
}
continue;
}
// Timers are not used in the global scope. Their values are derived
// to specific subnets (see SimpleParser6::deriveParameters).
// decline-probation-period, dhcp4o6-port and user-context
......
......@@ -6647,7 +6647,7 @@ TEST_F(Dhcp6ParserTest, comments) {
EXPECT_EQ(Host::IDENT_HWADDR, host->getIdentifierType());
EXPECT_EQ("aa:bb:cc:dd:ee:ff", host->getHWAddress()->toText(false));
EXPECT_FALSE(host->getDuid());
EXPECT_EQ(0, host->getIPv4SubnetID());
EXPECT_EQ(SUBNET_ID_UNUSED, host->getIPv4SubnetID());
EXPECT_EQ(100, host->getIPv6SubnetID());
EXPECT_EQ("foo.example.com", host->getHostname());
......@@ -6689,4 +6689,143 @@ TEST_F(Dhcp6ParserTest, comments) {
EXPECT_EQ("\"No dynamic DNS\"", ctx_d2->get("comment")->str());
}
// This test verifies that the global host reservations can be specified.
TEST_F(Dhcp6ParserTest, globalReservations) {
ConstElementPtr x;
string config = "{ " + genIfaceConfig() + ",\n"
"\"rebind-timer\": 2000, \n"
"\"renew-timer\": 1000, \n"
"\"reservations\": [\n"
" {\n"
" \"duid\": \"01:02:03:04:05:06:07:08:09:0A\",\n"
" \"ip-addresses\": [ \"2001:db8:2::1234\" ],\n"
" \"hostname\": \"\",\n"
" \"option-data\": [\n"
" {\n"
" \"name\": \"dns-servers\",\n"
" \"data\": \"2001:db8:2::1111\"\n"
" },\n"
" {\n"
" \"name\": \"preference\",\n"
" \"data\": \"11\"\n"
" }\n"
" ]\n"
" },\n"
" {\n"
" \"hw-address\": \"01:02:03:04:05:06\",\n"
" \"ip-addresses\": [ \"2001:db8:2::abcd\" ],\n"
" \"hostname\": \"\",\n"
" \"option-data\": [\n"
" {\n"
" \"name\": \"dns-servers\",\n"
" \"data\": \"2001:db8:2::abbc\"\n"
" },\n"
" {\n"
" \"name\": \"preference\",\n"
" \"data\": \"25\"\n"
" }\n"
" ]\n"
" }\n"
"],\n"
"\"subnet6\": [ \n"
" { \n"
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],\n"
" \"subnet\": \"2001:db8:1::/64\", \n"
" \"id\": 123,\n"
" \"reservations\": [\n"
" ]\n"
" },\n"
" {\n"
" \"pools\": [ ],\n"
" \"subnet\": \"2001:db8:2::/64\", \n"
" \"id\": 234\n"
" },\n"
" {\n"
" \"pools\": [ ],\n"
" \"subnet\": \"2001:db8:3::/64\", \n"
" \"id\": 542\n"
" }\n"
"],\n"
"\"preferred-lifetime\": 3000,\n"
"\"valid-lifetime\": 4000 }\n";
ConstElementPtr json;
(json = parseDHCP6(config));
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
checkResult(x, 0);
// Make sure all subnets have been successfully configured. There is no
// need to sanity check the subnet properties because it should have
// been already tested by other tests.
const Subnet6Collection* subnets =
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
ASSERT_TRUE(subnets);
ASSERT_EQ(3, subnets->size());
// Hosts configuration must be available.
CfgHostsPtr hosts_cfg = CfgMgr::instance().getStagingCfg()->getCfgHosts();
ASSERT_TRUE(hosts_cfg);
// Let's create an object holding hardware address of the host having
// a reservation in the subnet having id of 234. For simplicity the
// address is a collection of numbers from 1 to 6.
std::vector<uint8_t> hwaddr;
for (unsigned int i = 1; i < 7; ++i) {
hwaddr.push_back(static_cast<uint8_t>(i));
}
// Retrieve the reservation and sanity check the address reserved.
ConstHostPtr host = hosts_cfg->get6(SUBNET_ID_GLOBAL, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size());
ASSERT_TRUE(host);
IPv6ResrvRange resrv = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
ASSERT_EQ(1, std::distance(resrv.first, resrv.second));
EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA,
IOAddress("2001:db8:2::abcd")),
resrv));
// This reservation should be solely assigned to the subnet 234,
// and not to other two.
EXPECT_FALSE(hosts_cfg->get6(123, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size()));
EXPECT_FALSE(hosts_cfg->get6(542, Host::IDENT_HWADDR,
&hwaddr[0], hwaddr.size()));
// Check that options are assigned correctly.
Option6AddrLstPtr opt_dns =
retrieveOption<Option6AddrLstPtr>(*host, D6O_NAME_SERVERS);
ASSERT_TRUE(opt_dns);
Option6AddrLst::AddressContainer dns_addrs = opt_dns->getAddresses();
ASSERT_EQ(1, dns_addrs.size());