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 @@ ...@@ -72,6 +72,8 @@
"id": 1, "id": 1,
"match-client-id": true, "match-client-id": true,
"next-server": "0.0.0.0", "next-server": "0.0.0.0",
"server-hostname": "",
"boot-file-name": "",
"option-data": [ ], "option-data": [ ],
"pools": [ ], "pools": [ ],
"rebind-timer": 20, "rebind-timer": 20,
...@@ -91,6 +93,8 @@ ...@@ -91,6 +93,8 @@
"id": 2, "id": 2,
"match-client-id": true, "match-client-id": true,
"next-server": "0.0.0.0", "next-server": "0.0.0.0",
"server-hostname": "",
"boot-file-name": "",
"option-data": [ ], "option-data": [ ],
"pools": [ ], "pools": [ ],
"rebind-timer": 20, "rebind-timer": 20,
......
...@@ -2591,14 +2591,24 @@ It is merely echoed by the server ...@@ -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 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. it was not defined at all, i.e. use the global value.
</para> </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> <screen>
"Dhcp4": { "Dhcp4": {
<userinput>"next-server": "192.0.2.123"</userinput>, <userinput>"next-server": "192.0.2.123",
"boot-file-name": "/dev/null"</userinput>,
..., ...,
"subnet4": [ "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) { ...@@ -2165,6 +2165,28 @@ Dhcpv4Srv::setFixedFields(Dhcpv4Exchange& ex) {
if (!subnet_next_server.isV4Zero()) { if (!subnet_next_server.isV4Zero()) {
response->setSiaddr(subnet_next_server); 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. // Step 2: Try to set the values based on classes.
......
...@@ -455,7 +455,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set, ...@@ -455,7 +455,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
(config_pair.first == "dhcp4o6-port") || (config_pair.first == "dhcp4o6-port") ||
(config_pair.first == "echo-client-id") || (config_pair.first == "echo-client-id") ||
(config_pair.first == "match-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; continue;
} }
......
...@@ -1106,14 +1106,16 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) { ...@@ -1106,14 +1106,16 @@ TEST_F(Dhcp4ParserTest, reconfigureRemoveSubnet) {
/// @todo: implement subnet removal test as part of #3281. /// @todo: implement subnet removal test as part of #3281.
// Checks if the next-server defined as global parameter is taken into // Checks if the next-server and other fixed BOOTP fields defined as
// consideration. // global parameter are taken into consideration.
TEST_F(Dhcp4ParserTest, nextServerGlobal) { TEST_F(Dhcp4ParserTest, nextServerGlobal) {
string config = "{ " + genIfaceConfig() + "," + string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, " "\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, " "\"renew-timer\": 1000, "
"\"next-server\": \"1.2.3.4\", " "\"next-server\": \"1.2.3.4\", "
"\"server-hostname\": \"foo\", "
"\"boot-file-name\": \"bar\", "
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
...@@ -1135,10 +1137,12 @@ TEST_F(Dhcp4ParserTest, nextServerGlobal) { ...@@ -1135,10 +1137,12 @@ TEST_F(Dhcp4ParserTest, nextServerGlobal) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200")); getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet); ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText()); 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 // Checks if the next-server and other fixed BOOTP fields defined as
// consideration. // subnet parameter are taken into consideration.
TEST_F(Dhcp4ParserTest, nextServerSubnet) { TEST_F(Dhcp4ParserTest, nextServerSubnet) {
string config = "{ " + genIfaceConfig() + "," + string config = "{ " + genIfaceConfig() + "," +
...@@ -1147,6 +1151,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) { ...@@ -1147,6 +1151,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) {
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", " " \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"foo\", "
" \"boot-file-name\": \"bar\", "
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }"; "\"valid-lifetime\": 4000 }";
...@@ -1166,6 +1172,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) { ...@@ -1166,6 +1172,8 @@ TEST_F(Dhcp4ParserTest, nextServerSubnet) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200")); getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet); ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText()); 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 // Test checks several negative scenarios for next-server configuration: bogus
...@@ -1209,12 +1217,43 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { ...@@ -1209,12 +1217,43 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) {
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }"; "\"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; ConstElementPtr json1;
ASSERT_NO_THROW(json1 = parseDHCP4(config_bogus1)); ASSERT_NO_THROW(json1 = parseDHCP4(config_bogus1));
ConstElementPtr json2; ConstElementPtr json2;
ASSERT_NO_THROW(json2 = parseDHCP4(config_bogus2)); ASSERT_NO_THROW(json2 = parseDHCP4(config_bogus2));
ConstElementPtr json3; ConstElementPtr json3;
ASSERT_NO_THROW(json3 = parseDHCP4(config_bogus3)); 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 // check if returned status is always a failure
ConstElementPtr status; ConstElementPtr status;
...@@ -1233,6 +1272,18 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) { ...@@ -1233,6 +1272,18 @@ TEST_F(Dhcp4ParserTest, nextServerNegative) {
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3)); EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3));
checkResult(status, 0); checkResult(status, 0);
EXPECT_FALSE(errorContainsPosition(status, "<string>")); 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 // Checks if the next-server defined as global value is overridden by subnet
...@@ -1243,9 +1294,13 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) { ...@@ -1243,9 +1294,13 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
"\"rebind-timer\": 2000, " "\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, " "\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", " "\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"nohost\","
"\"boot-file-name\": \"nofile\","
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", " " \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"some-name.example.org\","
" \"boot-file-name\": \"bootfile.efi\","
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }"; "\"valid-lifetime\": 4000 }";
...@@ -1265,6 +1320,8 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) { ...@@ -1265,6 +1320,8 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200")); getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet); ASSERT_TRUE(subnet);
EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText()); 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 // Check whether it is possible to configure echo-client-id
...@@ -5229,6 +5286,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ...@@ -5229,6 +5286,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
" \"interface\": \"eth0\",\n" " \"interface\": \"eth0\",\n"
" \"match-client-id\": false,\n" " \"match-client-id\": false,\n"
" \"next-server\": \"1.2.3.4\",\n" " \"next-server\": \"1.2.3.4\",\n"
" \"server-hostname\": \"foo\",\n"
" \"boot-file-name\": \"bar\",\n"
" \"relay\": {\n" " \"relay\": {\n"
" \"ip-address\": \"5.6.7.8\"\n" " \"ip-address\": \"5.6.7.8\"\n"
" },\n" " },\n"
...@@ -5249,6 +5308,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ...@@ -5249,6 +5308,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
" \"valid-lifetime\": 400,\n" " \"valid-lifetime\": 400,\n"
" \"match-client-id\": true,\n" " \"match-client-id\": true,\n"
" \"next-server\": \"11.22.33.44\",\n" " \"next-server\": \"11.22.33.44\",\n"
" \"server-hostname\": \"some-name.example.org\",\n"
" \"boot-file-name\": \"bootfile.efi\",\n"
" \"relay\": {\n" " \"relay\": {\n"
" \"ip-address\": \"55.66.77.88\"\n" " \"ip-address\": \"55.66.77.88\"\n"
" },\n" " },\n"
...@@ -5299,6 +5360,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ...@@ -5299,6 +5360,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("eth0", s->getIface()); EXPECT_EQ("eth0", s->getIface());
EXPECT_EQ(false, s->getMatchClientId()); EXPECT_EQ(false, s->getMatchClientId());
EXPECT_EQ(IOAddress("1.2.3.4"), s->getSiaddr()); 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(IOAddress("5.6.7.8"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode()); EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode());
...@@ -5312,6 +5375,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ...@@ -5312,6 +5375,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("eth0", s->getIface()); EXPECT_EQ("eth0", s->getIface());
EXPECT_EQ(true, s->getMatchClientId()); EXPECT_EQ(true, s->getMatchClientId());
EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr()); 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(IOAddress("55.66.77.88"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode()); EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode());
...@@ -5329,6 +5394,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { ...@@ -5329,6 +5394,8 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ("", s->getIface()); EXPECT_EQ("", s->getIface());
EXPECT_EQ(true, s->getMatchClientId()); EXPECT_EQ(true, s->getMatchClientId());
EXPECT_EQ(IOAddress("0.0.0.0"), s->getSiaddr()); 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(IOAddress("0.0.0.0"), s->getRelayInfo().addr_);
EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode()); EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode());
} }
......
...@@ -1255,7 +1255,7 @@ TEST_F(Dhcpv4SrvTest, siaddr) { ...@@ -1255,7 +1255,7 @@ TEST_F(Dhcpv4SrvTest, siaddr) {
// Checks if the next-server defined as global value is overridden by subnet // 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 // specific value and returned in server messages. There's also similar test for
// checking parser only configuration, see Dhcp4ParserTest.nextServerOverride in // 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) { TEST_F(Dhcpv4SrvTest, nextServerOverride) {
IfaceMgrTestConfig test_config(true); IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4(); IfaceMgr::instance().openSockets4();
...@@ -1270,9 +1270,13 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) { ...@@ -1270,9 +1270,13 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
"\"rebind-timer\": 2000, " "\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, " "\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", " "\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"nohost\", "
"\"boot-file-name\": \"nofile\", "
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", " " \"next-server\": \"1.2.3.4\", "
" \"server-hostname\": \"some-name.example.org\", "
" \"boot-file-name\": \"bootfile.efi\", "
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }"; "\"valid-lifetime\": 4000 }";
...@@ -1300,6 +1304,16 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) { ...@@ -1300,6 +1304,16 @@ TEST_F(Dhcpv4SrvTest, nextServerOverride) {
EXPECT_EQ(DHCPOFFER, offer->getType()); EXPECT_EQ(DHCPOFFER, offer->getType());
EXPECT_EQ("1.2.3.4", offer->getSiaddr().toText()); 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 // Checks if the next-server defined as global value is used in responses
...@@ -1320,6 +1334,8 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) { ...@@ -1320,6 +1334,8 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
"\"rebind-timer\": 2000, " "\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, " "\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", " "\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"some-name.example.org\", "
"\"boot-file-name\": \"bootfile.efi\", "
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"subnet\": \"192.0.2.0/24\" } ]," " \"subnet\": \"192.0.2.0/24\" } ],"
...@@ -1349,6 +1365,16 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) { ...@@ -1349,6 +1365,16 @@ TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
EXPECT_EQ(DHCPOFFER, offer->getType()); EXPECT_EQ(DHCPOFFER, offer->getType());
EXPECT_EQ("192.0.0.1", offer->getSiaddr().toText()); 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 // Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
......
...@@ -267,6 +267,8 @@ const char* DORA_CONFIGS[] = { ...@@ -267,6 +267,8 @@ const char* DORA_CONFIGS[] = {
"}," "},"
"\"valid-lifetime\": 600," "\"valid-lifetime\": 600,"
"\"next-server\": \"10.0.0.1\"," "\"next-server\": \"10.0.0.1\","
"\"server-hostname\": \"nohost\","
"\"boot-file-name\": \"nofile\","
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", " " \"subnet\": \"10.0.0.0/24\", "
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]," " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
......
This diff is collapsed.
...@@ -109,6 +109,8 @@ const char* INFORM_CONFIGS[] = { ...@@ -109,6 +109,8 @@ const char* INFORM_CONFIGS[] = {
"}," "},"
"\"valid-lifetime\": 600," "\"valid-lifetime\": 600,"
"\"next-server\": \"10.0.0.1\"," "\"next-server\": \"10.0.0.1\","
"\"server-hostname\": \"nohost\","
"\"server-hostname\": \"nofile\","
"\"subnet4\": [ { " "\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", " " \"subnet\": \"192.0.2.0/24\", "
" \"reservations\": [ " " \"reservations\": [ "
......
...@@ -708,6 +708,32 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, ...@@ -708,6 +708,32 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
<< next_server << "(" << pos << ")"); << 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 // Get interface name. If it is defined, then the subnet is available
// directly over specified network interface. // directly over specified network interface.
std::string iface = getString(params, "interface"); std::string iface = getString(params, "interface");
......
...@@ -63,7 +63,9 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = { ...@@ -63,7 +63,9 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
{ "dhcp4o6-port", Element::integer, "0" }, { "dhcp4o6-port", Element::integer, "0" },
{ "echo-client-id", Element::boolean, "true" }, { "echo-client-id", Element::boolean, "true" },
{ "match-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. /// @brief This table defines default values for each IPv4 subnet.
...@@ -118,6 +120,7 @@ const SimpleDefaults SimpleParser4::IFACE4_DEFAULTS = { ...@@ -118,6 +120,7 @@ const SimpleDefaults SimpleParser4::IFACE4_DEFAULTS = {
/// This list is also used for inheriting from global to shared networks /// This list is also used for inheriting from global to shared networks
/// and from shared networks to subnets within it. /// and from shared networks to subnets within it.
const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = { const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = {
"boot-file-name",
"client-class", "client-class",
"interface", "interface",
"match-client-id", "match-client-id",
...@@ -126,6 +129,7 @@ const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = { ...@@ -126,6 +129,7 @@ const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = {
"relay", "relay",
"renew-timer", "renew-timer",
"reservation-mode", "reservation-mode",
"server-hostname",
"valid-lifetime" "valid-lifetime"
}; };
......
...@@ -239,6 +239,21 @@ isc::asiolink::IOAddress Subnet4::getSiaddr() const { ...@@ -239,6 +239,21 @@ isc::asiolink::IOAddress Subnet4::getSiaddr() const {
return (siaddr_); return (siaddr_);
} }
void Subnet4::setSname(const std::string& sname) {
sname_ = sname;
}
const std::string& Subnet4::getSname() const {
return (sname_);