const asiolink::IOAddress& ipv4_reservation,
const std::string& hostname,
const std::string& dhcp4_client_classes,
- const std::string& dhcp6_client_classes)
+ const std::string& dhcp6_client_classes,
+ const asiolink::IOAddress& next_server,
+ const std::string& server_host_name,
+ const std::string& boot_file_name)
+
: identifier_type_(identifier_type),
identifier_value_(), ipv4_subnet_id_(ipv4_subnet_id),
ipv6_subnet_id_(ipv6_subnet_id),
ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
- dhcp6_client_classes_(dhcp6_client_classes), host_id_(0),
- cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
+ dhcp6_client_classes_(dhcp6_client_classes),
+ next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+ server_host_name_(server_host_name), boot_file_name_(boot_file_name),
+ host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
// Initialize host identifier.
setIdentifier(identifier, identifier_len, identifier_type);
// Validate and set IPv4 address reservation.
setIPv4Reservation(ipv4_reservation);
}
+
+ if (!next_server.isV4Zero()) {
+ // Validate and set next server address.
+ setNextServer(next_server);
+ }
}
Host::Host(const std::string& identifier, const std::string& identifier_name,
const asiolink::IOAddress& ipv4_reservation,
const std::string& hostname,
const std::string& dhcp4_client_classes,
- const std::string& dhcp6_client_classes)
+ const std::string& dhcp6_client_classes,
+ const asiolink::IOAddress& next_server,
+ const std::string& server_host_name,
+ const std::string& boot_file_name)
: identifier_type_(IDENT_HWADDR),
identifier_value_(), ipv4_subnet_id_(ipv4_subnet_id),
ipv6_subnet_id_(ipv6_subnet_id),
ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
- dhcp6_client_classes_(dhcp6_client_classes), host_id_(0),
- cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
+ dhcp6_client_classes_(dhcp6_client_classes),
+ next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+ server_host_name_(server_host_name), boot_file_name_(boot_file_name),
+ host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
// Initialize host identifier.
setIdentifier(identifier, identifier_name);
// Validate and set IPv4 address reservation.
setIPv4Reservation(ipv4_reservation);
}
+
+ if (!next_server.isV4Zero()) {
+ // Validate and set next server address.
+ setNextServer(next_server);
+ }
}
const std::vector<uint8_t>&
}
}
+void
+Host::setNextServer(const asiolink::IOAddress& next_server) {
+ if (!next_server.isV4()) {
+ isc_throw(isc::BadValue, "next server address '" << next_server
+ << "' is not a valid IPv4 address");
+ } else if (next_server.isV4Zero() || next_server.isV4Bcast()) {
+ isc_throw(isc::BadValue, "invalid next server address '"
+ << next_server << "'");
+ }
+
+ next_server_ = next_server;
+}
+
std::string
Host::toText() const {
std::ostringstream s;
s << " ipv4_reservation=" << (ipv4_reservation_.isV4Zero() ? "(no)" :
ipv4_reservation_.toText());
+ // Add next server.
+ s << " siaddr=" << (next_server_.isV4Zero() ? "(no)" :
+ next_server_.toText());
+
+ // Add server host name.
+ s << " sname=" << (server_host_name_.empty() ? "(empty)" : server_host_name_);
+
+ // Add boot file name.
+ s << " file=" << (boot_file_name_.empty() ? "(empty)" : boot_file_name_);
+
if (ipv6_reservations_.empty()) {
s << " ipv6_reservations=(none)";
/// separated by commas. The names get trimmed by this constructor.
/// @param dhcp6_client_classes A string holding DHCPv6 client class names
/// separated by commas. The names get trimmed by this constructor.
+ /// @param next_server IPv4 address of next server (siaddr).
+ /// @param server_host_name Server host name (a.k.a. sname).
+ /// @param boot_file_name Boot file name (a.k.a. file).
///
/// @throw BadValue if the provided values are invalid. In particular,
/// if the identifier is invalid.
const asiolink::IOAddress& ipv4_reservation,
const std::string& hostname = "",
const std::string& dhcp4_client_classes = "",
- const std::string& dhcp6_client_classes = "");
+ const std::string& dhcp6_client_classes = "",
+ const asiolink::IOAddress& next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS(),
+ const std::string& server_host_name = "",
+ const std::string& boot_file_name = "");
/// @brief Constructor.
///
/// separated by commas. The names get trimmed by this constructor.
/// @param dhcp6_client_classes A string holding DHCPv6 client class names
/// separated by commas. The names get trimmed by this constructor.
+ /// @param next_server IPv4 address of next server (siaddr).
+ /// @param server_host_name Server host name (a.k.a. sname).
+ /// @param boot_file_name Boot file name (a.k.a. file).
///
/// @throw BadValue if the provided values are invalid. In particular,
/// if the identifier is invalid.
const asiolink::IOAddress& ipv4_reservation,
const std::string& hostname = "",
const std::string& dhcp4_client_classes = "",
- const std::string& dhcp6_client_classes = "");
+ const std::string& dhcp6_client_classes = "",
+ const asiolink::IOAddress& next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS(),
+ const std::string& server_host_name = "",
+ const std::string& boot_file_name = "");
/// @brief Replaces currently used identifier with a new identifier.
///
return (dhcp6_client_classes_);
}
+ /// @brief Sets new value for next server field (siaddr).
+ ///
+ /// @param next_server New address of a next server.
+ ///
+ /// @throw isc::BadValue if the provided address is not an IPv4 address,
+ /// is a 0 address or broadcast address.
+ void setNextServer(const asiolink::IOAddress& next_server);
+
+ /// @brief Returns value of next server field (siaddr).
+ const asiolink::IOAddress& getNextServer() const {
+ return (next_server_);
+ }
+
+ /// @brief Sets new value for server hostname (sname).
+ ///
+ /// @param server_host_name New value for server hostname.
+ void setServerHostname(const std::string& server_host_name) {
+ server_host_name_ = server_host_name;
+ }
+
+ /// @brief Returns value of server hostname (sname).
+ std::string getServerHostname() const {
+ return (server_host_name_);
+ }
+
+ /// @brief Sets new value for boot file name (file).
+ ///
+ /// @param boot_file_name New value of boot file name.
+ void setBootFileName(const std::string& boot_file_name) {
+ boot_file_name_ = boot_file_name;
+ }
+
+ /// @brief Returns value of boot file name (file).
+ std::string getBootFileName() const {
+ return (boot_file_name_);
+ }
+
/// @brief Returns pointer to the DHCPv4 option data configuration for
/// this host.
///
ClientClasses dhcp4_client_classes_;
/// @brief Collection of classes associated with a DHCPv6 client.
ClientClasses dhcp6_client_classes_;
+ /// @brief Next server (a.k.a. siaddr, carried in DHCPv4 message).
+ asiolink::IOAddress next_server_;
+ /// @brief Server host name (a.k.a. sname, carried in DHCPv4 message).
+ std::string server_host_name_;
+ /// @brief Boot file name (a.k.a. file, carried in DHCPv4 message)
+ std::string boot_file_name_;
/// @brief HostID (a unique identifier assigned when the host is stored in
/// MySQL or Pgsql)
ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
SubnetID(1), SubnetID(2),
IOAddress("192.0.2.3"),
- "somehost.example.org")));
+ "somehost.example.org",
+ std::string(), std::string(),
+ IOAddress("192.0.0.2"),
+ "server-hostname.example.org",
+ "bootfile.efi")));
// The HW address should be set to non-null.
HWAddrPtr hwaddr = host->getHWAddress();
ASSERT_TRUE(hwaddr);
EXPECT_EQ(2, host->getIPv6SubnetID());
EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
EXPECT_EQ("somehost.example.org", host->getHostname());
+ EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
+ EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+ EXPECT_EQ("bootfile.efi", host->getBootFileName());
// Use invalid identifier name
EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2),
Host::IDENT_HWADDR,
SubnetID(1), SubnetID(2),
IOAddress("192.0.2.3"),
- "somehost.example.org")));
+ "somehost.example.org",
+ std::string(), std::string(),
+ IOAddress("192.0.0.2"),
+ "server-hostname.example.org",
+ "bootfile.efi")));
+
// Hardware address should be non-null.
HWAddrPtr hwaddr = host->getHWAddress();
ASSERT_TRUE(hwaddr);
EXPECT_EQ(2, host->getIPv6SubnetID());
EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
EXPECT_EQ("somehost.example.org", host->getHostname());
+ EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
+ EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+ EXPECT_EQ("bootfile.efi", host->getBootFileName());
}
// This test verifies that it is possible to create a Host object using
host->setIPv6SubnetID(SubnetID(234));
host->setIPv4Reservation(IOAddress("10.0.0.1"));
host->setHostname("other-host.example.org");
+ host->setNextServer(IOAddress("192.0.2.2"));
+ host->setServerHostname("server-hostname.example.org");
+ host->setBootFileName("bootfile.efi");
EXPECT_EQ(123, host->getIPv4SubnetID());
EXPECT_EQ(234, host->getIPv6SubnetID());
EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText());
EXPECT_EQ("other-host.example.org", host->getHostname());
+ EXPECT_EQ("192.0.2.2", host->getNextServer().toText());
+ EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+ EXPECT_EQ("bootfile.efi", host->getBootFileName());
// Remove IPv4 reservation.
host->removeIPv4Reservation();
// Broadcast address can't be set.
EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_BCAST_ADDRESS()),
isc::BadValue);
+
+ // Zero or broadcast are invalid addresses for next server.
+ EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+ isc::BadValue);
+ EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_BCAST_ADDRESS()),
+ isc::BadValue);
}
// Test that Host constructors initialize client classes from string.
EXPECT_EQ("hwaddr=010203040506 ipv4_subnet_id=1 ipv6_subnet_id=2"
" hostname=myhost.example.com"
" ipv4_reservation=192.0.2.3"
+ " siaddr=(no)"
+ " sname=(empty)"
+ " file=(empty)"
" ipv6_reservation0=2001:db8:1::cafe"
" ipv6_reservation1=2001:db8:1::1"
" ipv6_reservation2=2001:db8:1:1::/64"
EXPECT_EQ("hwaddr=010203040506 ipv6_subnet_id=2"
" hostname=(empty) ipv4_reservation=(no)"
+ " siaddr=(no)"
+ " sname=(empty)"
+ " file=(empty)"
" ipv6_reservation0=2001:db8:1::cafe"
" ipv6_reservation1=2001:db8:1::1"
" ipv6_reservation2=2001:db8:1:1::/64"
"myhost")));
EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+ " siaddr=(no)"
+ " sname=(empty)"
+ " file=(empty)"
" ipv6_reservations=(none)", host->toText());
// Add some classes.
host->addClientClass4("router");
EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+ " siaddr=(no)"
+ " sname=(empty)"
+ " file=(empty)"
" ipv6_reservations=(none)"
" dhcp4_class0=modem dhcp4_class1=router",
host->toText());
host->addClientClass6("device");
EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+ " siaddr=(no)"
+ " sname=(empty)"
+ " file=(empty)"
" ipv6_reservations=(none)"
" dhcp4_class0=modem dhcp4_class1=router"
" dhcp6_class0=device dhcp6_class1=hub",