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

[5277] Extended server-hostname and boot-file-name (native for subnet4, else inherited)

parent d3efeac6
......@@ -72,6 +72,8 @@
"id": 1,
"match-client-id": true,
"next-server": "0.0.0.0",
"server-hostname": "",
"boot-file-name": "",
"option-data": [ ],
"pools": [ ],
"rebind-timer": 20,
......@@ -91,6 +93,8 @@
"id": 2,
"match-client-id": true,
"next-server": "0.0.0.0",
"server-hostname": "",
"boot-file-name": "",
"option-data": [ ],
"pools": [ ],
"rebind-timer": 20,
......
......@@ -2591,14 +2591,24 @@ It is merely echoed by the server
not be sent. It may also be set to an empty string, which means the same as if
it was not defined at all, i.e. use the global value.
</para>
<para>
The <command>server-hostname</command> (that conveys a server hostname,
can be up to 64 bytes long and will be sent in the sname field) and
<command>boot-file-name</command> (that conveys the configuration file,
can be up to 128 bytes long and will be sent using file field)
directives are handled the same way than <command>next-server</command>.
</para>
<screen>
"Dhcp4": {
<userinput>"next-server": "192.0.2.123"</userinput>,
<userinput>"next-server": "192.0.2.123",
"boot-file-name": "/dev/null"</userinput>,
...,
"subnet4": [
{
<userinput>"next-server": "192.0.2.234"</userinput>,
<userinput>"next-server": "192.0.2.234",
"server-hostname": "some-name.example.org",
"boot-file-name": "bootfile.efi"</userinput>,
...
}
]
......
......@@ -2165,6 +2165,28 @@ Dhcpv4Srv::setFixedFields(Dhcpv4Exchange& ex) {
if (!subnet_next_server.isV4Zero()) {
response->setSiaddr(subnet_next_server);
}
const string& sname = subnet->getSname();
if (!sname.empty()) {
// Converting string to (const uint8_t*, size_t len) format is
// tricky. reinterpret_cast is not the most elegant solution,
// but it does avoid us making unnecessary copy. We will convert
// sname and file fields in Pkt4 to string one day and life
// will be easier.
response->setSname(reinterpret_cast<const uint8_t*>(sname.c_str()),
sname.size());
}
const string& filename = subnet->getFilename();
if (!filename.empty()) {
// Converting string to (const uint8_t*, size_t len) format is
// tricky. reinterpret_cast is not the most elegant solution,
// but it does avoid us making unnecessary copy. We will convert
// sname and file fields in Pkt4 to string one day and life
// will be easier.
response->setFile(reinterpret_cast<const uint8_t*>(filename.c_str()),
filename.size());
}
}
// Step 2: Try to set the values based on classes.
......
......@@ -455,7 +455,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
(config_pair.first == "dhcp4o6-port") ||
(config_pair.first == "echo-client-id") ||
(config_pair.first == "match-client-id") ||
(config_pair.first == "next-server")) {
(config_pair.first == "next-server") ||
(config_pair.first == "server-hostname") ||
(config_pair.first == "boot-file-name")) {
continue;
}
......
......@@ -1106,14 +1106,16 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) {
/// @todo: implement subnet removal test as part of #3281.
// Checks if the next-server defined as global parameter is taken into
// consideration.
// Checks if the next-server and other fixed BOOTP fields defined as
// global parameter are taken into consideration.
TEST_F(Dhcp4ParserTest, nextServerGlobal) {
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"next-server\": \"1.2.3.4\", "
"\"server-hostname\": \"foo\", "
"\"boot-file-name\": \"bar\", "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\" } ],"
......@@ -1135,10 +1137,12 @@ TEST_F(Dhcp4ParserTest, nextServerGlobal) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
EXPECT_EQ("foo", subnet->getSname());
EXPECT_EQ("bar", subnet->getFilename());
}
// Checks if the next-server defined as subnet parameter is taken into
// consideration.
// Checks if the next-server and other fixed BOOTP fields defined as
// subnet parameter are taken into consideration.
TEST_F(Dhcp4ParserTest, nextServerSubnet) {
string config = "{ " + genIfaceConfig() + "," +
......@@ -1147,6 +1151,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) {
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"foo\", "
" \"boot-file-name\": \"bar\", "
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
......@@ -1166,6 +1172,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
EXPECT_EQ("foo", subnet->getSname());
EXPECT_EQ("bar", subnet->getFilename());
}
// Test checks several negative scenarios for next-server configuration: bogus
......@@ -1209,12 +1217,43 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) {
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
// Config with too large server-hostname
string bigsname(Pkt4::MAX_SNAME_LEN + 1, ' ');
string config_bogus4 = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"rebind-timer\": 2000, "
" \"renew-timer\": 1000, "
" \"server-hostname\": \"" + bigsname + "\", " +
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
// Config with too large boot-file-hostname
string bigfilename(Pkt4::MAX_FILE_LEN + 1, ' ');
string config_bogus5 = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"rebind-timer\": 2000, "
" \"renew-timer\": 1000, "
" \"boot-file-name\": \"" + bigfilename + "\", " +
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
ConstElementPtr json1;
ASSERT_NO_THROW(json1 = parseDHCP4(config_bogus1));
ConstElementPtr json2;
ASSERT_NO_THROW(json2 = parseDHCP4(config_bogus2));
ConstElementPtr json3;
ASSERT_NO_THROW(json3 = parseDHCP4(config_bogus3));
ConstElementPtr json4;
ASSERT_NO_THROW(json4 = parseDHCP4(config_bogus4));
ConstElementPtr json5;
ASSERT_NO_THROW(json5 = parseDHCP4(config_bogus5));
// check if returned status is always a failure
ConstElementPtr status;
......@@ -1233,6 +1272,18 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) {
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3));
checkResult(status, 0);
EXPECT_FALSE(errorContainsPosition(status, "<string>"));
CfgMgr::instance().clear();
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json4));
checkResult(status, 1);
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
CfgMgr::instance().clear();
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json5));
checkResult(status, 1);
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
}
// Checks if the next-server defined as global value is overridden by subnet
......@@ -1243,9 +1294,13 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"nohost\","
"\"boot-file-name\": \"nofile\","
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"some-name.example.org\","
" \"boot-file-name\": \"bootfile.efi\","
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
......@@ -1265,6 +1320,8 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
EXPECT_EQ("some-name.example.org", subnet->getSname());
EXPECT_EQ("bootfile.efi", subnet->getFilename());
}
// Check whether it is possible to configure echo-client-id
......@@ -5229,6 +5286,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
" \"interface\": \"eth0\",\n"
" \"match-client-id\": false,\n"
" \"next-server\": \"1.2.3.4\",\n"
" \"server-hostname\": \"foo\",\n"
" \"boot-file-name\": \"bar\",\n"
" \"relay\": {\n"
" \"ip-address\": \"5.6.7.8\"\n"
" },\n"
......@@ -5249,6 +5308,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
" \"valid-lifetime\": 400,\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"11.22.33.44\",\n"
" \"server-hostname\": \"some-name.example.org\",\n"
" \"boot-file-name\": \"bootfile.efi\",\n"
" \"relay\": {\n"
" \"ip-address\": \"55.66.77.88\"\n"
" },\n"
......@@ -5299,6 +5360,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("eth0", s->getIface());
EXPECT_EQ(false, s->getMatchClientId());
EXPECT_EQ(IOAddress("1.2.3.4"), s->getSiaddr());
EXPECT_EQ("foo", s->getSname());
EXPECT_EQ("bar", s->getFilename());
EXPECT_EQ(IOAddress("5.6.7.8"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode());
......@@ -5312,6 +5375,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("eth0", s->getIface());
EXPECT_EQ(true, s->getMatchClientId());
EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr());
EXPECT_EQ("some-name.example.org", s->getSname());
EXPECT_EQ("bootfile.efi", s->getFilename());
EXPECT_EQ(IOAddress("55.66.77.88"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode());
......@@ -5329,6 +5394,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("", s->getIface());
EXPECT_EQ(true, s->getMatchClientId());
EXPECT_EQ(IOAddress("0.0.0.0"), s->getSiaddr());
EXPECT_TRUE(s->getSname().empty());
EXPECT_TRUE(s->getFilename().empty());
EXPECT_EQ(IOAddress("0.0.0.0"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode());
}
......
......@@ -1255,7 +1255,7 @@ TEST_F(Dhcpv4SrvTest, siaddr) {
// Checks if the next-server defined as global value is overridden by subnet
// specific value and returned in server messages. There's also similar test for
// checking parser only configuration, see Dhcp4ParserTest.nextServerOverride in
// config_parser_unittest.cc.
// config_parser_unittest.cc. This test was extended to other BOOTP fixed fields.
TEST_F(Dhcpv4SrvTest, nextServerOverride) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
......@@ -1270,9 +1270,13 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"nohost\", "
"\"boot-file-name\": \"nofile\", "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"some-name.example.org\", "
" \"boot-file-name\": \"bootfile.efi\", "
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
......@@ -1300,6 +1304,16 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
EXPECT_EQ(DHCPOFFER, offer->getType());
EXPECT_EQ("1.2.3.4", offer->getSiaddr().toText());
std::string sname("some-name.example.org");
uint8_t sname_buf[Pkt4::MAX_SNAME_LEN];
std::memset(sname_buf, 0, Pkt4::MAX_SNAME_LEN);
std::memcpy(sname_buf, sname.c_str(), sname.size());
EXPECT_EQ(0, std::memcmp(sname_buf, &offer->getSname()[0], Pkt4::MAX_SNAME_LEN));
std::string filename("bootfile.efi");
uint8_t filename_buf[Pkt4::MAX_FILE_LEN];
std::memset(filename_buf, 0, Pkt4::MAX_FILE_LEN);
std::memcpy(filename_buf, filename.c_str(), filename.size());
EXPECT_EQ(0, std::memcmp(filename_buf, &offer->getFile()[0], Pkt4::MAX_FILE_LEN));
}
// Checks if the next-server defined as global value is used in responses
......@@ -1320,6 +1334,8 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"some-name.example.org\", "
"\"boot-file-name\": \"bootfile.efi\", "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\" } ],"
......@@ -1349,6 +1365,16 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
EXPECT_EQ(DHCPOFFER, offer->getType());
EXPECT_EQ("192.0.0.1", offer->getSiaddr().toText());
std::string sname("some-name.example.org");
uint8_t sname_buf[Pkt4::MAX_SNAME_LEN];
std::memset(sname_buf, 0, Pkt4::MAX_SNAME_LEN);
std::memcpy(sname_buf, sname.c_str(), sname.size());
EXPECT_EQ(0, std::memcmp(sname_buf, &offer->getSname()[0], Pkt4::MAX_SNAME_LEN));
std::string filename("bootfile.efi");
uint8_t filename_buf[Pkt4::MAX_FILE_LEN];
std::memset(filename_buf, 0, Pkt4::MAX_FILE_LEN);
std::memcpy(filename_buf, filename.c_str(), filename.size());
EXPECT_EQ(0, std::memcmp(filename_buf, &offer->getFile()[0], Pkt4::MAX_FILE_LEN));
}
// Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
......
......@@ -267,6 +267,8 @@ const char* DORA_CONFIGS[] = {
"},"
"\"valid-lifetime\": 600,"
"\"next-server\": \"10.0.0.1\","
"\"server-hostname\": \"nohost\","
"\"boot-file-name\": \"nofile\","
"\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", "
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
......
This diff is collapsed.
......@@ -109,6 +109,8 @@ const char* INFORM_CONFIGS[] = {
"},"
"\"valid-lifetime\": 600,"
"\"next-server\": \"10.0.0.1\","
"\"server-hostname\": \"nohost\","
"\"server-hostname\": \"nofile\","
"\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", "
" \"reservations\": [ "
......
......@@ -708,6 +708,32 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
<< next_server << "(" << pos << ")");
}
// Set server-hostname.
std::string sname = getString(params, "server-hostname");
if (!sname.empty()) {
if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
ConstElementPtr error = params->get("server-hostname");
isc_throw(DhcpConfigError, "server-hostname must be at most "
<< Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
<< sname.length() << " ("
<< error->getPosition() << ")");
}
subnet4->setSname(sname);
}
// Set boot-file-name.
std::string filename =getString(params, "boot-file-name");
if (!filename.empty()) {
if (filename.length() > Pkt4::MAX_FILE_LEN) {
ConstElementPtr error = params->get("boot-file-name");
isc_throw(DhcpConfigError, "boot-file-name must be at most "
<< Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
<< filename.length() << " ("
<< error->getPosition() << ")");
}
subnet4->setFilename(filename);
}
// Get interface name. If it is defined, then the subnet is available
// directly over specified network interface.
std::string iface = getString(params, "interface");
......
......@@ -63,7 +63,9 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
{ "dhcp4o6-port", Element::integer, "0" },
{ "echo-client-id", Element::boolean, "true" },
{ "match-client-id", Element::boolean, "true" },
{ "next-server", Element::string, "0.0.0.0" }
{ "next-server", Element::string, "0.0.0.0" },
{ "server-hostname", Element::string, "" },
{ "boot-file-name", Element::string, "" }
};
/// @brief This table defines default values for each IPv4 subnet.
......@@ -118,6 +120,7 @@ const SimpleDefaults SimpleParser4::IFACE4_DEFAULTS = {
/// This list is also used for inheriting from global to shared networks
/// and from shared networks to subnets within it.
const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = {
"boot-file-name",
"client-class",
"interface",
"match-client-id",
......@@ -126,6 +129,7 @@ const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = {
"relay",
"renew-timer",
"reservation-mode",
"server-hostname",
"valid-lifetime"
};
......
......@@ -239,6 +239,21 @@ isc::asiolink::IOAddress Subnet4::getSiaddr() const {
return (siaddr_);
}
void Subnet4::setSname(const std::string& sname) {
sname_ = sname;
}
const std::string& Subnet4::getSname() const {
return (sname_);
}
void Subnet4::setFilename(const std::string& filename) {
filename_ = filename;
}
const std::string& Subnet4::getFilename() const {
return (filename_);
}
const PoolCollection& Subnet::getPools(Lease::Type type) const {
// check if the type is valid (and throw if it isn't)
checkType(type);
......@@ -574,6 +589,12 @@ Subnet4::toElement() const {
// Set next-server
map->set("next-server", Element::create(getSiaddr().toText()));
// Set server-hostname
map->set("server-hostname", Element::create(getSname()));
// Set boot-file-name
map->set("boot-file-name",Element::create(getFilename()));
// Set pools
const PoolCollection& pools = getPools(Lease::TYPE_V4);
ElementPtr pool_list = Element::createList();
......
......@@ -457,6 +457,26 @@ public:
/// @return siaddr value
isc::asiolink::IOAddress getSiaddr() const;
/// @brief Sets server hostname for the Subnet4
///
/// Will be used for server hostname field (may be empty if not defined)
void setSname(const std::string& sname);
/// @brief Returns server hostname for this subnet
///
/// @return server hostname value
const std::string& getSname() const;
/// @brief Sets boot file name for the Subnet4
///
/// Will be used for boot file name (may be empty if not defined)
void setFilename(const std::string& filename);
/// @brief Returns boot file name for this subnet
///
/// @return boot file name value
const std::string& getFilename() const;
/// @brief Returns DHCP4o6 configuration parameters.
///
/// This structure is always available. If the 4o6 is not enabled, its
......@@ -497,6 +517,12 @@ private:
/// @brief siaddr value for this subnet
isc::asiolink::IOAddress siaddr_;
/// @brief server hostname for this subnet
std::string sname_;
/// @brief boot file name for this subnet
std::string filename_;
/// @brief All the information related to DHCP4o6
Cfg4o6 dhcp4o6_;
};
......
......@@ -748,6 +748,8 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"valid-lifetime\": 3,\n"
......@@ -765,6 +767,8 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"interface\": \"lo\",\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"valid-lifetime\": 3,\n"
......@@ -781,6 +785,8 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"interface\": \"eth1\",\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"valid-lifetime\": 3,\n"
......@@ -815,6 +821,8 @@ TEST(CfgSubnets4Test, unparsePool) {
" \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"valid-lifetime\": 3,\n"
......
......@@ -49,6 +49,8 @@ public:
" \"valid-lifetime\": 300,"
" \"match-client-id\": false,"
" \"next-server\": \"\","
" \"server-hostname\": \"\","
" \"boot-file-name\": \"\","
" \"client-class\": \"\","
" \"reservation-mode\": \"all\","
" \"4o6-interface\": \"\","
......@@ -67,6 +69,8 @@ public:
" \"valid-lifetime\": 30,"
" \"match-client-id\": false,"
" \"next-server\": \"\","
" \"server-hostname\": \"\","
" \"boot-file-name\": \"\","
" \"client-class\": \"\","
" \"reservation-mode\": \"all\","
" \"4o6-interface\": \"\","
......
......@@ -222,6 +222,8 @@ TEST(SharedNetwork4Test, unparse) {
" \"id\": 1,\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"rebind-timer\": 20,\n"
......@@ -240,6 +242,8 @@ TEST(SharedNetwork4Test, unparse) {
" \"id\": 2,\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"option-data\": [ ],\n"
" \"pools\": [ ],\n"
" \"rebind-timer\": 20,\n"
......
......@@ -110,6 +110,34 @@ TEST(Subnet4Test, siaddr) {
BadValue);
}
// Checks whether server-hostname field can be set and retrieved correctly.
TEST(Subnet4Test, serverHostname) {
Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
// Check if the default is empty
EXPECT_TRUE(subnet.getSname().empty());
// Check that we can set it up
EXPECT_NO_THROW(subnet.setSname("foobar"));
// Check that we can get it back
EXPECT_EQ("foobar", subnet.getSname());
}
// Checks whether boot-file-name field can be set and retrieved correctly.
TEST(Subnet4Test, bootFileName) {
Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
// Check if the default is empty
EXPECT_TRUE(subnet.getFilename().empty());
// Check that we can set it up
EXPECT_NO_THROW(subnet.setFilename("foobar"));
// Check that we can get it back
EXPECT_EQ("foobar", subnet.getFilename());
}
// Checks if the match-client-id flag can be set and retrieved.